2.18 数组分割
2.18 数组分割
基础问题:有一个没有排序的,元素个数为2n的正整数数组,要去:如何能把这个数组分割成为元素个数为n的两个数组,并且使两个子数组的和最接近
解法:
- 解法 1 : 动态规划
- 状态定义:boolean dp[i][j] 表示数组从下表0开始到下表i区间范围内选取若干个正整数,是否存在一种选取方法使得被选取的这些正整数的和等于j。
- 状态转移方程 :
dp[i][j] = {
dp[i-1][j] | dp[i-1][j-nums[i]] , if j >= nums[i]
dp[]i-1][j] , if j < nums[i]
} - 初始状态:
boolean dp[i][j] = false , for all i && all j
dp[i][0] = true , for all i , 表示不选取任何整数,则被选取的整数的和为0
dp[0][nums[0]] = true , 表示当i==0的时候,只有一个正整数可以被选取,因此dp[0][nums[0]] = true
拓展问题:如果数组中有负数怎么办?
all coding
// 2.18 数组分割
class Test{
public static void main(String[] args) {
/**
基础问题:有一个没有排序的,元素个数为2n的正整数数组,要去:如何能把这个数组分割成为元素个数为n的两个数组,并且使两个子数组的和最接近
> 解法:
- 解法 1 : 动态规划
状态定义:
boolean dp[i][j] 表示数组从下表0开始到下表i区间范围内选取若干个正整数,是否存在一种选取方法使得被选取的这些正整数的和等于j。
状态转移方程 :
dp[i][j] = {
dp[i-1][j] | dp[i-1][j-nums[i]] , if j >= nums[i]
dp[]i-1][j] , if j < nums[i]
}
初始状态:
boolean dp[i][j] = false , for all i && all j
dp[i][0] = true , for all i , 表示不选取任何整数,则被选取的整数的和为0
dp[0][nums[0]] = true , 表示当i==0的时候,只有一个正整数可以被选取,因此dp[0][nums[0]] = true
*/
int[] arr = new int[]{1,5,11,5};
int[] arr2 = new int[]{1,2,3,5};
System.out.println(canPartition(arr));
}
public static void print(boolean[][] arr){
for(boolean[] ar:arr){
for(boolean a:ar){
System.out.print(a+" ");
}
System.out.println();
}
}
public static boolean canPartition(int[] nums){
int n = nums.length;
if(n<2) return false;
int sum = 0;
int maxNum = 0;
for(int num:nums){
sum+=num;
maxNum = Math.max(maxNum,num);
}
if(sum%2 != 0) return false;
int target = sum/2;
if(maxNum > target) return false;
boolean[][] dp = new boolean[n][target+1];
for(int i = 0;i<n;i++) dp[i][0] = true;
dp[0][nums[0]] = true;
for(int i=1;i<n;i++){
int num = nums[i];
for(int j =1;j<=target;j++){
if( j>= num) dp[i][j] = dp[i-1][j] | dp[i-1][j-num];
else dp[i][j] = dp[i-1][j];
}
}
print(dp);
return dp[n-1][target];
}
/**
拓展问题:
如果数组中有负数怎么办?
*/
}
Saying Less Doing More