「这是我参与2022首次更文挑战的第39天,活动详情查看:2022首次更文挑战」
473. 火柴拼正方形
你将得到一个整数数组 matchsticks ,其中 matchsticks[i] 是第 i 个火柴棒的长度。你要用 所有的火柴棍 拼成一个正方形。你 不能折断 任何一根火柴棒,但你可以把它们连在一起,而且每根火柴棒必须 使用一次 。
如果你能使这个正方形,则返回 true ,否则返回 false 。
示例 1:
输入: matchsticks = [1,1,2,2,2]
输出: true
解释: 能拼成一个边长为2的正方形,每边两根火柴。
示例 2:
输入: matchsticks = [3,3,3,3,4]
输出: false
解释: 不能用所有火柴拼成一个正方形。
提示:
1 <= matchsticks.length <= 151 <= matchsticks[i] <= 108
搜索回溯
思路 这道题目是让我们吧数组中的所有火柴用完,拼成一个正方形,其实就是让我们吧数组中的元素进行分组,分成大小相等的四组
这里我们用搜索回溯的方式来解决
首先判断边界条件
如果需要拼成正方形,那么数组中元素的中和total对4取余一定要为0 否则返回false
每个边的变长side = total/4
接下来声明一个length为4的数组,每个元素从0开始,用来记录每个边的边长
声明一个check函数参数为index,代表matchsticks的第index个元素,尝试放入四个边中的任何一个
如果满足sideItem(正方形当前的边) + item(matchsticks[index]元素) <= side(正方形的边长)就将这个元素加入边长,并且处理matchsticks下一个元素index+1,如果这种情况可以满足条件直接返回true,否则进行状态回溯,sideArr[i] -= item
不断循环下去,那么每个元素都可能出现在每条边上,包含所有的情况
为了减少搜索的次数,需要先将matchsticks进行降序排序
最后返回check的值即可
var makesquare = function (matchsticks) {
// 总长
var total = matchsticks.reduce((total, item) => total += item)
// 余数不为0则直接false
if (total % 4) return false
// 变长side
var side = total / 4
// 查找四个边
var sideArr = [0, 0, 0, 0]
matchsticks.sort((a, b) => b - a)
// 排序以减少回溯的次数
// 参数:index 代表matchsticks的第index个元素,
var check = (index) => {
// 只要元素能全部用完则满足条件return true,否则返回false
if(index===matchsticks.length) return true
var item = matchsticks[index]
for (var i = 0; i < sideArr.length; i++) {
var sideItem = sideArr[i]
// 如果不超出side,那么可以放入此处
if (sideItem + item <= side) {
sideArr[i] += item
// 放入后,开始处理下一个元素index+1,如果这个方案可以返回true直接返回否则回溯状态将index往后面的桶中尝试
if(check(index+1)){
return true
}
// 回溯状态
sideArr[i] -= item
}
}
// 四个都放不进去,则返回false
return false
}
return check(0)
};
谢谢大家,一起加油