leetcode 473. 火柴拼正方形(DFS,回溯)
题目链接
题意
给定一串数,判断这串数字能不能拼接成为正方形
思路
DFS,但是不能每次从从序列开始往下搜索,因为这样无法做到四个边覆盖不同位置的值,比如输入是(5,5,5,5,4,4,4,4,3,3,3,3)这种情况
以四条边分类讨论,每次加入序列的值,最后判断四条边的结果是否相等
其次注意剪枝:
- 首先将序列逆序排列,尤其遇到(1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,4,4,4....),如果正着搜索那么一定会超时
- 每一轮检查每条边加上序列的值,得到的结果如果大于边长,那么直接剪枝
class Solution {
public:
int avr=-1;
bool dfs(vector<int> nums,int pos,int cnt[4]){
if(pos==-1){
return cnt[0]==cnt[1] && cnt[1]==cnt[2] && cnt[2]==cnt[3] && cnt[3]==avr;
}
//对每一个段的值进行统计
for(int i=0;i<4;i++){//对每一段分别统计
if(cnt[i]+nums[pos]>avr) continue;//剪枝
cnt[i]+=nums[pos];
if(dfs(nums,pos-1,cnt)) return true;
cnt[i]-=nums[pos];
}
return false;
}
bool makesquare(vector<int>& nums) {
int sum=0;
for(int num:nums) sum+=num;
if(sum%4!=0) return false;
if(!nums.size()) return false;//特判一下[]
avr=sum/4;
sum=0;
//排序一下,减少调用次数,从大到小调用,类似于剪枝
sort(nums.begin(),nums.end());
int cnt[4]={0};
return dfs(nums,nums.size()-1,cnt);
}
// bool dfs(vector<int> nums,int sum,int pos,int cnt){ //记录四条边的长度
// if(sum>avr) return false;
// if(sum==avr) {
// cnt++;
// sum=0;
// }
// if(pos==nums.size()){
// if(cnt==4) return true;
// else return false;
// }
// for(int i=pos;i<nums.size();i++){
// sum+=nums[i];
// if(dfs(nums,sum,i+1,cnt)) return true;//只能判断连续的值
// sum-=nums[i];
// }
// return false;
// }
// bool dfs(vector<int> nums,vector<int> tmp,int pos){
// if(tmp.size() && tmp[tmp.size()-1]>avr) return false;
// if(tmp.size()>4) return false;
// if(tmp.size()==4){
// if(tmp[0]==tmp[1] && tmp[1]==tmp[2] && tmp[2]==tmp[3] &&tmp[0]==avr) return true;
// return false;
// }
// for(int i=pos;i<nums.size();i++){//顺序不是连在一起的
// tmp.push_back()
// }
// return false;
// }
// bool dfs(vector<int> nums,int pos,vector<int> cnt(4,0)){//每一部分的和
};