划分为k个相等的子集
题目描述
给定一个整数数组 nums
和一个正整数 k
,找出是否有可能把这个数组分成 k
个非空子集,其总和都相等。
示例 1
输入: nums = [4, 3, 2, 3, 5, 2, 1], k = 4
输出: True
说明: 有可能将其分成 4 个子集(5),(1,4),(2,3),(2,3)等于总和。
题解
首先,我们知道 k
个子集的每一个和必须等于 target = sum(nums) / k
(如果 target
不是整数,那么是不符合题目要求的)。
我们可以对数组 num 进行排序,以便我们尝试先放置较大的元素。这种放置元素的方法将更快组合出较小大小的子集。我们还可以适当处理 nums[i] >= target 的情况。这些技巧不是解决问题所必需的,但它们在下面的解决方案中给出。
使用visited数组,将nums中的数字由大到小一次试探,将其添加到visited中,如果成功的达到了目标值,就减小问题规模,转化为划分为k-1个非空子集。
Python代码
nums = [10,10,10,7,7,7,7,7,7,6,6,6]
k = 3
class Solution:
def canPartitionKSubsets(self, nums, k) -> bool:
if k==1:
return True
target,rem = divmod(sum(nums), k)
if rem: return False
nums.sort(reverse=True)
n=len(nums)
if n<k:
return Fasle
visited=set()
def dfs(k,tmp_sum,loc):
if tmp_sum==target:
return dfs(k-1,0,0)
if k==1:
return True
for i in range(loc,n):
if i not in visited and nums[i]+tmp_sum<=target:
visited.add(i)
if dfs(k,tmp_sum+nums[i],i+1):#这一行代码其实就是满足相等情况就继续往下搜
return True
visited.remove(i)#不满足就把i去掉重新搜
return False
return dfs(k,0,0)
A = Solution()
print(A.canPartitionKSubsets(nums,k))
遇到的困难
想通过减小nums数组的规模来解决问题,遍历nums,将每个元素依次添加到num[1…length]中,递归出口nums.length 等于K时判断是否相等,这样大大增加了时间复杂度。
nums = [4, 3, 2, 3, 5, 2, 1]
k = 4
#判断是否相等
def isequal(nums):
b=len(set(nums)) #去重
#重复
if(b>1):
return False
#不重复,都相等
return True
length = len(nums)
issuccess = False
def Kdivide(nums):
#如果是小数,则不可能
target, rem = divmod(sum(nums), k)
if rem: return
if len(nums)==k:
if(isequal(nums)):
issuccess = True
return
return
else:
for j in range(len(nums)):
# if(temp[j]<=target):
for i in range(len(nums)):
if(i!=j):
temp = nums[:]
temp[i] += temp[j]
# if(temp[i]<=target):
temp.pop(j)
Kdivide(temp)
Kdivide(nums)
print(issuccess)