這類問題一般是給出候選集合(一般為數組 array [ ])和一個限定值(S),然后讓你求某一結果。
一般DFS與DP均可。下面談談這兩種思維方式不同。
DFS一般是對數組array元素進行討論,比如最后一個元素的有無。然后順序遞歸,削減數組長度,通過遞歸遍歷整個數組,得出最終結果。
比如全排列問題,比如組合問題。
DP則直接對限定值S進行討論,比如S-array[n] 的值是什么。通過討論S的前一值,建立DP表格,削減S,通過保存S的前一值來降低復雜度,得出最終結果。
比如背包問題,比如換硬幣問題。
下面通過換硬幣問題的兩種解法,來具體展示一下思維着力點的不同。
問題描述(LeetCode):
You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.
Example 1:
coins = [1, 2, 5], amount = 11
return 3 (11 = 5 + 5 + 1)
Example 2:
coins = [2], amount = 3
return -1.
Note:
You may assume that you have an infinite number of each kind of coin.
DFS解法:對是否包含coins[n-1]進行討論,然后遞歸值conis[n-2],直至conis[0]。
public class Solution {
private int minNum = 0x7fffffff;
public void coinNum(int[] coins, int amount, int end, int num){
if (end < 0){
return;
}
if (amount == 0){
if (num < minNum){
minNum = num;
}
}else {
if(num > minNum) return; // 大於最小次數,不再遞歸。
for(int i = end; i > -1; i--){
if(amount >= coins[i]){
coinNum(coins, amount - coins[i], i, num+1); //包含coins[i]的情況
}
}
}
}
public int coinChange(int[] coins, int amount) {
coinNum(coins, amount, coins.length-1, 0);
if (minNum == 0x7fffffff){
return -1;
}else
return minNum;
}
}
DP解法,主要對amount進行討論,通過遞歸算出amount-coin 的值來的出最終結果。
public class Solution {
private int coinNum(int[] coins, int amount, int[] result){
if (amount < 0) return -1;
if (amount == 0) return 0;
if (result[amount-1] != 0) return result[amount-1];
int min = 0x7fffffff;
for (int coin : coins){
int tmp = coinNum(coins, amount-coin, result);
if (tmp >= 0 && tmp < min){
min = tmp+1;
}
}
result[amount-1] = (min == 0x7fffffff) ? -1 : min;
return result[amount-1];
}
public int coinChange(int[] coins, int amount) {
return coinNum(coins, amount, new int[amount]);
}
}
