416. 分割等和子集

问题

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

示例 1:
输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。

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

分析

经过尝试,这题最好递推,不然记忆递归几乎都会超时。

法一、暴力递归,超时,测试用例39/147

class Solution {
public:
    int target = 0;
    int n_n = 0;
    vector<int> q;
    bool res = false;
    void dfs(int x, int cur_sum) {
        if (cur_sum == target) {
            res = true;
            return ;
        }
        if (cur_sum > target || x >= n_n) {return ;}
        dfs(x+1, cur_sum); // 不选
        dfs(x+1, cur_sum+q[x]); // 选
    }
    bool canPartition(vector<int>& nums) {
        this->n_n = nums.size();
        this->q = nums;
        for (int i = 0; i < n_n; i++) {
            target += nums[i];
        }
        if (target % 2) {return false;}
        target /= 2;
        dfs(0, 0);
        return res;
    }
};

法二、基于unordered_map的记忆递归,仍然超时,141/147

class Solution {
public:
    int target = 0;
    int n_n = 0;
    vector<int> q;
    unordered_map<int, unordered_map<int, bool>> mem;
    bool dfs(int x, int cur_sum) {
        if (mem.count(x) && mem[x].count(cur_sum)) {
            return mem[x][cur_sum];
        }
        if (cur_sum == target) {
            mem[x][cur_sum] = true; return true;
        }
        if (cur_sum > target || x >= n_n) {
            mem[x][cur_sum] = false; return false;
        }
        bool t1, t2;
        t1 = dfs(x+1, cur_sum); // 不选
        t2 = dfs(x+1, cur_sum+q[x]); // 选
        bool ans = t1 || t2;
        mem[x][cur_sum] = ans;
        return ans;
    }
    bool canPartition(vector<int>& nums) {
        this->n_n = nums.size();
        this->q = nums;
        for (int i = 0; i < n_n; i++) {
            target += nums[i];
        }
        if (target % 2) {return false;}
        target /= 2;
        bool res = dfs(0, 0);
        return res;        
    }
};

法三、基于vector<vector<>>的记忆递归

但是类似于计数排序,如果target过大,vector将会爆内存。

class Solution {
public:
    int target = 0;
    int n = 0;
    vector<int> nums;
    vector<vector<int>> memo; // -1:未访问,0:不可行,1:可行
    bool dfs(int i, int cur_sum) {
        if (cur_sum == target) return true;
        if (cur_sum > target || i >= n) return false;
        if (memo[i][cur_sum] != -1) return memo[i][cur_sum];
        bool res = dfs(i + 1, cur_sum) || dfs(i + 1, cur_sum + nums[i]);
        memo[i][cur_sum] = res;
        return res;
    }
    bool canPartition(vector<int>& nums) {
        this->nums = nums;
        this->n = nums.size();
        int total = 0;
        for (int num : nums) total += num;
        if (total % 2 != 0) return false;
        target = total / 2;
        memo = vector<vector<int>>(n, vector<int>(target + 1, -1));
        return dfs(0, 0);
    }
};

递推

posted @ 2025-07-08 16:53  saulstavo  阅读(9)  评论(0)    收藏  举报