473 火柴拼正方形(dfs剪枝)

这篇博客介绍了如何运用深度优先搜索(DFS)策略解决一个经典的算法问题——利用给定长度的火柴棒拼成正方形。文章详细分析了剪枝技巧,包括按火柴长度排序、避免重复搜索等,并给出了Python实现代码,通过排序、剪枝等方法判断能否用所有火柴构成正方形。
摘要由CSDN通过智能技术生成

1. 问题描述:

还记得童话《卖火柴的小女孩》吗?现在,你知道小女孩有多少根火柴,请找出一种能使用所有火柴拼成一个正方形的方法。不能折断火柴,可以把火柴连接起来,并且每根火柴都要用到。输入为小女孩拥有火柴的数目,每根火柴用其长度表示。输出即为是否能用所有的火柴拼成正方形。

示例 1:

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

示例 2:

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

注意:

给定的火柴长度和在 0 到 10 ^ 9之间。
火柴数组的长度不超过15。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/matchsticks-to-square

2. 思路分析:

这道题目属于dfs剪枝的经典问题,涉及到比较多剪枝的细节,其实可以记熟里面的技巧与方法这样在遇到类似的题目可以使用上相同的技巧。对于这道题目我们可以分为以下几种情况进行剪枝:

  • 先对火柴的长度由大到小进行排序,在搜索的时候可以由长度较长的火柴开始搜索,长度较长的火柴对应的分支数目肯定是比较少的,这样在一开始的时候避免很多分支的搜索
  • 我们可以每条边长每条边长拼凑,这样当我们拼成了三条边长的时候剩下那一条边就不用拼了,因为总和是固定的,前三条边已经拼好了那么最后一条边也一定可以拼出来。并且每一条边长我们可以按照火柴编号递增搜索,这样可以避免因为火柴顺序不一样但是总和一样的重复搜索,例如1,3,2与1,2,3其实是一样的,只是顺序不一样而已
  • 若某一根火柴拼凑失败了,那么又可以分为以下三种情况:
  1. 跳过长度相邻位置相同长度的火柴
  2. 当前是第一根火柴
  3. 当前是最后一根火柴

3. 代码如下:

from typing import List


class Solution:
    # start表示第几根火柴, cur表示当前拼成的火柴长度, l表示每根火柴需要拼成的长度, count表示拼成了多少条火柴, sta为标记列表标记哪些火柴是已经使用过了, nums是火柴长度
    def dfs(self, start: int, cur: int, l: int, count: int, sta: List[int], nums: List[int]):
        # 当前已经拼好了三根火柴
        if count == 3: return True
        # 拼好了当前的这条边长, 接下来拼下一个边长
        if cur == l: return self.dfs(0, 0, l, count + 1, sta, nums)
        i = start
        while i < len(sta):
            if sta[i] == 1:
                i += 1
                continue
            if cur + nums[i] <= l:
                sta[i] = 1
                if self.dfs(i + 1, cur + nums[i], l, count, sta, nums):return True
                # 回溯
                sta[i] = 0
            # 当前第一根或者最后一根不满足条件的时候直接减掉
            if cur == 0 or cur + nums[i] == l: return False
            i += 1
            # 跳过当前的相邻的相同长度的火柴
            while i < len(sta) and nums[i] == nums[i - 1]: i += 1
        return False

    def makesquare(self, nums: List[int]) -> bool:
        if not nums: return False
        # 从大到小排序
        nums.sort(reverse=True)
        sta = [0] * len(nums)
        s = 0
        for x in nums:
            s += x
        if s % 4: return False
        return self.dfs(0, 0, s // 4, 0, sta, nums)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值