目录
698. 划分为k个相等的子集 - 力扣(LeetCode)
给定一个整数数组 nums 和一个正整数 k,找出是否有可能把这个数组分成 k 个非空子集,其总和都相等。
| 输入 | nums = [4, 3, 2, 3, 5, 2, 1], k = 4 |
| 输出 | true |
| 说明 | 有可能将其分成 4 个子集(5),(1,4),(2,3),(2,3)等于总和。 |
| 输入 | nums = [1,2,3,4], k = 3 |
| 输出 | false |
| 说明 | 无 |
1 <= k <= len(nums) <= 160 < nums[i] < 10000[1,4] 范围内
本题其实是一道子集问题,可以利用回溯法求解。
首先,我们可以求出nums数组的所有元素之和sum,如果sum % k 不为0的话,说明每一份子集的和不是整数,但是题目说了nums数组中的元素都是整数,因此每一个子集的和也应该是整数,因此如果sum % k 不为0的话,则返回false。
如果sum % k 为0,则我们假设subSum = sum / k,即每一个子集的和为subSum,那么subSum应该大于等于nums数组的最大值,因为nums数组的每一个子集至少有一个元素组成,因此subSum应该大于或等于每一个nums元素,即至少不小于nums数组的最大值。
当面两个条件都符合后,还不能说明nums可以被分为k个和相等的子集,比如nums=[2,2,2,2,3,4,5] ,且k=4。
nums数组的和sum = 20,k=4,因此subSum = 5,而subSum >= max(nums[i]) = 5,因此符合上面两个条件,但是nums数组却无法分为4个等和子集。
因此,我们需要一种算法来判断一个数组是否可以划分k个和相等的子集,此时我们就需要借助回溯算法。
我们可以想象划分子集问题,可以看成向k个桶中放球,每个桶的承重为subSum,而现在nums中存放着重量不一的多个球,如果nums中的球都能放到k个桶中,则可以划分子集成功。
比如nums = [4, 3, 2, 3, 5, 2, 1], k = 4,对应的subSum=5

首先,nums的重量5的球可以独占一个桶,我们可以减少考虑一个桶的处理

接下来,我们需要将球按照降序排序,然后依次放入桶中


由于 4 + 3 > 5,因此球3需要放到下一个桶中
同理处理下面的球
这里我们对nums进行了降序排序,而不是升序排序,因为升序排序可能会产生非常复杂的放置行为,这将不利于我们理解。
上述逻辑对应的算法代码如下
/**
* @param {number[]} nums
* @param {number} k
* @return {boolean}
*/
var canPartitionKSubsets = function(nums, k) {
const sum = nums.sort((a,b) => b - a).reduce((p, c) => p + c)
if(sum % k !== 0) return false
const subSum = sum / k
if(subSum < nums[0]) return false
while(nums[0] === subSum) {
nums.shift()
k--
}
const buckets = new Array(k).fill(0)
return partition(nums, 0, buckets, subSum)
};
function partition(nums, index, buckets, target) {
if(index === nums.length) return true
const selected = nums[index]
for(let i = 0; i < buckets.length; i++) {
if(selected + buckets[i] <= target) {
buckets[i] += selected
if(partition(nums, index+1, buckets, target)) return true
buckets[i] -= selected
}
}
return false
}

可以发现,性能非常差。
有这样一种情况,即我们选择了一个球,但是发现此时每一个桶中的球重量之和都相等,也就是说此时选择的球放到哪一个桶中,最终结果都是相同的,比如球放到桶1中重量超了,则放到其他桶中重量肯定也是超的。
但是根本上面算法逻辑,我们肯定会在选择的球放到桶1超了之后,继续到桶2中尝试,而桶2超了之后,必然放到桶3中尝试,这其实就是一种无意义的试探操作。
因此我们再进入递归流程前,先判断 buckets[i]的重量是否和buckets[i-1]的重量是否相等,若相等的话,则buckets[i-1]试过了,则buckets[i]就不用试了。
最终代码如下
/**
* @param {number[]} nums
* @param {number} k
* @return {boolean}
*/
var canPartitionKSubsets = function(nums, k) {
const sum = nums.sort((a,b) => b - a).reduce((p, c) => p + c)
if(sum % k !== 0) return false
const subSum = sum / k
if(subSum < nums[0]) return false
while(nums[0] === subSum) {
nums.shift()
k--
}
const buckets = new Array(k).fill(0)
return partition(nums, 0, buckets, subSum)
};
function partition(nums, index, buckets, target) {
if(index === nums.length) return true
const selected = nums[index]
for(let i = 0; i < buckets.length; i++) {
if (i > 0 && buckets[i] === buckets[i - 1]) continue // 此步剪枝将大幅提升性能
if(selected + buckets[i] <= target) {
buckets[i] += selected
if(partition(nums, index+1, buckets, target)) return true
buckets[i] -= selected
}
}
return false
}

我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
根据ActiveRecord::Base的文档:==(comparison_object)Returnstrueifcomparison_objectisthesameexactobject,orcomparison_objectisofthesametypeandselfhasanIDanditisequaltocomparison_object.id.Notethatnewrecordsaredifferentfromanyotherrecordbydefinition,unlesstheotherrecordisthereceiveritself.Besides,ifyoufet
ValidPalindromeGivenastring,determineifitisapalindrome,consideringonlyalphanumericcharactersandignoringcases. [#125]Example:"Aman,aplan,acanal:Panama"isapalindrome."raceacar"isnotapalindrome.Haveyouconsiderthatthestringmightbeempty?Thisisagoodquestiontoaskduringaninterview.Forthepurposeofthisproblem
我已经开始了:defsplit_array(array,size)index=0results=[]ifsize>0whileindex如果我在[1,2,3,4,5,6]上运行它,比如split_array([1,2,3,4,5,6],3)它将产生这个数组:[[1,2,3],[4,5,6]]。在Ruby1.8.7中是否已经有可用的东西可以做到这一点? 最佳答案 [1,2,3,4,5,6].each_slice(3).to_a#=>[[1,2,3],[4,5,6]]对于1.8.6:require'enumerator'[1,2,3,4
我试图在每次运行时以随机顺序将一个名称数组拆分为多个数组。我知道如何拆分它们:name_array=["bob","john","rob","nate","nelly","michael"]array=name_array.each_slice(2).to_a=>[["bob","john"],["rob","nate"],["nelly","michael"]]但是,如果我希望它每次都以随机顺序吐出它们怎么办? 最佳答案 在做同样的事情之前,打乱数组。(Array#shuffle)name_array.shuffle.each_s
前言我们习惯用idea编写、调试代码,在LeetCode上刷题时,如果能够在IDEA编写代码,并且做好代码管理,是一件事半功倍的事情。对于后续复习题目,做笔记也会非常便利。本文目的在于介绍LeetCodeEditor的使用,以及配置工具类,最终目录结构如下:note:放置笔记src:放置代码leetcode.editor.cn:插件LeetCodeEditor自动生成utils:自定义的工具包,可用于自动化输入测试用例,定义题目需要的类(结构体)out:运行测试时自动生成LeetCodeEditorGitHub:https://github.com/shuzijun/leetcode-edit
给定一个数组['a','b','c','d','e','f'],我如何获得包含两个的所有子集的列表、三、四元素?我是Ruby的新手(从C#迁移过来),不确定“Ruby之道”是什么。 最佳答案 查看Array#combination然后是这样的:2.upto(4){|n|array.combination(n)} 关于ruby-使用Ruby在数组中查找大小为N的所有子集,我们在StackOverflow上找到一个类似的问题: https://stackoverf
我在使用Ruby代码时遇到了一些“问题”。我想检查数组的所有元素是否相等。例如,假设我有一个只有5的数组:arr=[5,5,5,5,5]我知道我可以做类似的事情arr[0]==arr[1]==arr[2]==arr[3]#==arr[4]==...但这对于巨大的数组来说是不可能的,而且在我看来也不是很像Ruby。我们可以通过做这样的事情来改进它:defall_equal?(arr)foriin0..(arr.size-2)ifarr[i]!=arr[i+1]thenreturnfalseendendtrueend但我也认为这很丑陋。那么是否有任何内置/更好/更短(更像Ruby风格)的方
抱歉,如果重复(我没找到)这只是为了确认Ruby的运算符==始终执行相等比较。IE。a==b将a的值与b的值进行比较,而不是像Java那样比较它们是否指向内存中的同一个对象(对于后者,在Ruby中,您应该使用a.object_id==b.object_id).因此,在Ruby中将字符串值与==进行比较是安全的(而在Java中这样做并不安全)谢谢编辑:问题在于任何Ruby对象的默认==行为,因为它会误导Java-C-C++程序员假设a==b比较引用本身,而不是引用内容。无论如何,你可以检查这段代码,使用字符串one="hello"two="he"two编辑2。所以,在Ruby中,比较a=