1. 题目来源
链接:473. 火柴拼正方形
拔高、证明:
2. 题目解析
水一篇。和之前的一个问题一模一样,在此不再赘述,写出来方便搜索。
- 时间复杂度:此类 dfs 和剪枝,不必进行分析
- 空间复杂度:此类 dfs 和剪枝,不必进行分析
class Solution {
public:
bool makesquare(vector<int>& matchsticks) {
return canPartitionKSubsets(matchsticks, 4);
}
bool canPartitionKSubsets(vector<int>& nums, int k) {
int n = nums.size();
int sum = 0;
for (int x : nums) sum += x;
int x = sum / k;
if (x * k != sum) return false;
sort(nums.begin(), nums.end(), greater<int>()); // 剪枝1:从大到小进行搜索
vector<bool> st(n, false);
function<bool(int, int, int)> dfs = [&](int u, int cur, int cnt) {
if (cnt == k) return true;
if (cur == x) return dfs(0, 0, cnt + 1);
for (int i = u; i < n; i ++ ) { // 从大到小搜索
if (st[i]) continue;
if (cur + nums[i] > x) continue;
// 尝试搜索当前位置
st[i] = true;
if (dfs(i + 1, cur + nums[i], cnt)) return true;
// 搜索当前位置失败的话
st[i] = false;
while (i + 1 < n && nums[i] == nums[i + 1]) i ++ ; // 剪枝2:搜索的相同元素失败
if (!cur || cur + nums[i] == x) return false; // 剪枝3、4:如果搜索的第一个、最后一个失败
}
return false;
};
return dfs(0, 0, 0);
}
};