8.28 模拟|双指针
lc 三数之和
lc 四数之和
剪枝法优化,提前终止无效循环
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
vector<vector<int>> res;
int n = nums.size(); // 单独用个 int 变量表示 nums.size()
for (int i = 0; i < n - 3; i++) {
long long x = nums[i];
if (i && x == nums[i - 1])
continue;
for (int j = i + 1; j < n - 2; j++) {
long long y = nums[j];
if (j > i+1 && y == nums[j - 1])
continue;
int l = j + 1, r = n - 1;
while (l < r) {
long long sum = x + y + nums[l] + nums[r];
if (sum ==target) {
res.push_back({(int)x, (int)y, nums[l], nums[r]});
for (l++; l < r && nums[l] == nums[l - 1]; l++)
;
for (r--; l < r && nums[r] == nums[r + 1]; r--)
;
} else if (sum > target) {
r--;
} else {
l++;
}
}
}
}
return res;
}
};
lc2328
// 累加子路径数量
ret = (ret + dfs(x, y)) % mod;
class Solution {
typedef long long ll;
const int mod = 1e9 + 7;
public:
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
int m, n;
vector<vector<ll>> memo; // (i,j) 出发的严格递增路径数量
vector<vector<int>> matrix;
int countPaths(vector<vector<int>>& grid) {
matrix = grid;
m = matrix.size();
n = matrix[0].size();
memo.resize(m, vector<ll>(n, 0));
ll cnt = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
// 累加所有格子出发的路径数
cnt = (cnt + dfs(i, j)) % mod;
}
}
return (int)cnt;
}
ll dfs(int i, int j) {
if (memo[i][j]) return memo[i][j];
ll ret = 1;
for (int k = 0; k < 4; k++) {
int x = i + dx[k], y = j + dy[k];
if (x >= 0 && x < m && y >= 0 && y < n
&& matrix[x][y] > matrix[i][j]) {
// 累加子路径数量
ret = (ret + dfs(x, y)) % mod;
}
}
return memo[i][j] = ret;
}
};
lc3459
解决与对角线(这里是类似“之字形”或带转向的对角线相关)遍历、长度计算的问题,核心逻辑围绕深度优先搜索(DFS)结合记忆化( memo 数组)优化,同时用 lambda 实现递归并巧妙处理了 this 捕获与类成员访问,以下从几个关键维度拆解讨论:
1. Lambda 里 this auto&& dfs 的语法作用
- 语法本质:这是 C++14 及以上支持的递归 lambda 写法, this auto&& dfs 是 C++ 对 lambda 递归调用的一种“就地捕获自身”技巧。
- auto&& 让编译器自动推导 dfs 的类型(lambda 类型是编译器匿名生成的,无法手动写), this 确保在类成员函数语境下,能正确关联当前类的作用域(比如访问 memo 、 grid 这些类作用域内的变量)。
- 解决的问题:普通 lambda 无法直接递归(因为定义时“自身名字还不存在”),这种写法让 lambda 内部能通过 dfs 调用自己,实现递归逻辑(比如这里的深度优先遍历)。
2. 结合评论区讨论的延伸点
- 关于 std::function :评论提到“力扣里 std::function 慢,不如 lambda 方便”,原因是 std::function 是类型擦除的封装(内部有虚函数、动态分配等开销),而 lambda 是编译器直接生成的函数对象,调用更高效。
- 代码里用递归 lambda 替代 std::function 包装递归函数,就是在利用 lambda 的轻量优势,尤其刷题场景对时间敏感时,这种写法更优。
- “拐弯后”的逻辑:代码里 can_turn 标记、 k = (k + 1) % 4 (切换方向),对应评论说的“拐弯计算”——遍历到某位置后,尝试切换对角线方向(比如从“右下”拐到“右上”等),继续搜索更长的符合条件的路径,用 maxs 数组做理论长度剪枝(避免无效递归),提升效率。
3. 代码整体逻辑串联
- 功能:遍历二维网格 grid ,针对每个值为 1 的起点,沿 4 种对角线方向( DIRS )做深度优先搜索,允许“拐弯”切换方向,计算最长连续符合条件(值匹配 target 切换)的对角线长度,最终返回全局最大值 ans 。
- 关键设计:
- memo 数组做记忆化:记录 (i,j,k) 位置沿方向 k 不拐弯时的结果,避免重复计算。
- can_turn 控制逻辑:区分“是否允许拐弯”,拐弯时切换方向继续探索,不拐弯时复用 memo 加速。
- 剪枝优化( maxs 数组):通过“理论最大可能长度”预判,跳过不可能超过当前 ans 的递归,减少计算量。
简单说,这段代码用 C++ 递归 lambda 的语法技巧,结合记忆化 + 剪枝,高效解决了带方向切换的对角线遍历长度问题,也呼应了评论区关于 lambda 递归、 std::function 性能的讨论,是刷题场景里“语法技巧 + 算法优化”结合的典型写法。
lc3446.
利用同一对角线差相等提取vec tmp,sort后再填入
class Solution {
public:
vector<vector<int>> sortMatrix(vector<vector<int>>& grid)
{
int n = grid.size();
for (int i = 0; i < n; i++)
{ //提取
vector<int> vec;
for (int k = 0; i + k < n; k++) vec.push_back(grid[i + k][k]);
//排序
sort(vec.begin(), vec.end(),greater<int>());
//填入
for (int k = 0; i + k < n; k++) grid[i + k][k] = vec[k];
}
// 枚举右上角
for (int j = 1; j < n; j++)
{
vector<int> vec;
for (int k = 0; j + k < n; k++) vec.push_back(grid[k][j + k]);
sort(vec.begin(), vec.end());
for (int k = 0; j + k < n; k++) grid[k][j + k] = vec[k];
}
return grid;
}
};