[LeetCode解题报告] 473. 火柴拼正方形

一、 题目

1. 题目描述

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

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

 

示例 1:

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

示例 2:

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

 

提示:

  • 1 <= matchsticks.length <= 15
  • 1 <= matchsticks[i] <= 108
Related Topics
  • 位运算
  • 数组
  • 动态规划
  • 回溯
  • 状态压缩

  • 👍 358
  • 👎 0

2. 原题链接

链接: 473. 火柴拼正方形

二、 解题报告

1. 思路分析

这题是20220601儿童节每日一题。
求出总边长除4就是每条边长side,然后设置4个盒子,往里扔火柴就行了。
直接DFS回溯枚举,然后TLE了,想了一下 n=15 ,复杂度O(4n)= 2^30 是得TLE。
1) 所以进行了一个简单剪枝,放每个盒子的时候,如果这个盒子长度大于side就可以剪掉;那么可以先倒序排序,让长火柴先放,这样可以更快进入剪枝。3248ms过了,
2)后来我又剪了一下:先枚举用所有15根火柴能拼出来的所有长度O(2^n),用set记下来,n=15的时候是3.2w多次,就还好。然后放每根火柴的时候,如果这个盒子剩余能放的长度不在set里,说明用这15根火柴并不能拼出要求的长度,这个方案一定失败,可以剪掉。1124ms。
3) 追加:后来又剪了一下,把2剪枝去掉了,毕竟2^n,每个数尝试放盒子的时候检查是否前边有一样长度的盒子,如果有就不用放了,因为之前已经尝试过。
在这里插入图片描述

2. 复杂度分析

最坏时间复杂度O(4^n)

3. 代码实现

递归回溯枚举

class Solution:
    def makesquare(self, matchsticks: List[int]) -> bool:
        n = len(matchsticks)
        if n < 4:
            return False
        s = sum(matchsticks)
        side = s // 4
        if side * 4 != s:
            return False
        matchsticks.sort(reverse=True)
        res = [0] * 4
        # 枚举每个数字是否出现能组合成什么值,2^n;这个组合值用于下边dfs的剪枝:
        # 如果放火柴之后,本边剩余长度不能用火柴组合起来,那直接剪掉
        # 本来我就是试试,没想到剪成功了!
        # cmb = set()
        # def dfs_sum(i,s):
        #     if i == n:
        #         cmb.add(s)
        #         return 
        #     dfs_sum(i+1,s)
        #     dfs_sum(i+1,s+matchsticks[i])
        # dfs_sum(0,0)
        # print(cmb)
        def dfs(i):
            if i == n:
                return True
                # return all(res[j]==side for j in range(4))
            
            for j in range(4):
                # if  res[j]+matchsticks[i]>  side or side - res[j]-matchsticks[i] not in cmb :
                
                if  res[j]+matchsticks[i]>  side :                    
                    continue                
                if j > 0 and res[j] == res[j-1]:
                    continue
                if j > 1 and res[j] == res[j-2]:
                    continue
                if j > 3 and res[j] == res[j-3]:
                    continue
                res[j] += matchsticks[i]               
                if dfs(i+1):
                    return True
                res[j] -= matchsticks[i]
            return False

        return dfs(0)

三、 本题小结

  1. 枚举型递归还是要算一下复杂度,不剪枝基本难过

链接: 698. 划分为k个相等的子集

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值