一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情。
题目描述
Given an array of integers nums and a positive integer k, find whether it's possible to divide this array into k non-empty subsets whose sums are all equal.
Example 1:
Input: nums = [4, 3, 2, 3, 5, 2, 1], k = 4
Output: True
Explanation: It's possible to divide it into 4 subsets (5), (1, 4), (2,3), (2,3) with equal sums.
思路分析
这道题我只是穷举的做了下,相当于递归写一个深度优先遍历,每次取一个数,如果待计算数组长度大于sum/k,则此路不通,如果待计算长度小于k,则继续深度遍历,从数组中再选一个未被使用的元素,然后加入待待计算数组中(为了方便计算,这里加入的其实是索引)。如果待计算长度等于k,则将索引设置为已使用(代码写完发现好像是没用的)。并将已分割成功数组数量+1.
后来发现这种计算长度和k的关系其实是可以简化的,一些遍历也可以进行剪枝。
代码实现
public boolean dfs(int[] nums,int k,int target,int i,int cursum,boolean[] isvisited){
if (k == 1) return true;
if (cursum == target) return dfs(nums,k - 1,target,0,0,isvisited);
for (int j = i;j < nums.length;j ++){
if (! isvisited[j] && nums[j] + cursum <= target){
isvisited[j] = true;
if (dfs(nums,k,target,j + 1,cursum + nums[j],isvisited)) return true;
isvisited[j] = false;
}
}
return false;
}
总结
代码的一个精妙的点就是,对于一个链路,通过传递索引i的方式,使其一定只遍历一次。
而实现剪枝。
同时,对于待计算数组和为k时,其实没有必要进行复杂的操作,可以直接调用我们的dfs函数,只需要将索引置为0(因为需要重新选举数组中的元素)、将待计算和置为0。而且更妙的一点是不需要存储待计算数组了,因为visited本身是够用的。