动态规划练习:
1.硬币找零(leetcode322)
给定一组硬币数,找出一组最少的硬币数,来找换零钱N。
比如,可用来找零的硬币为: 1、3、4 待找的钱数为 6。用两个面值为3的硬币找零,最少硬币数为2。而不是 4,1,1
public int coinChange(int[] coins, int amount) {
if(amount <= 0){
return 0;
}
if(coins.length == 0 ){
return -1;
}
//dp[i]:凑成i(前j的硬币中)元所需的最少硬币数
int[] dp = new int[amount+1];
for(int i = 1; i<dp.length; i++)
{
dp[i] = Integer.MAX_VALUE;
for(int j =0; j<coins.length; j++)
{
//dp[i - nums[kind]] != Integer.MAX_VALUE保证dp[i - nums[kind]]是可以凑出来的
if(coins[j]<=i && dp[i - coins[j]] != Integer.MAX_VALUE)
{
dp[i] = Math.min(dp[i], dp[i - coins[j]]+1);
}
}
}
return dp[amount] == Integer.MAX_VALUE? -1 : dp[amount];
}
}
2.等和拆分数组
判断能否将给定数组拆分成数组和相等的两个数组(leetcode416)
Input: [1, 5, 11, 5] Output: true Explanation: The array can be partitioned as [1, 5, 5] and [11].
思路:背包的变形题。可以看作是从数组中取数填满容积为sum/2的背包。如果可以填满则返回true,否则返回false。
class Solution {
public boolean canPartition(int[] nums) {
int sum = 0 ;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
if(sum%2 != 0 ){
return false;
}
return helper(nums,nums.length-1,sum/2);
}
private boolean helper(int[] nums, int index, int c) {
boolean[] dp = new boolean[c+1];
for (int i = 0; i <= c; i++) {
dp[i] = (nums[0] == i);
}
//i需要从c递减,而不能从1递增。因为dp[]只记录T,F,递增就会数组中的数据就会重复选取了。
for (int j = 1; j < nums.length; j++) {
for (int i = c; i >= nums[j]; i--) {
dp[i] = dp[i] || dp[i - nums[j]];
}
}
return dp[c];
}
}