题目描述
arr是货币数组,其中的值都是正数。再给定一个正数aim。 每个值都认为是一张货币,认为值相同的货币没有任何不同,返回组成aim的方法数
例如:arr = {1,2,1,1,2,1,2},aim = 4
方法:1+1+1+1、1+1+2、2+2
一共就3种方法,所以返回3
题目解析
暴力递归
class Solution {
struct Info{
std::vector<int> coins;
std::vector<int> zhangs;
};
Info getInfos(vector<int>& coins){
std::map<int, int> mapper;
for(auto i : coins){
++mapper[i];
}
Info info;
for(auto i : mapper){
info.coins.emplace_back(i.first);
info.zhangs.emplace_back(i.second);
}
return info;
}
int process(vector<int>& coins, vector<int>& zhangs, int idx, int rest){
int N = coins.size();
if(idx == N){
return rest == 0 ? 1 : 0;
}
int ways = 0;
for (int zhang = 0; zhang * coins[idx] <= rest && zhang <= zhangs[idx]; ++zhang) {
ways += process(coins, zhangs, idx + 1, rest - zhang * coins[idx]);
}
return ways;
}
public:
int coinsWay(vector<int>& coins, int amount){
if(amount < 0){
return -1;
}
if(amount == 0 || coins.empty()){
return 0;
}
auto item = getInfos(coins);
return process(item.coins, item.zhangs, 0, amount);
}
};
暴力递归改动态规划
class Solution {
struct Info{
std::vector<int> coins;
std::vector<int> zhangs;
};
Info getInfos(vector<int>& coins){
std::map<int, int> mapper;
for(auto i : coins){
++mapper[i];
}
Info info;
for(auto i : mapper){
info.coins.emplace_back(i.first);
info.zhangs.emplace_back(i.second);
}
return info;
}
int process(vector<int>& coins, vector<int>& zhangs, int idx, int rest){
int N = coins.size();
if(idx == N){
return rest == 0 ? 1 : 0;
}
int ways = 0;
for (int zhang = 0; zhang * coins[idx] <= rest && zhang <= zhangs[idx]; ++zhang) {
ways += process(coins, zhangs, idx + 1, rest - zhang * coins[idx]);
}
return ways;
}
public:
int coinsWay(vector<int>& moneys, int amount){
if(amount < 0){
return -1;
}
if(amount == 0 || moneys.empty()){
return 0;
}
auto item = getInfos(moneys);
auto coins = item.coins, zhangs = item.zhangs;
int N = coins.size();
std::vector<std::vector<int>> dp(N + 1, std::vector<int>(amount + 1, 0));
dp[N][0] = 1;
for (int idx = N - 1; idx >= 0; --idx) {
for (int rest = 0; rest <= amount; ++rest) {
int ways = 0;
for (int zhang = 0; zhang * coins[idx] <= rest && zhang <= zhangs[idx]; ++zhang) {
ways += dp[idx + 1][rest - zhang * coins[idx]];
}
dp[idx][rest] = ways;
}
}
return dp[0][ amount];
}
};
斜率优化
有上面可以推出:(假设只有5张)
- d p [ 2 ] [ 20 ] = d p [ 3 ] [ 20 ] + d p [ 3 ] [ 18 ] + d p [ 3 ] [ 16 ] + d p [ 3 ] [ 14 ] + d p [ 3 ] [ 12 ] + d p [ 3 ] [ 10 ] dp[2][20] = dp[3][20] + dp[3][18] + dp[3][16] + dp[3][14] + dp[3][12] + dp[3][10] dp[2][20]=dp[3][20]+dp[3][18]+dp[3][16]+dp[3][14]+dp[3][12]+dp[3][10]
- d p [ 2 ] [ 22 ] = d p [ 3 ] [ 22 ] + d p [ 3 ] [ 20 ] + d p [ 3 ] [ 18 ] + d p [ 3 ] [ 16 ] + d p [ 3 ] [ 14 ] + d p [ 3 ] [ 12 ] dp[2][22] = dp[3][22] + dp[3][20] + dp[3][18] + dp[3][16] + dp[3][14] + dp[3][12] dp[2][22]=dp[3][22]+dp[3][20]+dp[3][18]+dp[3][16]+dp[3][14]+dp[3][12]
因此:
- d p [ 2 ] [ 22 ] = d p [ 3 ] [ 22 ] + d p [ 2 ] [ 20 ] − d p [ 3 ] [ 10 ] dp[2][22] = dp[3][22] + dp[2][20] - dp[3][10] dp[2][22]=dp[3][22]+dp[2][20]−dp[3][10]
又因为:
- d p [ 2 ] [ 22 ] = d p [ 3 ] [ 22 − 0 ∗ 2 ] + d p [ 3 ] [ 22 − 1 ∗ 2 ] + d p [ 3 ] [ 22 − 2 ∗ 2 ] + d p [ 3 ] [ 22 − 3 ∗ 2 ] + d p [ 3 ] [ 22 − 4 ∗ 2 ] + d p [ 3 ] [ 22 − 5 ∗ 2 ] dp[2][22] = dp[3][22 - 0 * 2] + dp[3][22 - 1 * 2] + dp[3][22 - 2 * 2] + dp[3][22 - 3* 2] + dp[3][22 - 4 * 2] + dp[3][22 - 5 * 2] dp[2][22]=dp[3][22−0∗2]+dp[3][22−1∗2]+dp[3][22−2∗2]+dp[3][22−3∗2]+dp[3][22−4∗2]+dp[3][22−5∗2]
- d p [ 2 ] [ 22 ] = d p [ 3 ] [ 22 − 0 ∗ 2 ] + d p [ 3 ] [ 22 − 1 ∗ 2 ] d p [ 3 ] [ 22 − 2 ∗ 2 ] + d p [ 3 ] [ 22 − 3 ∗ 2 ] + d p [ 3 ] [ 22 − 4 ∗ 2 ] + d p [ 3 ] [ 22 − z h a n g [ i d x ] ∗ 2 ] dp[2][22] = dp[3][22 - 0 * 2] + dp[3][22 - 1 * 2] dp[3][22 - 2 * 2] + dp[3][22 - 3* 2] + dp[3][22 - 4 * 2] + dp[3][22 - zhang[idx] * 2] dp[2][22]=dp[3][22−0∗2]+dp[3][22−1∗2]dp[3][22−2∗2]+dp[3][22−3∗2]+dp[3][22−4∗2]+dp[3][22−zhang[idx]∗2]
- d p [ 2 ] [ 22 ] = d p [ 3 ] [ 22 − 0 ∗ c o i n s [ i d x ] ] + d p [ 3 ] [ 22 − 1 ∗ c o i n s [ i d x ] ] + d p [ 3 ] [ 22 − 2 ∗ c o i n s [ i d x ] ] + d p [ 3 ] [ 22 − 3 ∗ c o i n s [ i d x ] ] + d p [ 3 ] [ 22 − 4 ∗ c o i n s [ i d x ] ] + d p [ 3 ] [ 22 − z h a n g [ i d x ] ∗ c o i n s [ i d x ] ] dp[2][22] = dp[3][22 - 0 * coins[idx]] + dp[3][22 - 1 * coins[idx]] + dp[3][22 - 2 * coins[idx]] + dp[3][22 - 3 * coins[idx]]+ dp[3][22 - 4 * coins[idx]]+ dp[3][22 - zhang[idx] * coins[idx]] dp[2][22]=dp[3][22−0∗coins[idx]]+dp[3][22−1∗coins[idx]]+dp[3][22−2∗coins[idx]]+dp[3][22−3∗coins[idx]]+dp[3][22−4∗coins[idx]]+dp[3][22−zhang[idx]∗coins[idx]]
相当于:
- d p [ 2 ] [ 22 ] = d p [ 3 ] [ 22 − ( 0 + 1 + 2 + . . . . + z h a n g [ i d x ] ) ∗ c o i n s [ i d x ] ] dp[2][22] = dp[3][22 - (0+1+2+....+zhang[idx])* coins[idx]] dp[2][22]=dp[3][22−(0+1+2+....+zhang[idx])∗coins[idx]]
从:
- d p [ 2 ] [ 22 ] = d p [ 3 ] [ 22 ] + d p [ 2 ] [ 20 ] − d p [ 3 ] [ 10 ] dp[2][22] = dp[3][22] + dp[2][20] - dp[3][10] dp[2][22]=dp[3][22]+dp[2][20]−dp[3][10]
推广:
- d p [ i d x ] [ r e s t ] = d p [ i d x + 1 ] [ r e s t ] + d p [ i d x ] [ r e s t − c o i n s [ i d x ] ] − d p [ i d x + 1 ] [ r e s t − ( z h a n g [ i d x ] + 1 ) ∗ c o i n s [ i d x ] ] dp[idx][rest] = dp[idx + 1][rest] + dp[idx][rest - coins[idx]] - dp[idx + 1][rest - (zhang[idx] + 1) * coins[idx]] dp[idx][rest]=dp[idx+1][rest]+dp[idx][rest−coins[idx]]−dp[idx+1][rest−(zhang[idx]+1)∗coins[idx]]
class Solution {
struct Info{
std::vector<int> coins;
std::vector<int> zhangs;
};
Info getInfos(vector<int>& coins){
std::map<int, int> mapper;
for(auto i : coins){
++mapper[i];
}
Info info;
for(auto i : mapper){
info.coins.emplace_back(i.first);
info.zhangs.emplace_back(i.second);
}
return info;
}
public:
int coinsWay(vector<int>& moneys, int amount){
if(amount < 0){
return -1;
}
if(amount == 0 || moneys.empty()){
return 0;
}
auto item = getInfos(moneys);
auto coins = item.coins, zhangs = item.zhangs;
int N = coins.size();
std::vector<std::vector<int>> dp(N + 1, std::vector<int>(amount + 1, 0));
dp[N][0] = 1;
for (int idx = N - 1; idx >= 0; --idx) {
for (int rest = 0; rest <= amount; ++rest) {
dp[idx][rest] = dp[idx + 1][rest];
if(rest - coins[idx] >= 0){
dp[idx][rest] += dp[idx][rest - coins[idx]];
}
if(rest - (zhangs[idx] + 1) * coins[idx] >= 0){
dp[idx][rest] -= dp[idx + 1][rest - (zhangs[idx] + 1) * coins[idx]];
}
}
}
return dp[0][ amount];
}
};