Quick Overview

Return the fewest coins that add up exactly to an amount, first when every coin value can be reused without limit and then when each listed coin can be used at most once. An onsite coding problem that tests the difference between unlimited and single-use selection and the handling of amounts that cannot be formed.

Fewest Coins for an Amount with Unlimited or Single-Use Coins

Company: Oracle

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Onsite

You are given coin values `coins` and a target `amount`. Return the fewest coins whose values add up to exactly `amount`, or `-1` if no selection of coins does. The interview asked this in two forms, and `unlimited` selects between them: - `unlimited = True`: every value in `coins` is a denomination with an unlimited supply, so a value can be used any number of times. - `unlimited = False`: every element of `coins` is one physical coin that can be used at most once; equal values in the list are separate coins. The report describes the round only as the classic coin-change problem followed by the variant in which each coin can be used at most once; this version asks for the fewest coins in both forms. ### Function Signature ```python def fewest_coins(coins: list[int], amount: int, unlimited: bool) -> int: ``` ### Rules - `amount = 0` needs no coins, so the answer is `0` in both forms. - The answer counts coins, not distinct values: using the value 3 twice counts as two coins. - Return `-1` when `amount` cannot be formed exactly. ### Constraints - `1 <= len(coins) <= 100` - `1 <= coins[i] <= 10^4` - `0 <= amount <= 10^4` ### Examples **Example 1** ```text Input: coins = [1, 3, 4], amount = 6, unlimited = True Output: 2 ``` `3 + 3` uses two coins. Taking the largest coin first gives `4 + 1 + 1`, which uses three. **Example 2** ```text Input: coins = [1, 3, 4], amount = 6, unlimited = False Output: -1 ``` With each coin usable once, the reachable totals are 1, 3, 4, 5, 7 and 8, so 6 cannot be formed. **Example 3** ```text Input: coins = [2, 5, 2, 2], amount = 6, unlimited = False Output: 3 ``` The three separate 2-coins make 6; the 5-coin is not part of any selection that sums to 6.

Overview: Return the fewest coins that add up exactly to an amount, first when every coin value can be reused without limit and then when each listed coin can be used at most once. An onsite coding problem that tests the difference between unlimited and single-use selection and the handling of amounts that cannot be formed.

Read the full Oracle Software Engineer interview experience this question came from

You are given a list of coin values `coins`, a target `amount`, and a boolean `unlimited`. Return the fewest coins whose values add up to exactly `amount`, or `-1` if no selection of coins does. The interview asked this in two forms, and `unlimited` selects between them: - `unlimited = True`: every value in `coins` is a denomination with an unlimited supply, so a value can be used any number of times. - `unlimited = False`: every element of `coins` is one physical coin that can be used at most once; equal values in the list are separate coins. ### Rules - `amount = 0` needs no coins, so the answer is `0` in both forms. - The answer counts coins, not distinct values: using the value 3 twice counts as two coins. - Return `-1` when `amount` cannot be formed exactly. - The answer is a single integer (at most 10^4), so there is nothing to break ties on. Every input and output value fits in a 32-bit signed integer. ### Constraints - `1 <= len(coins) <= 100` - `1 <= coins[i] <= 10^4` - `0 <= amount <= 10^4` - `unlimited` is `True` or `False` ### Example 1 ```text Input: coins = [1, 3, 4], amount = 6, unlimited = True Output: 2 ``` `3 + 3` uses two coins. Taking the largest coin first gives `4 + 1 + 1`, which uses three. ### Example 2 ```text Input: coins = [1, 3, 4], amount = 6, unlimited = False Output: -1 ``` With each coin usable once, the reachable totals are 1, 3, 4, 5, 7 and 8, so 6 cannot be formed.

Constraints

  • 1 <= len(coins) <= 100
  • 1 <= coins[i] <= 10^4
  • 0 <= amount <= 10^4
  • unlimited is True or False

Examples

Input: ([7], 0, True)

Expected Output: 0

Explanation: amount = 0 needs no coins in the unlimited form.

Input: ([1, 2, 3], 0, False)

Expected Output: 0

Explanation: amount = 0 needs no coins in the at-most-once form.

Hints

  1. Example 1 shows that always taking the largest coin that fits can use more coins than necessary, so the choice must account for more than the biggest value.
  2. amount is at most 10^4, so it is feasible to reason about every total from 0 up to amount and how few coins reach each one.
  3. The two forms differ only in whether a coin is still available after it is used: in the at-most-once form make sure one list element is never counted twice, while equal values at different positions remain separate coins.

Loading coding console...

Show the approach

Approach

Keep an array dp over totals 0..amount, where dp[s] is the fewest coins found so far that sum to exactly s. dp[0] = 0 and every other entry starts at the sentinel amount + 1, which no real answer can reach because every coin is at least 1, so any exact selection for s uses at most s <= amount coins. Process the coins one list element at a time and relax dp[s] with dp[s - c] + 1.

Unlimited form: scan s upward from c to amount. When dp[s] is updated, dp[s - c] may already include the value c, so a denomination can be reused any number of times (unbounded knapsack). Invariant: after the first i elements, dp[s] is the minimum count over multisets of those values summing to s.

At-most-once form: scan s downward from amount to c. Then dp[s - c] still reflects only the earlier elements, so the current coin is added at most once (0/1 knapsack). Equal values are separate list elements and are processed separately, so duplicates count as distinct coins. Invariant: after the first i elements, dp[s] is the minimum size of a subset of those elements summing to s.

By induction both invariants hold after all coins, so dp[amount] is the answer, and an entry still at the sentinel means amount cannot be formed, giving -1. Edge cases: amount = 0 returns 0 without using any coin; coins larger than amount are skipped; totals unreachable by parity or a common divisor stay at the sentinel. Greedy largest-first is wrong (coins [1, 3, 4], amount 6 needs 3 + 3, not 4 + 1 + 1), which is why every total is considered. All values stay at most 10^4, so 32-bit integers suffice.

Time complexity:
O(n * amount), where n = len(coins)
Space complexity:
O(amount)