每日一题 -- LeetCode473

104 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情image.png

前言

每日一题,轻松解题

每日一题为刷题系列 每日刷一题LeetCode题,并且对题目进行分析,分享思路。

正文

:火柴拼正方形

难度:中等

题目要求:

你将得到一个整数数组 matchsticks ,其中 matchsticks[i] 是第 i 个火柴棒的长度。你要用 所有的火柴棍 拼成一个正方形。你 不能折断 任何一根火柴棒,但你可以把它们连在一起,而且每根火柴棒必须 使用一次 。

如果你能使这个正方形,则返回 true ,否则返回 false 。

举个例子

输入: matchsticks = [1,1,2,2,2]
输出: true
解释: 能拼成一个边长为2的正方形,每边两根火柴。

image.png

:解题

方法一 :深度优先搜索

假设火柴的长度分别为 [1,1,1,1,2,2,2,2,3,3,3,3],它们的和为 24,因此对应正方形的变成为 6。如下图所示,我们给正方形的每一条边都放上长度为 [1,2,3] 的火柴,这是一种可行的方法。

image.png

因此,对于给定的若干根火柴,我们需要:

  • 将它们分成四组,每一根火柴恰好属于其中的一组;
  • 每一组火柴的长度之和都相同,等于所有火柴长度之和的四分之一。

解题思路:

我们可以使用深度优先搜索枚举出所有的分组情况,并对于每一种情况,判断是否满足上述的两个条件。

我们依次对每一根火柴进行搜索,当搜索到第 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
};

总结

无论做什么分析最重要,其中我们分析了题目,分析了解题思路,其实在分析完解题思路后,代码其实就是很简单的事情了,养成习惯,无论做什么之前,都要进行分析,这样有助于你更快更好的完成这件事。