leetcode698. 划分为k个相等的子集(java)

划分为k个相等的子集

  • leetcode698. 划分为k个相等的子集
    • 回溯算法 + 剪枝
  • 回溯算法

leetcode698. 划分为k个相等的子集

给定一个整数数组 nums 和一个正整数 k,找出是否有可能把这个数组分成 k 个非空子集,其总和都相等。

示例 1:
输入: nums = [4, 3, 2, 3, 5, 2, 1], k = 4
输出: True
说明: 有可能将其分成 4 个子集(5),(1,4),(2,3),(2,3)等于总和。

示例 2:
输入: nums = [1,2,3,4], k = 3
输出: false

提示:
1 <= k <= len(nums) <= 16
0 < nums[i] < 10000
每个元素的频率在 [1,4] 范围内

回溯算法 + 剪枝

首先了解什么是回溯算法:
解决一个回溯问题,实际上就是一个决策树的遍历过程,站在回溯树的一个节点上,你只需要思考 3 个问题:

  1. 路径:也就是已经做出的选择。
  2. 选择列表:也就是你当前可以做的选择。
  3. 结束条件:也就是到达决策树底层,无法再做选择的条件。

代码框架:

result = []
def backtrack(路径, 选择列表):
    if 满足结束条件:
        result.add(路径)
        return
    
    for 选择 in 选择列表:
        做选择
        backtrack(路径, 选择列表)
        撤销选择

关于这道题,我们就是要考虑下,如何构造路径和选择列表,我们要选择的路径就是数组的数字,但结束条件呢,就是选择够k个相等的子集,因此我们把这些都放进回溯代码中,进行判断。直接代码演示:

代码演示:

class Solution {

     int n ,_k,t;
    int[]_nums;
    public boolean canPartitionKSubsets(int[] nums, int k) {
        if(nums.length == 1){
            return true;
        }
        if(k > nums.length){
            return false;
        }
        int sum = 0;
        for(int i = 0; i < nums.length;i++){
            sum += nums[i];
        }
        if(sum % k != 0){
            return false;
        }
        Arrays.sort(nums);
        _nums = nums;
        n = nums.length;
        _k = k;
        t = sum / k;
        return dfs(n - 1,0,0,new boolean[n]);
    }

     /**
     *
     * @param index
     * @param cur 当前元素和
     * @param cnt 已经凑够几个和为t的集合。
     * @param vis 标记哪些元素被使用过了。
     * @return
     */
    boolean dfs(int index,int cur,int cnt,boolean[]vis){
        //base case 数量刚好满足,
        if (cnt == _k){
            return true;
        }
        //当前选择的数字刚好满足时,进行下一次选择
        if (cur == t){
            //还是从最后一个元素开始选择,cur 初始化为0,集合数量加1,
            return dfs(n - 1,0,cnt + 1,vis);
        }
        for (int i = index;i >= 0;i--){
            //剪枝 元素已经选过了,或者选择大于t 进行下一次选择
            if (vis[i] || cur + _nums[i] > t){
                continue;
            }
            //选择中的数字标记下
            vis[i] = true;
            //进行递归
            if (dfs(i - 1,cur + _nums[i],cnt,vis)){
                return true;
            }
            //撤销选择
            vis[i] = false;
            //剪枝,累加和等于0 直接返回false;
            if (cur == 0){
                return false;
            }
        }
        return false;
    }
}

回溯算法

leetcode93. 复原 IP 地址

你可能感兴趣的:(数据结构,算法,java,java,开发语言,算法,数据结构,贪心算法,动态规划)