Imagine you're a cryptographer who has intercepted a secret message! You've found an array numWays that contains clues about a hidden coin system. Each position i tells you how many ways you can make amount i using some mysterious coin denominations.
Your mission: reverse-engineer the original coin denominations!
The Challenge: Given a 1-indexed array numWays[i] representing the number of ways to make amount i, determine what coin denominations could have produced this pattern. The coins have infinite supply, and each denomination is a positive integer ≤ numWays.length.
Goal: Return a sorted array of unique coin denominations that could generate the given numWays array. If no valid set exists, return an empty array.
Example: If numWays = [0, 1, 1, 2], this means: • 1 way to make amount 1 • 1 way to make amount 2 • 2 ways to make amount 3 This could come from coins [1, 2]!
Input & Output
example_1.py — Basic Case
$Input:numWays = [0, 1, 1, 2]
›Output:[1, 2]
💡 Note:With coins [1, 2]: amount 1 has 1 way (use coin 1), amount 2 has 1 way (use coin 2), amount 3 has 2 ways (1+2 or 1+1+1). This matches the given numWays pattern.
example_2.py — Single Coin
$Input:numWays = [0, 1, 1, 1]
›Output:[1]
💡 Note:Only coin denomination 1 can produce this pattern: 1 way each to make amounts 1, 2, and 3 (using 1, 2, and 3 coins of denomination 1 respectively).
example_3.py — No Valid Coins
$Input:numWays = [0, 0, 1]
›Output:[]
💡 Note:This pattern is impossible. If we can make amount 2 in 1 way, we must be able to make smaller amounts, but numWays[1] = 0 indicates amount 1 cannot be made.
Constraints
1 ≤ numWays.length ≤ 100
0 ≤ numWays[i] ≤ 1000
numWays[0] = 0 (always, as there's only one way to make 0: use no coins)
Each coin denomination is a positive integer ≤ numWays.length
Visualization
Tap to expand
Understanding the Visualization
1
Examine the Evidence
numWays = [0, 1, 1, 2] tells us: 1 way for amount 1, 1 way for amount 2, 2 ways for amount 3
2
Start with Amount 1
Since amount 1 has exactly 1 way, coin denomination 1 must exist
3
Check Amount 2
With coin 1, we can make amount 2 in 1 way (1+1). This matches numWays[2]=1
4
Analyze Amount 3
With coin 1, we can make amount 3 in 1 way (1+1+1). But numWays[3]=2! We need another coin
5
Discover Coin 2
Adding coin 2 gives us 2 ways for amount 3: (1+1+1) and (2+1). Perfect match!
Key Takeaway
🎯 Key Insight: The detective method works because each coin denomination reveals itself when we can't make its amount with previously discovered coins. By incrementally building our coin set and verifying against the evidence, we can reconstruct the original currency system with confidence.
The optimal approach uses incremental coin identification: iterate through amounts 1 to n, and for each amount i where numWays[i] > 0 but our current DP can't make it (dp[i] = 0), add i as a coin denomination. This works because if we can't make amount i with existing coins but the target says we should be able to, then i itself must be a coin. Key insight: verify the solution by reconstructing the entire numWays array using standard coin change DP.
Common Approaches
Approach
Time
Space
Notes
✓
Brute Force (Test All Subsets)
O(2^n × n²)
O(n)
Test every possible subset of coin denominations and simulate coin change DP
Two-Pass: Identify & Verify
O(n²)
O(n)
First pass identifies potential coins, second pass verifies with DP reconstruction
Brute Force (Test All Subsets) — Algorithm Steps
Generate all possible subsets of numbers from 1 to numWays.length
For each subset, simulate coin change DP to compute ways array
Compare computed ways with given numWays array
Return the first matching subset (sorted)
Visualization
Tap to expand
Step-by-Step Walkthrough
1
Generate Subsets
Create all possible combinations of coin denominations from 1 to n
2
Test Each Subset
For each subset, run coin change DP to compute numWays
3
Compare Results
Check if computed numWays matches the given array
4
Return First Match
Return the first valid coin denomination set found
Code -
solution.c — C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int* coinChangeDP(int* coins, int coinsSize, int target) {
int* dp = calloc(target + 1, sizeof(int));
dp[0] = 1;
for (int i = 0; i < coinsSize; i++) {
for (int amount = coins[i]; amount <= target; amount++) {
dp[amount] += dp[amount - coins[i]];
}
}
return dp;
}
void generateSubsets(int* nums, int numsSize, int start, int* current, int currentSize, int** result, int* resultSizes, int* returnSize) {
result[*returnSize] = malloc(currentSize * sizeof(int));
memcpy(result[*returnSize], current, currentSize * sizeof(int));
resultSizes[*returnSize] = currentSize;
(*returnSize)++;
for (int i = start; i < numsSize; i++) {
current[currentSize] = nums[i];
generateSubsets(nums, numsSize, i + 1, current, currentSize + 1, result, resultSizes, returnSize);
}
}
int* recoverCoinDenominations(int* numWays, int numWaysSize, int* returnSize) {
int n = numWaysSize - 1;
int* candidates = malloc(n * sizeof(int));
for (int i = 0; i < n; i++) {
candidates[i] = i + 1;
}
int** subsets = malloc((1 << n) * sizeof(int*));
int* subsetSizes = malloc((1 << n) * sizeof(int));
int subsetsCount = 0;
int* current = malloc(n * sizeof(int));
generateSubsets(candidates, n, 0, current, 0, subsets, subsetSizes, &subsetsCount);
for (int i = 0; i < subsetsCount; i++) {
if (subsetSizes[i] == 0) continue;
int* computed = coinChangeDP(subsets[i], subsetSizes[i], n);
int match = 1;
for (int j = 1; j <= n; j++) {
if (computed[j] != numWays[j]) {
match = 0;
break;
}
}
if (match) {
*returnSize = subsetSizes[i];
int* result = malloc(subsetSizes[i] * sizeof(int));
memcpy(result, subsets[i], subsetSizes[i] * sizeof(int));
// Clean up
for (int k = 0; k < subsetsCount; k++) {
free(subsets[k]);
}
free(subsets);
free(subsetSizes);
free(candidates);
free(current);
free(computed);
return result;
}
free(computed);
}
// Clean up
for (int k = 0; k < subsetsCount; k++) {
free(subsets[k]);
}
free(subsets);
free(subsetSizes);
free(candidates);
free(current);
*returnSize = 0;
return NULL;
}
int main() {
char line[1000];
fgets(line, sizeof(line), stdin);
int numWays[100];
int count = 0;
char* token = strtok(line, " \n");
while (token) {
numWays[count++] = atoi(token);
token = strtok(NULL, " \n");
}
int returnSize;
int* result = recoverCoinDenominations(numWays, count, &returnSize);
for (int i = 0; i < returnSize; i++) {
if (i > 0) printf(" ");
printf("%d", result[i]);
}
printf("\n");
if (result) free(result);
return 0;
}
Time & Space Complexity
Time Complexity
⏱️
O(2^n × n²)
2^n subsets to check, each taking O(n²) time for DP simulation
n
2n
⚠ Quadratic Growth
Space Complexity
O(n)
Space for DP array and recursion stack
n
2n
⚡ Linearithmic Space
43.7K Views
MediumFrequency
~25 minAvg. Time
1.8K Likes
Ln 1, Col 1
Smart Actions
💡Explanation
AI Ready
💡 SuggestionTabto acceptEscto dismiss
// Output will appear here after running code
Code Editor Closed
Click the red button to reopen
Algorithm Visualization
Pinch to zoom • Tap outside to close
Test Cases
0 passed
0 failed
3 pending
Select Compiler
Choose a programming language
Compiler list would appear here...
AI Editor Features
Header Buttons
💡
Explain
Get a detailed explanation of your code. Select specific code or analyze the entire file. Understand algorithms, logic flow, and complexity.
🔧
Fix
Automatically detect and fix issues in your code. Finds bugs, syntax errors, and common mistakes. Shows you what was fixed.
💡
Suggest
Get improvement suggestions for your code. Best practices, performance tips, and code quality recommendations.
💬
Ask AI
Open an AI chat assistant to ask any coding questions. Have a conversation about your code, get help with debugging, or learn new concepts.
Smart Actions (Slash Commands)
🔧
/fix Enter
Find and fix issues in your code. Detects common problems and applies automatic fixes.
💡
/explain Enter
Get a detailed explanation of what your code does, including time/space complexity analysis.
🧪
/tests Enter
Automatically generate unit tests for your code. Creates comprehensive test cases.
📝
/docs Enter
Generate documentation for your code. Creates docstrings, JSDoc comments, and type hints.
⚡
/optimize Enter
Get performance optimization suggestions. Improve speed and reduce memory usage.
AI Code Completion (Copilot-style)
👻
Ghost Text Suggestions
As you type, AI suggests code completions shown in gray text. Works with keywords like def, for, if, etc.
Tabto acceptEscto dismiss
💬
Comment-to-Code
Write a comment describing what you want, and AI generates the code. Try: # two sum, # binary search, # fibonacci
💡
Pro Tip: Select specific code before using Explain, Fix, or Smart Actions to analyze only that portion. Otherwise, the entire file will be analyzed.