leetcode 473. 火柴拼正方形(DFS超级好题!)

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

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

示例 1:

输入: [1,1,2,2,2]
输出: true

解释: 能拼成一个边长为2的正方形,每边两根火柴。
示例 2:

输入: [3,3,3,3,4]
输出: false

解释: 不能用所有火柴拼成一个正方形。
注意:

给定的火柴长度和在 0 到 10^9之间。
火柴数组的长度不超过15。

题目分析:

存在很明显的剪枝

1、sum不是 4的倍数,直接return false

2、先对nums排序 先遍历nums值大的,再遍历小的,这样能够有效 减少递归层数(贪心的思想

3.每次放置时,每条边上不可放置超过总和1/4长度的火柴棍,所以 我们每次把木棍放到budgt[i]中

class Solution {
public:
    bool makesquare(vector<int>& nums) {
        if(nums.size() < 4)
            return false;
        
        int sum =0;
        for(int i =0;i<nums.size();++i)
            sum += nums[i];
        
        if(sum%4 !=0)  // 剪枝一
            return false;
        int bucket[4];// 四条边已经有的长度

        sort(nums.rbegin(),nums.rend()); //剪枝2

        for(int i=0;i<4;i++)
            bucket[i] = 0;
        return DFS(0,nums,sum/4,bucket);
        
    }
    
    bool DFS(int i,vector<int>& nums, int target,int bucket[])
    {//参数依次是 i是 物品的index, nums 是木棍的长度数组 ,target 是每个边长,
        if(i==nums.size()){ //所有的木条都选完了 判断是否满足条件
            return bucket[0]==target&&bucket[1]==target&&bucket[2]==target&&bucket[3]==target;
        }
        for(int j=0;j<4;j++){ //对于物品 nums[i] 都可以尝试放到bucket[j]中 
            if(bucket[j]+nums[i]>target) continue; //可以选 则加入
            bucket[j] += nums[i];
            if(DFS(i+1,nums,target,bucket))// 如果这条边放进去可以 走到上面的那步 
                return true;
            bucket[j] -= nums[i];//如果说这条边 不行的话 得回溯!!!
        }
        return false;
    }
};
发布了124 篇原创文章 · 获赞 47 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/ludan_xia/article/details/104933404