LeetCode:473 火柴拼正方形 dfs+剪枝

白昼怎懂夜的黑 提交于 2020-03-03 16:33:29

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

输入为小女孩拥有火柴的数目,每根火柴用其长度表示。输出即为是否能用所有的火柴拼成正方形。

示例 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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

其实就是有四个容量为len的桶,要把它们装满,并且用上全部的火柴,那么对于每个火柴都有4种选择,暴力枚举所有的选择即可,复杂度为O(4n),但是这么做OJ上超时,需要加入两个剪枝:

  • 如果搜索的过程中,遇到某个桶的容量超过len,那么这种情况以及其之和的衍生情况都不成立,直接返回false
  • 在容量足够的情况下,优先考虑最大的火柴,也就是对数组降序排序,这样有助于更快发现最优解

比如最后一个火柴长度超出len,但是按照顺序搜索,直到最后我们才发现有不行,如果排序之后,第一次搜我们就会发现不满足,大大节省时间开销

代码

class Solution {
public:
    int len=0;
    bool dfs(int x, vector<int>& nums, int a, int b, int c, int d)
    {
        if(x==nums.size())
            if(a==len && b==len && c==len && d==len) return true;
            else return false;
        if(a>len || b>len || c>len || d>len) return false;
        return (dfs(x+1, nums, a+nums[x], b, c, d) 
             || dfs(x+1, nums, a, b+nums[x], c, d)
             || dfs(x+1, nums, a, b, c+nums[x], d)
             || dfs(x+1, nums, a, b, c, d+nums[x]));
    }
    bool makesquare(vector<int>& nums)
    {
        if(nums.size()==0) return false;
        for(int i=0; i<nums.size(); i++) len+=nums[i];
        if(len%4 != 0) return false;
        len /= 4;
        sort(nums.begin(), nums.end(), greater<int>());
        return dfs(0, nums, 0, 0, 0, 0);
    }
};
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!