872 字
4 分钟
算法 : 枚举

§枚举右,维护左#

对于 双变量问题,例如两数之和 ai+aj=ta_i + a_j = t,可以枚举右边的 aja_j,转换成 单变量问题,也就是在 aja_j 左边查找是否有 ai=taja_i = t - a_j ,这可以用哈希表维护。

我把这个技巧叫做 枚举右,维护左。 讲解: 1. 两数之和 - 力扣(LeetCode)

class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> idx; // 创建一个空哈希表
for (int j = 0; ; j++) { // 枚举 j
// 在左边找 nums[i],满足 nums[i]+nums[j]=target
auto it = idx.find(target - nums[j]);
if (it != idx.end()) { // 找到了
return {it->second, j}; // 返回两个数的下标
}
idx[nums[j]] = j; // 保存 nums[j] 和 j
}
}
};

§进阶#

§枚举中间#

对于有三个或者四个变量的问题,枚举中间的变量往往更好算。 为什么?比如问题有三个下标,需要满足 0i<j<k<n0 \le i < j < k < n,对比一下:

  • 枚举 ii,后续计算中还需保证 j<kj < k
  • 枚举 jj,那么 iikk 自动被 jj 隔开,互相独立,后续计算中无需关心 iikk 的位置关系。 所以枚举中间的变量更简单。
class Solution {
public:
int minimumSum(vector<int>& nums) {
int n = nums.size();
vector<int> right(n);
right[n - 1] = nums[n - 1];
for(int i = n - 2; i > 1; i--){
right[i] = min(nums[i], right[i + 1]);
}
int ans = INT_MAX;
int pre = nums[0];
for(int j = 1; j < n - 1; j++){
if(pre < nums[j] && nums[j] > right[j + 1]){
ans = min(ans, pre + nums[j] + right[j + 1]);
}
pre = min(pre, nums[j]);
}
return ans == INT_MAX ? -1 : ans;
}
};

§遍历对角线#

class Solution {
public:
vector<vector<int>> sortMatrix(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();
for(int k = 0; k < m + n; k++){
int min_j = max(n - k, 0);
int max_j = min(m + n - 1 - k, n - 1);
vector<int> a;
for(int j = min_j; j <= max_j; j++){
a.push_back(grid[k + j - n][j]);
}
if(min_j > 0){
ranges::sort(a);
}else{
ranges::sort(a,greater());
}
for(int j = min_j; j <= max_j; j++){
grid[k + j - n][j] = a[j - min_j];
}
}
return grid;
}
};
算法 : 枚举
https://dingfengbo.vercel.app/posts/算法/枚举/
作者
Eureka
发布于
2026-04-25
许可协议
CC BY-NC-SA 4.0