零钱兑换1
思想:完全背包,只是求最小硬币数
那么钱币有顺序和没有顺序都可以,都不影响钱币的最小个数。
所以本题并不强调集合是组合还是排列。
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
本题钱币数量可以无限使用,那么是完全背包。所以遍历的内循环是正序
public int coinChange(int[] coins, int amount) {
//总金额为j时的最少硬币数为dp[j]
if(amount==0)return 0;
int[] dp=new int[amount+1];
//初始化,如果只是初始化了dp[0]呢么最后的结果一定被初始值0覆盖,因为每次求得都是min
//因为状态方程是min,初始化一个最坏的情况,也就是无解
Arrays.fill(dp, amount+1);
dp[0]=0;
for(int i=0; i<coins.length; i++)
//完全背包,内层循环正序遍历
for(int j=coins[i]; j<=amount; j++) {
dp[j]=Math.min(dp[j], dp[j-coins[i]]+1);
}
//dp[amount]==amount+1就是无解的情况
return dp[amount]==amount+1 ? -1:dp[amount];
}
零钱兑换2
思想:完全背包、组合数(外层物品,内层背包)
public int change(int amount, int[] coins) {
//总金额为j时的组合数为dp[j]
int[] dp=new int[amount+1];
//金额为0的组合就1种
dp[0]=1;
//组合数
for(int i=0; i<coins.length; i++)
for(int j=coins[i]; j<=amount; j++) {
dp[j]+=dp[j-coins[i]];
}
return dp[amount];
}
组合总和4
思想:完全背包、排列数(外层背包,内层物品)
既然递归公式是 dp[i] += dp[i - j],那么dp[0] 一定为1,dp[0]是递归中一切数值的基础所在,如果dp[0]是0的话,其他数值都是0了。
public int combinationSum4(int[] nums, int target) {
//总和为j时的排列数为dp[i]
int[] dp=new int[target+1];
//和为0的组合就1种
dp[0]=1;
//排列数
for(int i=1; i<=target; i++)
for(int j=0; j<nums.length; j++) {
if(i>=nums[j])dp[i]+=dp[i-nums[j]];
}
return dp[target];
}
回文子串
思想:中心拓展法。和最长回文子串类似,但是要注释掉只向左拓展(或者只向右边拓展),不然像s="aaa"就会重复计算同一回文子串
public int countSubstrings(String s) {
int count=0;
int len=s.length();
int left,right;
for(int i=0; i<len; i++) {
count++;
left=i-1;
right=i+1;
while(left>=0 && s.charAt(i)==s.charAt(left)) {
count++;
left--;
}
// while(right<len && s.charAt(i)==s.charAt(right)) {
// count++;
// right++;
// }
while(left>=0 && right<len && s.charAt(right)==s.charAt(left)) {
count++;
right++;
left--;
}
}
return count;
}