416. 分割等和子集
一、题目
给你一个 只包含正整数 的 非空 数组 nums
。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
二、思路
假定nums[]
数组下标从1
开始,如何确定f[i][j]
的值?
我们一般去考虑最后一步,那么对于当前的数字 nums[i]
,可以选取也可以不选取:
- 1、不选
nums[i]
,那么我们就从前i - 1
个数中选,看是否使得这些数字的和恰好等于j
,即f[i][j] = f[i - 1][j]
。 - 2、选择
nums[i]
,在背包可以装下的情况下,那么相应的背包容量就要减去nums[i]
,f[i][j]
的状态就可以从f[i - 1][j - nums[i]]
转移过来,即f[i][j] = f[i - 1][j - nums[i]]
。
综上,两种情况只要有一个为true
,f[i][j]
就为true
。因此状态转移方程为f[i][j] = f[i - 1][j] | f[i - 1][j - nums[i]]
。
三、代码
class Solution { public boolean canPartition(int[] nums) { int n = nums.length, sum = 0; for(int x : nums) sum += x; if(sum % 2 != 0) return false; int m = sum / 2; boolean[][] f = new boolean[n + 1][m + 1]; f[0][0] = true; for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ if(j >= nums[i - 1]) f[i][j] = f[i - 1][j - nums[i - 1]] || f[i - 1][j]; else f[i][j] = f[i - 1][j]; } } return f[n][m]; } }
四、分析
时间复杂度分析: O(n∗m),n
是nums
数组的大小,m
是数组元素和的一半。
空间复杂度分析:O(n∗m)