一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情。
前言
每日一题,轻松解题
每日一题为刷题系列 每日刷一题LeetCode题,并且对题目进行分析,分享思路。
正文
:火柴拼正方形
难度:中等
题目要求:
你将得到一个整数数组 matchsticks ,其中 matchsticks[i] 是第 i 个火柴棒的长度。你要用 所有的火柴棍 拼成一个正方形。你 不能折断 任何一根火柴棒,但你可以把它们连在一起,而且每根火柴棒必须 使用一次 。
如果你能使这个正方形,则返回 true ,否则返回 false 。
举个例子
输入: matchsticks = [1,1,2,2,2]
输出: true
解释: 能拼成一个边长为2的正方形,每边两根火柴。
:解题
方法一 :深度优先搜索
假设火柴的长度分别为 [1,1,1,1,2,2,2,2,3,3,3,3],它们的和为 24,因此对应正方形的变成为 6。如下图所示,我们给正方形的每一条边都放上长度为 [1,2,3] 的火柴,这是一种可行的方法。
因此,对于给定的若干根火柴,我们需要:
- 将它们分成四组,每一根火柴恰好属于其中的一组;
- 每一组火柴的长度之和都相同,等于所有火柴长度之和的四分之一。
解题思路:
我们可以使用深度优先搜索枚举出所有的分组情况,并对于每一种情况,判断是否满足上述的两个条件。
我们依次对每一根火柴进行搜索,当搜索到第 i 根火柴时,我们可以把它放到四组中的任意一种。对于每一种放置方法,我们继续对第 i + 1 根火柴进行递归搜索。当我们搜索完全部的 N 根火柴后,再判断每一组火柴的长度之和是否都相同。
编辑代码:
var makesquare = function (nums) {
function backtrack(i, nums, edge, bucket) {
if (i >= nums.length) {//递归结束条件
return true;
}
for (let j = 0; j < 4; j++) {//循环4个桶
if (bucket[j] + nums[i] > edge) {//这个桶装不下 继续找下一个桶
continue;
}
bucket[j] += nums[i];//将当前元素加入桶中
if (backtrack(i + 1, nums, edge, bucket)) {//索引i加1 继续递归下一个nums中的元素
return true;//下一个元素能放进桶中
}
bucket[j] -= nums[i];//回溯状态
}
return false;//循环结束都没放进合适的桶 那不能构成正方形
}
if (nums.length < 4) {//nums长度小于4 直接不能构成正方形
return false;
}
let sum = 0;
for (let i = 0; i < nums.length; i++) {
sum += nums[i];
}
if (sum % 4) {//nums的和不能整除4 不能构成正方行
return false;
}
nums.sort((a, b) => b - a);//排序nums
let bucket = Array(4).fill(0);//准备4个桶
return backtrack(0, nums, sum / 4, bucket);//传入nums元素的索引i,nums,一个边长,和桶bucket
};
总结
无论做什么分析最重要,其中我们分析了题目,分析了解题思路,其实在分析完解题思路后,代码其实就是很简单的事情了,养成习惯,无论做什么之前,都要进行分析,这样有助于你更快更好的完成这件事。