解题思路:
分析:要想组成正方形,需要四条边都等于总和的1/4,因此需要将火柴分成四组,使得每一个火柴都属于其中的一组。因此可以考虑回溯 ( 想到了),将四条边想象成四个桶( 没想到 ),如果将当前的边加入到一个桶中没有违背条件,则在此基础上继续回溯。如果回溯到最后也无法满足,或者如果某个边加入后就超出理应的边长了,就剪枝。
优化的策略:
如果火柴杆的总和不是4的倍数,火柴杆的最大值 > 边长 ,直接返回 false 即可。
将火柴杆从大到小排序,优先选用大的边可以令不成功的情况更快的返回。
class Solution
{
public:
static bool compare(int x, int y)
{
return x > y;
}
bool DFS(vector<int>& bd,vector<int>& mat, int border,int index)
{
if (*max_element(bd.begin(), bd.end()) > border) //找到四个桶里面的最大值
return false; //如果超过边长回溯
if (index == mat.size()) //走到最后判断是否满足条件
{
if (bd[0] == bd[1] && bd[1] == bd[2] && bd[2] == bd[3])
{
return true;
}
else
return false;
}
for (int i = 0; i < 4; ++i)
{
if(bd[i] + mat[index] > border)
continue;
bd[i] += mat[index];
if (DFS(bd, mat, border, index + 1))
return true;
bd[i] -= mat[index];
}
return false;
}
bool makesquare(vector<int>& matchsticks)
{
int sum = 0;
for (const auto& e : matchsticks)
{
sum += e;
}
if (sum % 4 != 0) // 不是4的倍数,不能组成正方形
return false;
int border = sum / 4;
sort(matchsticks.begin(), matchsticks.end(),compare);//降序排列
if (matchsticks[matchsticks.size() - 1] > border) //元素值> 边长
return false;
vector<int> bd(4, 0);//四个桶
return DFS(bd, matchsticks, border, 0);
}
};