zoukankan      html  css  js  c++  java
  • leetcode 416.分割等和子集(回溯解法以及dp 解法)

    给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

    注意:
    每个数组中的元素不会超过 100
    数组的大小不会超过 200
    示例 1:

    输入: [1, 5, 11, 5]
    输出: true
    解释: 数组可以分割成 [1, 5, 5] 和 [11].

    示例 2:

    输入: [1, 2, 3, 5]
    输出: false
    解释: 数组不能分割成两个元素和相等的子集.

    本题我的第一想法就是回溯,利用晦回溯遍历整个数组的所有子数组,观察子数组的和是否是数组和的1/2。 在利用回溯进行选择的时候,对"选择"(数组)往往先通过排序,利用有序性,可以帮助剪枝,也可以帮助去重。两种回溯的写法如下:

    bool comp(int & a, int & b){
        return a > b;
    }
    
    class Solution {
    public:
        bool DFS(vector<int> & nums, int ptr, int curr_sum, int target)
        {
            int remain = target - curr_sum;
            for (int i = ptr; i < nums.size(); i++)
            {
                if (nums[i]==remain)
                    return true;
                else if (nums[i] < remain)
                {
                    if (DFS(nums, i+1, curr_sum+nums[i], target))
                        return true;
                }
                //nums[i] > remain的情况不用管,直接下一步
            }
            return false;//全部都搜过一遍还是没有return true
        }
    
        bool canPartition(vector<int>& nums)
        {
            int n = nums.size();
            int tot_sum = 0;
            for (int i = 0; i < n; i++)
            {
                tot_sum += nums[i];
            }
            if (tot_sum % 2 != 0)
                return false;
            int div_sum = tot_sum / 2;
    
            sort(nums.begin(), nums.end(), comp);//降序排列
            if (nums[0] > div_sum) return false;//第一个就已经过半了
            else {
                if (DFS(nums, 0, 0, div_sum))
                    return true;
                else return false;
            }
        }
    };
    
    class Solution {
    public:
        bool DFS(int target,vector<int>& nums,int j)
        {
            if(target==0)
                return true;
            if(j==nums.size())
                return false;
            if(target<0)
                return false;
            return DFS(target-nums[j],nums,j+1)||DFS(target,nums,j+1);
        }
        bool canPartition(vector<int>& nums) {
             int sum=accumulate(nums.begin(),nums.end(),0);
             sort(nums.rbegin(),nums.rend());
             int target=sum/2;
             if(sum%2==1)
                 return false;
             if(nums[0]>target)
                 return false;
             if(nums[0]==target)
                 return true;
             return DFS(target,nums,0);
        }
    };
    

    这道题目可以使用动态规划的思想,创建二维数组 (dp),包含 (n)(target+1) 列,其中 (dp[i][j]) 表示从数组的 ([0,i])(左闭右闭) 下标范围内选取若干个正整数(可以是 (0) 个),是否存在一种选取方案使得被选取的正整数的和等于 (j)。初始时,(dp) 中的全部元素都是 (false)

    class Solution {
    public:
        bool canPartition(vector<int>& nums) {
            int n = nums.size();
            if (n < 2) {
                return false;
            }
            int sum = accumulate(nums.begin(), nums.end(), 0);
            int maxNum = *max_element(nums.begin(), nums.end());
            if (sum & 1) {
                return false;
            }
            int target = sum / 2;
            if (maxNum > target) {
                return false;
            }
            vector<vector<int>> dp(n, vector<int>(target + 1, 0));
            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];
                    }
                }
            }
            return dp[n - 1][target];
        }
    };
    
  • 相关阅读:
    错误处理
    触发器
    存储过程
    用户自定义函数
    动态 SQL
    临时表
    游标
    流程控制元素
    锁定和阻塞
    Spring内置事件以及自定义事件
  • 原文地址:https://www.cnblogs.com/wsl-hitsz/p/13797397.html
Copyright © 2011-2022 走看看