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: trueExplanation: 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