[Leetcode] Matchsticks to Square 火柴拼方形

Matchsticks to Square

Remember the story of Little Match Girl? By now, you know exactly what
matchsticks the little match girl has, please find out a way you can
make one square by using up all those matchsticks. You should not
break any stick, but you can link them up, and each matchstick must be
used exactly one time.

Your input will be several matchsticks the girl has, represented with
their stick length. Your output will either be true or false, to
represent whether you could make one square using all the matchsticks
the little match girl has.

Example 1: Input: [1,1,2,2,2] Output: true

Explanation: You can form a square with length 2, one side of the
square came two sticks with length 1.

给定一个数组,其中每个数字是火柴长度。求是否能够用且只用一次每一根火柴,通过首尾相连来拼出一个正方形。

深度优先搜索

思路

由于正方形有四条边,该搜索其实要满足四个目标才能算成功,即四条边都用能够用火柴拼出来。想象此时我们有个火柴队列,我们拿出一支火柴,先尝试将它放入第一条边上,如果第一条边放得下,再拿出第二根火柴,尝试继续放在第一条边上,如果此时发现已经放不下了,就试着把它放在第二条边上,以此类推。细心的同学可能会发现,如果第一根火柴在第一条边上都放不进去的话,后面也都不用试了,因为每条边长都一样,一个放不进去的话其他也放不进去。其实不只是第一根火柴,由于较长的火柴较不容易放入边中,所以如果我们先把较长的火柴放完再放较短的火柴,能帮助减少很多分叉的情况。所以这里一个优化的方法就是先将火柴排序,将长的放在前面。

到这里你可能会疑惑,为什么用完所有火柴就意味着四条边都拼完了呢?因为我们规定了边长的目标为总长除以4,而所火柴用完时总长已经确定即为边长的4倍,那么肯定就是有四条边被拼出来了。

代码

class Solution:
    def makesquare(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        perimeter = sum(nums)
        if perimeter == 0 or perimeter % 4 != 0:
            return False
        sides = [perimeter // 4 for i in range(0, 4)]
        nums.sort(reverse=True) # 先试着拼较长的边,有助于减少搜索分叉
        return self.findSolution(nums, sides, 0) # 从第一根开始尝试拼出边
    
    def findSolution(self, nums, sides, pos):
        if pos == len(nums):
            return True
        for index in range(0, 4): # 对于当前这个火柴,尝试拼入上下左右四个边
            if sides[index] >= nums[pos]:
                sides[index] -= nums[pos] # 用当前火柴拼第index个边
                if self.findSolution(nums, sides, pos + 1): # 如果这个火柴被成功使用,就开始尝试拼下一根火柴
                    return True
                sides[index] += nums[pos] # 把当前火柴从第index个边中拿出来,好尝试下一条边
        return False
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值