/**
* 416. 分割等和子集
* @author wsq
* @date 2020/10/11
给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
注意:
每个数组中的元素不会超过 100
数组的大小不会超过 200
示例 1:
输入: [1, 5, 11, 5]
输出: true
解释: 数组可以分割成 [1, 5, 5] 和 [11].
示例 2:
输入: [1, 2, 3, 5]
输出: false
解释: 数组不能分割成两个元素和相等的子集.
链接:https://leetcode-cn.com/problems/partition-equal-subset-sum
*/
package com.wsq.dp;
public class CanPartition {
/**
* 一开始想着用回溯的方式去实现,但是性能方面不够优化,导致运行失败
* 动态规划还是掌握的不熟练,加强训练吧
* @param nums
* @return
*/
public boolean canPartition(int[] nums) {
int n = nums.length;
if(n < 2) {
return false;
}
int totalSum = 0, maxNum = 0;
for(int i = 0; i < n; i++) {
totalSum += nums[i];
maxNum = Math.max(maxNum, nums[i]);
}
if(totalSum % 2 != 0) {
return false;
}
int target = totalSum / 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 + 1; j++) {
// if(j >=num) {
// dp[i][j] = dp[i-1][j] | dp[i-1][j-num];
// }else {
// dp[i][j] = dp[i-1][j];
// }
// }
// }
// 由于i状态的值只与i-1状态相关,因此可考虑采用以为数组代替二维数组
boolean[] dp = new boolean[target + 1];
dp[0] = true;
for(int i = 0; i < n; i++) {
int num = nums[i];
for(int j = target; j >= num; j--) {
dp[j] |= dp[j-num];
}
}
return dp[target];
}
public static void main(String[] args) {
int[] nums = {1, 5, 11, 5};
CanPartition cp = new CanPartition();
boolean ans = cp.canPartition(nums);
System.out.println(ans);
}
}