从大到小排序
sort(coins.rbegin(),coins.rend());
动态规划
f[n]表示构成n所需的最少硬币数 f[0]=0 对于每个硬币 f[n]=min(f[n],f[n-coins[i]]+1);
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
if(amount<0)return -1;
if(amount==0)return 0;
sort(coins.begin(),coins.end());
int n=coins.size();
int ans=0;
int Max = amount + 1;
vector<int> dp(amount + 1, Max);//必须将所有的dp赋最大值,因为要找最小值
dp[0] = 0;//自底向上,金额为0,最小硬币数为0
for(int i=1;i<amount+1;i++){
for(int j=0;j<n;j++){//遍历coins的金额
if (i-coins[j]>=0) {//必须大于,否则数组溢出
dp[i]=min(dp[i],dp[i-coins[j]]+1);
}
}
}
//返回金额为amount的最小硬币数 根据测试用例判断dp[amout]>amount
return dp[amount] > amount ? -1 : dp[amount];
}
};
广度优先遍历
数据结构deque
小归纳
像向量一样,它能够快速地随机访问任一个元素,并且能够高效地插入和删除容器的尾部元素。但它又与vector不同,deque支持高效插入和删除容器的头部元素,因此也叫做双端队列
void push_front(const T& x)//双端队列头部增加一个元素X
front()
void push_back(const T& x)//双端队列头部增加一个元素X
back()
insert()
erase()
void pop_front()//删除双端队列中最前一个元素
void pop_back()//删除双端队列中最后一个元素
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
if (amount < 1) return 0;
if (amount == 0)return 0;
deque<int> deq;
deq.push_back(amount);
vector<int> visited(amount+1);
visited[amount]=true;
int step=0;
sort(coins.begin(),coins.end());
while(!deq.empty()){
step++;
int size=deq.size();
for(int i=0;i<size;i++){
int head=deq.front();
deq.pop_front();
for (int coin : coins) {
int next=head-coin;
if(next==0){// 只要遇到 0,就找到了一个最短路径
return step;
}
if (next < 0) {
// 由于 coins 升序排序,后面的面值会越来越大,剪枝
break;
}
if(!visited[next]){//若未访问过
deq.push_back(next);
// 添加到队列的时候,就应该立即设置为 true
// 否则还会发生重复访问
visited[next]=true;
}
}
}
}
// 进入队列的顶点都出队,都没有看到 0 ,就表示凑不出当前面值
return -1;
}
};