二刷698. Partition to K Equal Sum Subsets

Medium

这题原来的解法不是很好懂,有位拿到google offer的前辈说解法最重要的是“自己觉得好懂 + 面试当场能解释清楚”的。 我觉得很对,自己做得最顺的可能既不是最naive的也不是最优化的,但可以先用自己觉得最理解的方法做,再一步步学会优化即可。

一开始先算出来每分的和是多少,解决一些可以尽早判断t,f的情况。然后sort,如果最小的都比每分大,肯定false. 从后往前遍历去跳过那些本身就等于每分subsum的元素。比如[1,5,5,11]里面的11. 跳过的时候beginIndex--,k--. 然后新建一个size = k的int[] 来存subsets,每个index对应的数就是每一分现在的sum.

helper method需要int[k] subset, int[] nums, int subSum, int index做参数。这个index就是从后遍历到现在的那个index。我们可以进入helper method就判断这个index是不是小于0,如果是的话,说明我们已经遍历完所有的nums元素,直接return true。 然后我们选现在的这个selected数,让它尝试加入到当前subsets里的每一组。如果某一组加了之后可以partition成功,就返回true. 如果不能,就backtracking.

画一画recursion tree 再分析一下时间空间复杂度:
什么情况canPartition会return false???

class Solution {
    public boolean canPartitionKSubsets(int[] nums, int k) {
        int sum = 0;
        for (int i = 0; i < nums.length; i++){
            sum += nums[i];
        }
        if (sum % k != 0){
            return false;
        }
        int subSum = sum / k;
        Arrays.sort(nums);
        if (nums[0] > subSum){
            return false;
        }
        int beginIndex = nums.length - 1;
        while (beginIndex >= 0 && nums[beginIndex] == subSum){
                beginIndex--;
                k--;
        }
        return canPartition(nums, subSum, new int[k], beginIndex);
    }
    
    private boolean canPartition(int[] nums, int subSum, int[] subsets, int index){
        if (index < 0){
            return true;
        }
        int selected = nums[index];
        for (int i = 0; i < subsets.length; i++){
            if (subsets[i] + selected <= subSum){
                subsets[i] += selected;
                if (canPartition(nums, subSum, subsets, index - 1)){
                    return true;
                }
                subsets[i] -= selected;
            }
        }
        return false;
    }
}

你可能感兴趣的:(二刷698. Partition to K Equal Sum Subsets)