1449. Form Largest Integer With Digits That Add up to Target
Problem Description
You need to form the largest possible integer by "painting" digits, where each digit has an associated cost.
The problem gives you:
- An array
cost
wherecost[i]
represents the cost to paint digit(i + 1)
- For example,
cost[0]
is the cost to paint digit 1,cost[1]
is the cost to paint digit 2, and so on up to digit 9
- For example,
- A
target
value representing the exact total cost you must spend
Your goal is to find the maximum integer you can create by selecting and arranging digits such that:
- The sum of costs for all selected digits equals exactly
target
- The resulting number doesn't contain the digit 0 (only digits 1-9 are available)
- You want the largest possible integer value
The key insights for maximizing the integer value:
- First, maximize the number of digits (more digits means a larger number)
- Among numbers with the same digit count, prefer using larger digits (9 is better than 1)
- Digits can be reused multiple times
For example, if cost = [4,3,2,5,6,7,2,5,5]
and target = 9
:
- Digit 3 costs 2, and digit 7 costs 2
- You could paint "777" (cost: 2+2+2 = 6) or "7777" (cost: 2+2+2+2 = 8) or "77777" (cost: 2+2+2+2+2 = 10)
- But since target is 9, you could paint "7773" (cost: 2+2+2+3 = 9)
The solution uses dynamic programming where:
f[i][j]
tracks the maximum number of digits achievable using digits 1 throughi
with exact costj
g[i][j]
helps reconstruct which digits were chosen by storing the previous state- The algorithm fills the DP table considering whether to use digit
i
or not at each step - Finally, it reconstructs the answer by backtracking through the states, preferring larger digits when possible
Return the result as a string since the number can be very large. If it's impossible to spend exactly target
cost, return "0".
Intuition
To get the largest possible number, we need to think about what makes one number larger than another. A number with more digits is always larger than a number with fewer digits (e.g., 1000 > 999). So our first priority is maximizing the number of digits we can paint with our budget.
This leads us to a key observation: if we want the most digits for our money, we should look for the cheapest digit available. However, once we know how many digits we can afford, we want those digits to be as large as possible (preferring 9s over 1s).
This creates a two-phase optimization problem:
- First, find the maximum number of digits we can paint with exactly
target
cost - Then, among all ways to paint that many digits, choose the combination that gives the largest number
The challenge is that we can't just greedily pick the cheapest digit repeatedly. We need to spend exactly target
cost, not just stay under it. For example, if the cheapest digit costs 3 and our target is 10, we can't paint 3 digits (cost 9) because we'd have 1 unit left over that we can't spend.
This "exact change" constraint naturally suggests dynamic programming. We can build up solutions by asking: "If I have budget j
, what's the maximum number of digits I can paint using digits 1 through i
?"
For each digit i
and budget j
, we have two choices:
- Don't use digit
i
at all: inherit the best solution from digits 1 throughi-1
- Use digit
i
: if we have enough budget (j >= cost[i-1]
), we can paint digiti
and then solve the subproblem with remaining budgetj - cost[i-1]
The DP table f[i][j]
stores the maximum number of digits achievable. We also need g[i][j]
to track our decisions so we can reconstruct which digits to use.
Once we've filled the DP table and know the maximum number of digits possible, we reconstruct the answer by working backwards. At each step, we greedily choose to use the largest digit possible (starting from 9 and going down). This ensures that our final number has the largest possible value among all numbers with the maximum digit count.
The reconstruction process examines g[i][j]
to determine whether digit i
was used. If g[i][j] == j
, it means we didn't use digit i
at that state, so we move to i-1
. Otherwise, we used digit i
, add it to our answer, and move to the state with reduced budget g[i][j]
.
Learn more about Dynamic Programming patterns.
Solution Approach
The solution uses a 2D dynamic programming approach with state reconstruction. Let's walk through the implementation step by step:
DP Table Setup:
f[i][j]
represents the maximum number of digits we can paint using digits 1 throughi
with exact costj
- Initialize
f
with-inf
to mark impossible states - Set
f[0][0] = 0
as base case (0 digits with 0 cost) g[i][j]
stores the previous budget state to help reconstruct the solution
Filling the DP Table:
for i, c in enumerate(cost, 1): # i represents digit i (1-indexed)
for j in range(target + 1): # j represents current budget
For each digit i
and budget j
, we make a decision:
-
Option 1: Don't use digit
i
- Inherit the solution from
f[i-1][j]
- Set
g[i][j] = j
(budget remains unchanged)
- Inherit the solution from
-
Option 2: Use digit
i
- Only possible if
j >= c
(enough budget) - New digit count would be
f[i][j-c] + 1
- Set
g[i][j] = j - c
(remaining budget after using digiti
)
- Only possible if
The decision logic:
if j < c or f[i][j - c] + 1 < f[i - 1][j]: f[i][j] = f[i - 1][j] # Don't use digit i g[i][j] = j else: f[i][j] = f[i][j - c] + 1 # Use digit i g[i][j] = j - c
We choose Option 2 (use digit i
) only if:
- We have enough budget (
j >= c
) - AND using digit
i
gives us more total digits (f[i][j-c] + 1 >= f[i-1][j]
)
Checking Feasibility:
if f[9][target] < 0: return "0"
If f[9][target]
is negative, it's impossible to spend exactly target
cost.
Reconstructing the Answer:
Starting from state (i=9, j=target)
, we work backwards to build the largest number:
ans = []
i, j = 9, target
while i:
if j == g[i][j]:
i -= 1 # Digit i wasn't used, move to i-1
else:
ans.append(str(i)) # Digit i was used
j = g[i][j] # Move to previous budget state
The reconstruction starts from digit 9 and works down. This ensures we use the largest digits possible for the maximum digit count. When j != g[i][j]
, it means we used digit i
at this state, so we:
- Add digit
i
to our answer - Update
j
to the previous budget stateg[i][j]
The algorithm continues until i = 0
, at which point we've reconstructed all the digits used.
Time Complexity: O(9 * target)
for filling the DP table and O(max_digits)
for reconstruction
Space Complexity: O(9 * target)
for the two 2D arrays
The key insight is that by processing digits from 1 to 9 and reconstructing from 9 to 1, we automatically get the largest possible number among all numbers with the maximum digit count.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example with cost = [2, 4, 6, 2, 4, 6, 4, 4, 4]
and target = 6
.
This means:
- Digit 1 costs 2, Digit 2 costs 4, Digit 3 costs 6
- Digit 4 costs 2, Digit 5 costs 4, Digit 6 costs 6
- Digit 7 costs 4, Digit 8 costs 4, Digit 9 costs 4
Step 1: Initialize DP tables
f[i][j]
tracks max digits using digits 1-i with cost jf[0][0] = 0
, all other entries start as-inf
Step 2: Fill DP table for key states
For digit 1 (cost=2):
- At j=2: Can use digit 1 once,
f[1][2] = 1
- At j=4: Can use digit 1 twice,
f[1][4] = 2
- At j=6: Can use digit 1 three times,
f[1][6] = 3
For digit 4 (cost=2):
- At j=2: Can use digit 4 once,
f[4][2] = 1
- At j=4: Can use digit 4 twice,
f[4][4] = 2
- At j=6: Can use digit 4 three times,
f[4][6] = 3
Since digits 1 and 4 have the same cost (2), they achieve the same max digit counts. But digit 4 is larger, so when we have a choice, we prefer it.
For digit 9 (cost=4):
- At j=4: Can use digit 9 once,
f[9][4] = 1
- At j=6: Best option is still three digits (using cheaper digits),
f[9][6] = 3
Step 3: Check feasibility
f[9][6] = 3
, which is positive, so a solution exists.
Step 4: Reconstruct the answer Starting from state (i=9, j=6):
-
i=9, j=6: Check if we used digit 9
g[9][6]
tells us whether we used digit 9 here- Since using digit 9 (cost 4) would leave us with j=2, and we can get 1 more digit with cost 2, total would be 2 digits
- But not using digit 9 and using cheaper digits gives us 3 digits
- So
g[9][6] = 6
(didn't use digit 9) - Move to i=8, j=6
-
Continue checking digits 8, 7, 6, 5 (all cost 4 or 6)
- Similar logic: using them gives fewer than 3 digits
- Keep moving down without using them
-
i=4, j=6: Check if we used digit 4
- Using digit 4 (cost 2) leaves j=4, where we can get 2 more digits
- Total: 3 digits, same as not using it
- But digit 4 is valuable!
g[4][6] = 4
(we did use digit 4) - Add "4" to answer, move to i=4, j=4
-
i=4, j=4: Check if we used digit 4 again
- Using digit 4 leaves j=2, where we can get 1 more digit
- Total: 2 digits.
g[4][4] = 2
(we did use digit 4) - Add "4" to answer, move to i=4, j=2
-
i=4, j=2: Check if we used digit 4 again
- Using digit 4 leaves j=0, where we have 0 more digits
- Total: 1 digit.
g[4][2] = 0
(we did use digit 4) - Add "4" to answer, move to i=4, j=0
-
j=0, so we're done
Final answer: "444"
This makes sense because:
- We maximized the number of digits (3 digits)
- Among all ways to get 3 digits with cost 6, we used the largest possible digits (all 4s instead of mixing with 1s)
- The cost is exactly 2+2+2 = 6
Solution Implementation
1class Solution:
2 def largestNumber(self, cost: List[int], target: int) -> str:
3 # dp[i][j] = maximum count of digits we can use with digits 1..i and exact cost j
4 # Initialize with negative infinity to mark invalid states
5 dp = [[-float('inf')] * (target + 1) for _ in range(10)]
6 dp[0][0] = 0 # Base case: 0 digits with 0 cost is valid (0 digits used)
7
8 # parent[i][j] = the cost from which we transitioned to reach state (i, j)
9 # Used for backtracking to construct the answer
10 parent = [[0] * (target + 1) for _ in range(10)]
11
12 # Fill the DP table
13 for digit in range(1, 10): # Digits 1-9 (index i corresponds to digit i)
14 digit_cost = cost[digit - 1] # Cost of current digit
15
16 for current_cost in range(target + 1):
17 # Option 1: Don't use current digit, inherit from previous digit
18 dont_use = dp[digit - 1][current_cost]
19
20 # Option 2: Use current digit (if we have enough budget)
21 if current_cost >= digit_cost:
22 use_digit = dp[digit][current_cost - digit_cost] + 1
23 else:
24 use_digit = -float('inf')
25
26 # Choose the option that gives more digits
27 if use_digit > dont_use:
28 dp[digit][current_cost] = use_digit
29 parent[digit][current_cost] = current_cost - digit_cost
30 else:
31 dp[digit][current_cost] = dont_use
32 parent[digit][current_cost] = current_cost
33
34 # Check if it's possible to achieve the target cost
35 if dp[9][target] < 0:
36 return "0"
37
38 # Backtrack to construct the largest number
39 result = []
40 current_digit, remaining_cost = 9, target
41
42 while current_digit > 0:
43 if remaining_cost == parent[current_digit][remaining_cost]:
44 # Current digit was not used, move to previous digit
45 current_digit -= 1
46 else:
47 # Current digit was used, add it to result
48 result.append(str(current_digit))
49 remaining_cost = parent[current_digit][remaining_cost]
50
51 return "".join(result)
52
1class Solution {
2 public String largestNumber(int[] cost, int target) {
3 // Use a large negative value to represent impossible states
4 final int NEGATIVE_INFINITY = 1 << 30;
5
6 // dp[i][j] represents the maximum number of digits we can use
7 // when considering digits 1 to i with total cost j
8 int[][] dp = new int[10][target + 1];
9
10 // backtrack[i][j] stores the previous cost state for reconstruction
11 // If backtrack[i][j] == j, we didn't use digit i
12 // Otherwise, we used digit i and the previous state was j - cost[i-1]
13 int[][] backtrack = new int[10][target + 1];
14
15 // Initialize all dp values to negative infinity (impossible states)
16 for (int[] row : dp) {
17 Arrays.fill(row, -NEGATIVE_INFINITY);
18 }
19
20 // Base case: 0 digits with 0 cost gives 0 length
21 dp[0][0] = 0;
22
23 // Fill the dp table for each digit from 1 to 9
24 for (int digit = 1; digit <= 9; digit++) {
25 int digitCost = cost[digit - 1];
26
27 for (int currentCost = 0; currentCost <= target; currentCost++) {
28 // Option 1: Don't use the current digit
29 int withoutCurrentDigit = dp[digit - 1][currentCost];
30
31 // Option 2: Use the current digit (if we have enough cost)
32 int withCurrentDigit = -NEGATIVE_INFINITY;
33 if (currentCost >= digitCost) {
34 withCurrentDigit = dp[digit][currentCost - digitCost] + 1;
35 }
36
37 // Choose the option that gives more digits
38 if (withCurrentDigit > withoutCurrentDigit) {
39 dp[digit][currentCost] = withCurrentDigit;
40 backtrack[digit][currentCost] = currentCost - digitCost;
41 } else {
42 dp[digit][currentCost] = withoutCurrentDigit;
43 backtrack[digit][currentCost] = currentCost;
44 }
45 }
46 }
47
48 // If we can't form any number with the exact target cost, return "0"
49 if (dp[9][target] < 0) {
50 return "0";
51 }
52
53 // Reconstruct the largest number by backtracking from the largest digit
54 StringBuilder result = new StringBuilder();
55 int currentDigit = 9;
56 int remainingCost = target;
57
58 while (currentDigit > 0) {
59 // If backtrack value equals current cost, we didn't use this digit
60 if (remainingCost == backtrack[currentDigit][remainingCost]) {
61 currentDigit--;
62 } else {
63 // We used this digit, append it to result
64 result.append(currentDigit);
65 remainingCost = backtrack[currentDigit][remainingCost];
66 }
67 }
68
69 return result.toString();
70 }
71}
72
1class Solution {
2public:
3 string largestNumber(vector<int>& cost, int target) {
4 // Initialize constants and data structures
5 const int INF = 1 << 30; // Large negative value to represent impossible states
6
7 // dp[i][j] = maximum number of digits achievable using digits 1 to i with total cost j
8 vector<vector<int>> dp(10, vector<int>(target + 1, -INF));
9
10 // parent[i][j] = the cost from which we transitioned to reach state (i, j)
11 // Used for backtracking to reconstruct the solution
12 vector<vector<int>> parent(10, vector<int>(target + 1));
13
14 // Base case: 0 digits with 0 cost is achievable with 0 digits
15 dp[0][0] = 0;
16
17 // Fill the DP table for each digit from 1 to 9
18 for (int digit = 1; digit <= 9; ++digit) {
19 int digitCost = cost[digit - 1]; // Cost of current digit (0-indexed in cost array)
20
21 for (int currentTarget = 0; currentTarget <= target; ++currentTarget) {
22 // Option 1: Don't use the current digit - inherit from previous digit
23 int withoutCurrentDigit = dp[digit - 1][currentTarget];
24
25 // Option 2: Use the current digit (if we have enough budget)
26 int withCurrentDigit = -INF;
27 if (currentTarget >= digitCost) {
28 withCurrentDigit = dp[digit][currentTarget - digitCost] + 1;
29 }
30
31 // Choose the option that gives more digits
32 if (withCurrentDigit > withoutCurrentDigit) {
33 dp[digit][currentTarget] = withCurrentDigit;
34 parent[digit][currentTarget] = currentTarget - digitCost; // Mark transition
35 } else {
36 dp[digit][currentTarget] = withoutCurrentDigit;
37 parent[digit][currentTarget] = currentTarget; // No transition (same cost)
38 }
39 }
40 }
41
42 // Check if it's impossible to achieve the target cost
43 if (dp[9][target] < 0) {
44 return "0";
45 }
46
47 // Reconstruct the solution by backtracking through parent array
48 string result;
49 int currentDigit = 9;
50 int remainingTarget = target;
51
52 // Start from largest digit (9) and work backwards for maximum value
53 while (currentDigit > 0) {
54 // Check if we used the current digit
55 if (parent[currentDigit][remainingTarget] == remainingTarget) {
56 // Didn't use this digit, move to smaller digit
57 --currentDigit;
58 } else {
59 // Used this digit, add it to result
60 result += '0' + currentDigit;
61 remainingTarget = parent[currentDigit][remainingTarget];
62 }
63 }
64
65 return result;
66 }
67};
68
1/**
2 * Finds the largest number that can be formed with given digit costs and target sum
3 * @param cost - Array where cost[i] is the cost of digit (i+1)
4 * @param target - The target sum we need to achieve
5 * @returns The largest number as a string, or "0" if impossible
6 */
7function largestNumber(cost: number[], target: number): string {
8 // Large negative value to represent impossible states
9 const NEGATIVE_INFINITY = 1 << 30;
10
11 // dp[i][j] represents the maximum number of digits we can use
12 // when considering digits 1 to i with total cost j
13 const dp: number[][] = Array(10)
14 .fill(0)
15 .map(() => Array(target + 1).fill(-NEGATIVE_INFINITY));
16
17 // backtrack[i][j] stores the previous cost state for reconstruction
18 // If backtrack[i][j] = j, we didn't use digit i
19 // Otherwise, we used digit i and moved from cost backtrack[i][j]
20 const backtrack: number[][] = Array(10)
21 .fill(0)
22 .map(() => Array(target + 1).fill(0));
23
24 // Base case: 0 digits with 0 cost is valid (0 digits used)
25 dp[0][0] = 0;
26
27 // Fill the DP table for each digit from 1 to 9
28 for (let digit = 1; digit <= 9; ++digit) {
29 const digitCost = cost[digit - 1];
30
31 for (let currentCost = 0; currentCost <= target; ++currentCost) {
32 // Option 1: Don't use current digit - inherit from previous digit
33 // Option 2: Use current digit if we have enough budget
34
35 if (currentCost < digitCost || dp[digit][currentCost - digitCost] + 1 < dp[digit - 1][currentCost]) {
36 // Either can't afford this digit or using it doesn't give more digits
37 dp[digit][currentCost] = dp[digit - 1][currentCost];
38 backtrack[digit][currentCost] = currentCost;
39 } else {
40 // Use this digit as it gives us more total digits
41 dp[digit][currentCost] = dp[digit][currentCost - digitCost] + 1;
42 backtrack[digit][currentCost] = currentCost - digitCost;
43 }
44 }
45 }
46
47 // Check if it's possible to form any number with exact target cost
48 if (dp[9][target] < 0) {
49 return '0';
50 }
51
52 // Reconstruct the largest number by backtracking
53 // Start from largest digit (9) to ensure maximum value
54 const result: number[] = [];
55 let currentDigit = 9;
56 let remainingCost = target;
57
58 while (currentDigit > 0) {
59 if (backtrack[currentDigit][remainingCost] === remainingCost) {
60 // Didn't use this digit, try smaller digit
61 --currentDigit;
62 } else {
63 // Used this digit, add it to result
64 result.push(currentDigit);
65 remainingCost = backtrack[currentDigit][remainingCost];
66 }
67 }
68
69 // Convert digit array to string
70 return result.join('');
71}
72
Time and Space Complexity
Time Complexity: O(n * target)
where n
is the length of the cost array (which is 9 in this problem since digits are 1-9).
The algorithm uses dynamic programming with two nested loops:
- The outer loop iterates through each digit from 1 to 9 (i.e., through the cost array)
- The inner loop iterates through all possible values from 0 to target
- Each iteration performs constant time operations (comparisons and assignments)
- The reconstruction phase (while loop at the end) runs in
O(target)
time in the worst case, as we can select at mosttarget
digits (when all costs are 1)
Therefore, the overall time complexity is O(9 * target) + O(target) = O(target)
.
Space Complexity: O(n * target) = O(target)
The algorithm uses:
- Two 2D arrays
f
andg
, each of size10 × (target + 1)
, requiringO(10 * target) = O(target)
space - An array
ans
to store the result digits, which in the worst case could havetarget
elements (when minimum cost is 1), requiringO(target)
space - A few constant variables
i
,j
, andc
The total space complexity is O(target) + O(target) = O(target)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect DP Initialization - Using 0 Instead of Negative Infinity
The Pitfall: A common mistake is initializing the DP table with 0 instead of negative infinity:
# WRONG - This makes invalid states appear valid
dp = [[0] * (target + 1) for _ in range(10)]
This causes the algorithm to incorrectly consider impossible states as valid (having 0 digits), leading to wrong answers when backtracking.
Why This Happens:
When we check dp[digit][current_cost - digit_cost] + 1
, if this cell contains 0 (but should be impossible), we'd incorrectly think we can add 1 digit to a valid 0-digit solution.
The Fix: Always initialize with negative infinity except for the base case:
dp = [[-float('inf')] * (target + 1) for _ in range(10)]
dp[0][0] = 0 # Only valid base case
2. Allowing Digit Reuse in the Wrong DP Dimension
The Pitfall:
Using dp[digit - 1][current_cost - digit_cost]
instead of dp[digit][current_cost - digit_cost]
:
# WRONG - Prevents digit reuse use_digit = dp[digit - 1][current_cost - digit_cost] + 1
This would mean each digit can only be used once, drastically limiting our solutions.
The Fix: Allow the same digit to be reused by referencing the same digit row:
# CORRECT - Allows digit reuse use_digit = dp[digit][current_cost - digit_cost] + 1
3. Incorrect Backtracking Logic
The Pitfall: During reconstruction, incorrectly determining when a digit was used:
# WRONG - Comparing with wrong value
if parent[current_digit][remaining_cost] != remaining_cost - cost[current_digit - 1]:
current_digit -= 1
else:
result.append(str(current_digit))
remaining_cost = parent[current_digit][remaining_cost]
Why This Fails: The parent array stores the previous cost state, not the cost difference. Misunderstanding this leads to incorrect digit selection.
The Fix: Check if the cost remained the same (digit not used) or changed (digit used):
if remaining_cost == parent[current_digit][remaining_cost]:
# Cost unchanged - digit not used
current_digit -= 1
else:
# Cost changed - digit was used
result.append(str(current_digit))
remaining_cost = parent[current_digit][remaining_cost]
4. Not Handling the Greedy Choice Correctly
The Pitfall: Breaking ties incorrectly when multiple options give the same digit count:
# WRONG - Using >= instead of > if use_digit >= dont_use: # This might not give largest number dp[digit][current_cost] = use_digit
Why This Matters:
When use_digit == dont_use
, we have two ways to achieve the same digit count. Since we process digits from 1 to 9 and reconstruct from 9 to 1, using >=
would prefer smaller digits when counts are equal, giving a smaller final number.
The Fix: Use strict inequality to prefer the "don't use" option when counts are equal:
if use_digit > dont_use: # Only use digit if it gives MORE digits dp[digit][current_cost] = use_digit
This ensures that during backtracking from digit 9 to 1, we naturally prefer larger digits when multiple options exist for the same digit count.
5. Off-by-One Errors with Digit Indexing
The Pitfall:
Forgetting that digit i
corresponds to cost[i-1]
:
# WRONG - Using wrong index digit_cost = cost[digit] # Should be cost[digit - 1]
The Fix: Always remember the mapping: digit 1 → cost[0], digit 2 → cost[1], ..., digit 9 → cost[8]:
digit_cost = cost[digit - 1]
What's the output of running the following function using input 56
?
1KEYBOARD = {
2 '2': 'abc',
3 '3': 'def',
4 '4': 'ghi',
5 '5': 'jkl',
6 '6': 'mno',
7 '7': 'pqrs',
8 '8': 'tuv',
9 '9': 'wxyz',
10}
11
12def letter_combinations_of_phone_number(digits):
13 def dfs(path, res):
14 if len(path) == len(digits):
15 res.append(''.join(path))
16 return
17
18 next_number = digits[len(path)]
19 for letter in KEYBOARD[next_number]:
20 path.append(letter)
21 dfs(path, res)
22 path.pop()
23
24 res = []
25 dfs([], res)
26 return res
27
1private static final Map<Character, char[]> KEYBOARD = Map.of(
2 '2', "abc".toCharArray(),
3 '3', "def".toCharArray(),
4 '4', "ghi".toCharArray(),
5 '5', "jkl".toCharArray(),
6 '6', "mno".toCharArray(),
7 '7', "pqrs".toCharArray(),
8 '8', "tuv".toCharArray(),
9 '9', "wxyz".toCharArray()
10);
11
12public static List<String> letterCombinationsOfPhoneNumber(String digits) {
13 List<String> res = new ArrayList<>();
14 dfs(new StringBuilder(), res, digits.toCharArray());
15 return res;
16}
17
18private static void dfs(StringBuilder path, List<String> res, char[] digits) {
19 if (path.length() == digits.length) {
20 res.add(path.toString());
21 return;
22 }
23 char next_digit = digits[path.length()];
24 for (char letter : KEYBOARD.get(next_digit)) {
25 path.append(letter);
26 dfs(path, res, digits);
27 path.deleteCharAt(path.length() - 1);
28 }
29}
30
1const KEYBOARD = {
2 '2': 'abc',
3 '3': 'def',
4 '4': 'ghi',
5 '5': 'jkl',
6 '6': 'mno',
7 '7': 'pqrs',
8 '8': 'tuv',
9 '9': 'wxyz',
10}
11
12function letter_combinations_of_phone_number(digits) {
13 let res = [];
14 dfs(digits, [], res);
15 return res;
16}
17
18function dfs(digits, path, res) {
19 if (path.length === digits.length) {
20 res.push(path.join(''));
21 return;
22 }
23 let next_number = digits.charAt(path.length);
24 for (let letter of KEYBOARD[next_number]) {
25 path.push(letter);
26 dfs(digits, path, res);
27 path.pop();
28 }
29}
30
Recommended Readings
What is Dynamic Programming Prerequisite DFS problems dfs_intro Backtracking problems backtracking Memoization problems memoization_intro Pruning problems backtracking_pruning Dynamic programming is an algorithmic optimization technique that breaks down a complicated problem into smaller overlapping sub problems in a recursive manner and uses solutions to the sub problems to construct a solution
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!