++回溯枚举情况 出口处check++
lc1601
不选 选
++DFS枚举所有请求的选与不选,统计++满足所有节点进出人数平衡的请求组合,返回最大请求数量
class Solution {
public:
int maximumRequests(int n, vector<vector<int>>& requests) {
int ans = 0;
int l = requests.size();
vector<int> path(n,0);
//i表示当前遍历的元素,cnt是当前满足的请求
function<void(int,int)> dfs = [&](int i,int cnt)
{
if(i==l)
{
for(int k = 0;k < n;++k)
++if(path[k] != 0) return; //check
ans = max(ans,cnt);++
return;
}
//不选
dfs(i+1,cnt);
//选
path[requests[i][0]]--;//出去
path[requests[i][1]]++;//进去
dfs(i+1,cnt+1);
//恢复现场
path[requests[i][0]]++;//出去
path[requests[i][1]]--;//进去
};
dfs(0,0);
return ans;
}
};
lc2044
之前是用for迭代写的
刷题单发现还可以回溯写(`・ω・´)
先计算数组所有元素的总按位或值
再通过DFS枚举子集,统计按位或等于该最大值的子集数量
trick:
if (subset_or == total_or)
ans += 1 << (n - i);
当子集按位或等于最大值时,剩++余 n-i 个元素选或不选都不影响结果++,直接用 2^(n-i) 快速统计这类子集的数量。
class Solution {
/*
输入:nums = [3,2,1,5]
输出:6
解释:子集按位或可能的最大值是 7 。有 6 个子集按位或可以得到 7 :
-
3,5
-
3,1,5
-
3,2,5
-
3,2,1,5
-
2,5
-
2,1,5
*/
public:
int countMaxOrSubsets(vector<int>& nums) {
int ++total_or = reduce(nums.begin(), nums.end(), 0, bit_or());++
int n = nums.size();
int ans = 0;
auto dfs = [&](this auto&& dfs, int i, int subset_or) {
++if (subset_or == total_or) {
ans += 1 << (n - i);++
return; //cut
}
if (i == n)
return;
dfs(i + 1, subset_or); // 不选 nums[i]
dfs(i + 1, ++subset_or | nums[i]); // 选++
};
dfs(0, 0);
return ans;
}
};
lc1255
预处理: 统计字母库存后
DFS枚举单词选或不选的所有组合
验证字母是否充足并计算得分,最终返回最大得分

class Solution {
public:
int maxScoreWords(vector<string> &words, vector<char> &letters, vector<int> &score) {
int ans = 0, left[26]{};
for (char c : letters)
++left[c - 'a'];
function<void(int, int)> dfs = [&](int i, int total)
{
if (i < 0) { // 到头了
++ans = max(ans, total);++
return;
}
// 不选 words[i]
dfs(i - 1, total);
// 选 words[i]
bool ok = true;
for (char c : words[i]) {
++if (left[c - 'a']-- == 0)++
++ok = false; // 剩余字母不足++
++total += score[c - 'a']; // 累加得分++
}
if (ok)
++dfs(i - 1, total);++
// 恢复现场
++for (char c : words[i])++
++++left[c - 'a'];++
};
dfs(words.size() - 1, 0);
return ans;
}
};
lc1095
山脉数组 两次二分
先二分查找山脉数组的峰值位置
再在峰值左侧升序区间和右侧降序区间分别二分查找目标值
优先返回左侧找到的索引

/**
* // This is the MountainArray's API interface.
* // You should not implement it, or speculate about its implementation
* class MountainArray {
* public:
* int get(int index);
* int length();
* };
*/
class Solution
{
public:
int binary_search(MountainArray & mountainArr, int target, int L, int R, int sign)
{
target = sign * target;
while (L <= R)
{
int mid = (L + R) >> 1;
int cur = sign * mountainArr.get(mid);
if (cur == target)
return mid;
else if (cur < target)
L = mid + 1;
else
R = mid - 1;
}
return -1;
}
int findInMountainArray(int target, MountainArray &mountainArr)
{
int L = 0, R = mountainArr.length() - 1;
while (L <= R)
{
int mid = (L + R) >> 1;
if (mountainArr.get(mid) < mountainArr.get(mid + 1))
L = mid + 1;
else
R = mid-1;
}
int peak_idx = L;
int idx = binary_search(mountainArr, target, 0, peak_idx, 1 );
if (idx != -1)
return idx;
return binary_search(mountainArr, target, peak_idx + 1, mountainArr.length() - 1, -1 );
}
};