[路飞]_程序员必刷力扣题: 473. 火柴拼正方形

147 阅读1分钟

「这是我参与2022首次更文挑战的第39天,活动详情查看:2022首次更文挑战

473. 火柴拼正方形

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

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

示例 1:

image.png

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

示例 2:

输入: matchsticks = [3,3,3,3,4]
输出: false
解释: 不能用所有火柴拼成一个正方形。

提示:

  • 1 <= matchsticks.length <= 15
  • 1 <= 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)

};

谢谢大家,一起加油