1

image.png

  1. class Solution {
  2. public boolean canPartition(int[] nums) {
  3. int len = nums.length;
  4. int sum = 0;
  5. for (int num : nums) {
  6. sum += num;
  7. }
  8. if (sum % 2 == 1) {
  9. return false;
  10. }
  11. int target = sum / 2;
  12. boolean[] dp = new boolean[target + 1];
  13. // dp[0] = true;有没有都没影响
  14. if (nums[0] <= target) {
  15. dp[nums[0]] = true;
  16. }
  17. for (int i = 1; i < len; i++) {
  18. for (int j = target; j >= 0 && nums[i] <= j; j--) {
  19. //逆序遍历是不能覆盖之前的值,因为只用一维数组,当前元素的值由上一行或上一行左边某个值得来
  20. dp[j] = dp[j] || dp[j - nums[i]];
  21. }
  22. if (dp[target]) {
  23. return true;
  24. }
  25. }
  26. return dp[target];
  27. }
  28. }

2

image.png

  1. class Solution {
  2. public int numSquares(int n) {
  3. //dp[i] 表示当前数字i最少由几个完全平方数构成
  4. //dp[i] = Math.Min(dp[i],dp[i-j*j]+1);
  5. int[] dp = new int[n+1];
  6. Arrays.fill(dp,Integer.MAX_VALUE);
  7. dp[0] = 0;
  8. for(int i=1;i*i<=n;i++){
  9. int x = i*i;
  10. for(int j = x;j<=n;j++){
  11. dp[j] = Math.min(dp[j],dp[j-x]+1);
  12. }
  13. }
  14. return dp[n];
  15. }
  16. }
  1. 标签:动态规划
  2. 首先初始化长度为 n+1 的数组 dp,每个位置都为 0
  3. 如果 n 0,则结果为 0
  4. 对数组进行遍历,下标为 i,每次都将当前数字先更新为最大的结果,即 dp[i]=i,比如 i=4,最坏结果为 4=1+1+1+1 即为 4 个数字
  5. 动态转移方程为:dp[i] = MIN(dp[i], dp[i - j * j] + 1),i 表示当前数字,j*j 表示平方数
  6. 时间复杂度:O(n*sqrt(n))O(nsqrt(n)),sqrt 为平方根
  7. class Solution {
  8. public int numSquares(int n) {
  9. //dp[i] 表示当前数字i最少由几个完全平方数构成
  10. //dp[i] = Math.Min(dp[i],dp[i-j*j]+1);
  11. int[] dp = new int[n+1];
  12. for(int i=1;i<=n;i++){
  13. dp[i] = i; //每次最坏的情况就是+1
  14. for(int j = 1;i-j*j>=0;j++){
  15. dp[i] = Math.min(dp[i],dp[i-j*j]+1);
  16. }
  17. }
  18. return dp[n];
  19. }
  20. }

image.png