算法题总结-均等划分

原题
https://leetcode.cn/problems/partition-to-k-equal-sum-subsets/submissions/
给定一个整数数组 nums 和一个正整数 k,找出是否有可能把这个数组分成 k 个非空子集,其总和都相等。[1 <= k <= len(nums) <= 16]
输入示例

nums = [4, 3, 2, 3, 5, 2, 1], k = 4

输出示例

True

官方解法:
核心在于回溯算法。回溯算法即,尝试是否能找到,如果能找到所有组合即返回,如果没找到,就返回上层递归,重新尝试新组合
解析:
1.每件物品能且仅能取一次,因此,肯定需要保存每次尝试组合时,物品的状态(因为后续必须要用到@cache提速 因此状态必须用二进制来判断从而使得状态变成单个数字)
2.由于每个物品都要尝试组合,因此,不能在取出一组就返回,因此,递归过程中,组合目标值必须通过取余运算,每次取完一组就重置(例如 19%19==0)
3.组合递归函数的特殊返回:
3.1 每件物品取完了 且目标值重置了[正常找到所有组合了]
3.2 for循环遍历过后没有找到正常的组合

源码:

class Solution:
    def __init__(self):
        self.value = 0
        self.minList = []
        pass
    
    @cache
    def recurisive(self,status:int,ratio:int)->bool:
        '''
        通过递归确定组合策略
        :param status: 每个数字的使用情况
        :param minList: 实际使用的数组
        :param ratio: 每次递归需要拼出来的值
        :param assemble: 上层已经拼出来的策略
        :return:
        '''
        if status==0 and ratio==0:
            return True
        for i in range(len(self.minList)):
            if ratio+self.minList[i]>self.value:
                continue
            if (status>>i) & 1:
                if self.recurisive(status-pow(2,i),int((ratio+self.minList[i])%self.value)):
                    return True
        return False

    def canPartitionKSubsets(self,nums:list[int],k:int)->bool:
        sumValue = sum(nums)
        if sumValue%k == 0:
            ratio = sumValue//k
            minList = []
            equalList = []
            for item in nums:
                if item<ratio:
                    minList.append(item)
                elif item==ratio:
                    equalList.append([item])
                else:
                    return False
            if len(equalList)==k:
                return True
            # 状态列表 1:未用 0:使用
            status = pow(2,len(minList))-1
            # 排序 首先确定最大值对应的策略[如果先确定最小值的策略 最大值很大可能拼不出来 例如 ratio=19 [1,1,1,.....,18]]
            minList.sort()
            self.minList = minList[::-1]
            self.value = ratio
            # 如果并不是一个数字一个策略 那么就肯定需要排列组合来确定
            out = self.recurisive(status,0)
            return out
        else:
            return False
posted @ 2023-06-19 17:03  356a  阅读(15)  评论(0编辑  收藏  举报