本周主要是dp+链表(学校课程的进度所以也写一下)
用dp写了两题:
乘积最大子数组
思路:与求最大和相似但是遇到负数元素会比较麻烦。若单是算最大值,则遇到负数的时候此前计算出的最大值就变为最小值,此时若单纯将这个最大值抛掉,遇到[3,2,-2,1,-3]这类情况时就会出错,因此需要一个min来保存,遇到负数的时候min与max交换(负数的min乘上负数就为max)(?
int MAX(int a,int b){
return (a>b)?a:b;
}
int MIN(int a,int b){
return (a<b)?a:b;
}
int maxProduct(int* nums, int numsSize){
int max=1,min = 1;
int res = nums[0];
for(int i=0;i<numsSize;i++){
if(nums[i]<0){
int temp = max;
max = min;
min = temp;
}
max = MAX(max*nums[i],nums[i]);
min = MIN(min*nums[i],nums[i]);
res = MAX(max,res);
}
return res;
}
零钱兑换
与算导中切钢管类似
思路:
1.将数组排序,然后用数组中最大数除amount取余,然后再用比前一个数小的数取余,以此循环直到amount=0
但这会出错,如[1,5,7] amount=10,r若按照这种方法计算,则使用硬币的最小数量为4(10=1+1+1+7)但答案应该是2(10=5+5)
2.类似以前写过的爬楼梯,如[1,2,5] amount = n 则f(n) = min(f(n-1),f(n-2),f(n-5)),用数组记录此前的最优解,以此求得amount==n时的最优解
int coinChange(int* coins, int coinsSize, int amount){
int *dp=(int *)malloc((amount+1)*sizeof(int));
memset(dp,-1,sizeof(int)*(amount+1));
for(int i=0;i<coinsSize&&coins[i]<=amount;i++)
dp[coins[i]]=1;
dp[0]=0;
for(int i=0;i<=amount;i++){
int number=amount+1;
for(int j=0;j<coinsSize;j++){
if(i-coins[j]>=0&&dp[i-coins[j]]!=-1) number=(dp[i-coins[j]]<number?dp[i-coins[j]]:number);
}
if(number!=amount+1)
dp[i]=number+1;
}
return dp[amount];
}