力扣每月题解汇总-2026年04月
目录
2026-04-01力扣每日一题2751-机器人碰撞2026-04-02力扣每日一题3418-机器人可以获得的最大金币数2026-04-03力扣每日一题3661-可以被机器人摧毁的最大墙壁数目2026-04-04力扣每日一题2087-网格图中机器人回家的最小代价2026-04-05力扣每日一题657-机器人能否返回原点2026-04-06力扣每日一题874-模拟行走机器人2026-04-07力扣每日一题2069-模拟行走机器人II2026-04-08力扣每日一题3653-区间乘法查询后的异或I2026-04-09力扣每日一题3655-区间乘法查询后的异或II2026-04-10力扣每日一题3740-三个相等元素之间的最小距离I2026-04-11力扣每日一题3741-三个相等元素之间的最小距离II2026-04-12力扣每日一题1320-二指输入的的最小距离2026-04-13力扣每日一题1848-到目标元素的最小距离2026-04-14力扣每日一题2463-最小移动总距离2026-04-15力扣每日一题2515-到目标字符串的最短距离2026-04-16力扣每日一题2388-距离最小相等元素查询2026-04-17力扣每日一题3761-镜像对之间最小绝对距离2026-04-18力扣每日一题3783-整数的镜像距离2026-04-19力扣每日一题1855-下标对中的最大距离2026-04-20力扣每日一题2078-两栋颜色不同且距离最远的房子2026-04-21力扣每日一题1722-执行交换操作后的最小汉明距离2026-04-22力扣每日一题2452-距离字典两次编辑以内的单词2026-04-23力扣每日一题2615-等值距离和2026-04-24力扣每日一题2833-距离原点最远的点2026-04-25力扣每日一题3464-正方形上的点之间的最大距离2026-04-26力扣每日一题1559-二维网格图中探测环2026-04-27力扣每日一题1391-检查网格中是否存在有效路径2026-04-28力扣每日一题2033-获取单值网格的最小操作数2026-04-29力扣每日一题3225-网格图操作后的最大分数2026-04-30力扣每日一题3742-网格中得分最大的路径
力扣每日一题2751-机器人碰撞
日期:2026-04-01
题意
过定数组 position 与 healths 以及一个字符串 directions, 分别表示多个机器人的 初始位置 健康度 与 方向. 所有机器人同时启动向着各自方向以相同的速度移动. 若健康度不同的两机器人相撞, 较低健康度的机器人被移除, 较高健康度的机器人保持方向运动但健康度减一; 若两健康度相同的机器人相撞则双双移除.
求足够长时间后, 剩余机器人的健康度.
思路
所有机器人速度相同, 即不会发生追尾. 那只需要从左往右或反过来模拟就好了. 以从左向右为例, 若当前向右则加入到栈中维护; 若当前机器人向左且其左无机器人则永不移除, 若其左存在机器人则进行碰撞模拟即可.
实现
class Solution {
public:
vector<int> survivedRobotsHealths(vector<int>& positions, vector<int>& healths, string directions) {
int n = positions.size();
vector<int> p(n);
ranges::iota(p, 0);
ranges::sort(p, [&](int& x, int& y) {
return positions[x] < positions[y];
});
vector<int> stk;
for (auto& x : p) {
if (directions[x] == 'L') {
if (stk.empty()) continue;
else {
while (!stk.empty() && healths[x]) {
int y = stk.back();
if (healths[x] > healths[y]) {
stk.pop_back();
healths[y] = 0;
healths[x]--;
} else if (healths[x] == healths[y]) {
stk.pop_back();
healths[x] = healths[y] = 0;
} else {
if (--healths[y] == 0) stk.pop_back();
healths[x] = 0;
}
}
}
} else {
stk.push_back(x);
}
}
vector<int> ans;
for (int x : healths)
if (x) ans.push_back(x);
return ans;
}
};
力扣每日一题3418-机器人可以获得的最大金币数
日期:2026-04-02
题意
给定矩阵 coins 表示网格各个格子的初始硬币数. 初始机器人位于左上角, 每次操作可向右或向下移动到相邻格. 若所达格子含硬币数大于等于零, 机器人可获得所有该格硬币; 若所达格子含硬币数小于零, 表示该格存在强盗, 机器人将损失该格数值的绝对值个硬币. 初始所含硬币为 0, 硬币数可为负, 目标为右下角, 同时机器人总共可以感化 2 个强盗使损失为 0,问机器人可得最大硬币数.
思路
不考虑感化的前提下显然就是个裸的二维 dp, 应该是都比较熟悉就不过多赘述了. 再考虑感化强盗, 那也就是多加一个维度用以记录当前已用感化次数即可.
实现
class Solution {
static constexpr int inf = 1e9;
public:
int maximumAmount(vector<vector<int>>& coins) {
int n = coins.size(), m = coins.back().size();
vector f(3, vector (n + 1, vector<int> (m + 1, -inf)));
f[0][0][0] = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
for (int k = 0; k < 3; k++) {
int& x = f[k][i][j];
int& c = coins[i][j];
f[k][i + 1][j] = max(f[k][i + 1][j], x + c);
f[k][i][j + 1] = max(f[k][i][j + 1], x + c);
if (c < 0 && k < 2) {
f[k + 1][i + 1][j] = max(f[k + 1][i + 1][j], x);
f[k + 1][i][j + 1] = max(f[k + 1][i][j + 1], x);
}
}
}
}
int ans = -inf;
for (int i = 0; i < 3; i++) ans = max({ans, f[i][n - 1][m], f[i][n][m - 1]});
return ans;
}
};
力扣每日一题3661-可以被机器人摧毁的最大墙壁数目
日期:2026-04-03
题意
给定数组 robots distance walls 分别表示一条线上的一堆机器人的位置、射击距离以及一堆墙的位置. 每个机器人可以选择向左或向右发射一枚子弹, 子弹会摧毁到距离上限的路上所有的墙但无法穿透别的机器人. 求所有机器人最多摧毁多少墙.
注: 墙和机器人可能在同一位置, 该墙仅能由该机器人摧毁.
思路
子弹无法穿透其它机器人, 那就很好做了. 首先将机器人按顺序排列, 从左往右或反过来总之按顺序进行处理即可, 不过需要提前想好各自的边界, 我这里就是没完全想好所以写得有点屎. 以我的实现为例: 若当前机器人向左且前一机器人也向左, 则至多射到距离上限或上一机器人后; 若向左且前一向右, 至多到距离上限或上一机器人所射上限; 若向右, 至多至上限或下一机器人前.
实现
class Solution {
public:
int maxWalls(vector<int>& robots, vector<int>& distance, vector<int>& walls) {
int n = robots.size();
robots.push_back(INT_MAX - 1);
distance.push_back(0);
vector<int> p(n + 1), f(n), g(n);
ranges::sort(walls);
ranges::iota(p, 0);
ranges::sort(p, [&](const int& x, const int& y) {
return robots[x] < robots[y];
});
for (int x = 0; x < n; x++) {
int i = p[x];
int l = robots[i] - distance[i];
if (x) l = max(l, robots[p[x - 1]] + 1);
int ll = ranges::lower_bound(walls, l) - walls.begin();
int lr = ranges::upper_bound(walls, robots[i]) - walls.begin() - 1;
lr = max(lr, ll - 1);
if (x) {
int t = ranges::lower_bound(walls, max(robots[p[x - 1]] + distance[p[x - 1]] + 1, l)) - walls.begin();
f[x] = max(lr - ll + 1 + f[x - 1], lr - t + 1 + g[x - 1]);
} else {
f[x] = lr - ll + 1;
}
int r = min(robots[i] + distance[i], robots[p[x + 1]] - 1);
int rl = ranges::lower_bound(walls, robots[i]) - walls.begin();
int rr = ranges::upper_bound(walls, r) - walls.begin() - 1;
rr = max(rr, rl - 1);
if (x) g[x] = max(f[x - 1], g[x - 1]) + rr - rl + 1;
else g[x] = rr - rl + 1;
}
return max(f.back(), g.back());
}
};
力扣每日一题2087-网格图中机器人回家的最小代价
日期:2026-04-04
题意
给定网格与机器人的初始位置及目标位置, 每次可往上下左右其一方向移动一格, 上下移动到第 i 行的代价为 rowCosts[i], 左右移动到第 i 列的代价为 colCosts[i]. 求从初始位置到目标位置所需的最小代价.
思路
注意到代价均为非负数, 那显然直接前往必然优于绕道. 求所有途径的行列代价和即可, 但需注意起始格应不参与计算.
实现
class Solution {
public:
int minCost(vector<int>& startPos, vector<int>& homePos, vector<int>& rowCosts, vector<int>& colCosts) {
int sx = startPos[0], sy = startPos[1];
int ex = homePos[0], ey = homePos[1];
int ans = - rowCosts[sx] - colCosts[sy];
for (int i = min(sx, ex); i <= max(sx, ex); i++) ans += rowCosts[i];
for (int i = min(sy, ey); i <= max(sy, ey); i++) ans += colCosts[i];
return ans;
}
};
力扣每日一题657-机器人能否返回原点
日期:2026-04-05
题意
给定机器人的行动轨迹, 判断其最终是否会回到原地.
思路
最终回到原地, 换言而之就是往相反方向移动的距离相等, 各个方向的位移为 0.
实现
class Solution {
public:
bool judgeCircle(string moves) {
int x = 0, y = 0;
for (auto& ch : moves) {
if (ch == 'U') y++;
else if (ch == 'D') y--;
else if (ch == 'L') x++;
else x--;
}
return x == 0 && y == 0;
}
};
力扣每日一题874-模拟行走机器人
日期:2026-04-06
题意
给定数组 obstacles 表示障碍物位置; 给定数组 commands 表示机器人的行动指令, 其中若 commands[i] == -2 表示机器人向左转 90°, 若 commands[i] == -1 表示机器人向右转 90°, 若 commands[i] > 0 表示朝当前方向移动对应距离. 机器人初始位于坐标原点, 面朝北, 无法跨过障碍物只会停在障碍物前. 求移动过程中机器人离起点的最大欧式距离的平方.
思路
并无什么特别的, 开个哈希记录障碍位置, 然后进行一个模拟就好.
实现
class Solution {
static constexpr int MX = 3e4 + 10;
static constexpr array<int, 2> nxt[] = {
{0, 1}, {1, 0}, {0, -1}, {-1, 0}
};
public:
int robotSim(vector<int>& commands, vector<vector<int>>& obstacles) {
unordered_set<int> ob;
for (auto& o : obstacles) {
int x = o[0], y = o[1];
ob.insert(x * MX + y);
}
int x = 0, y = 0, to = 0;
int ans = 0;
for (auto op : commands) {
if (op == -2) to = (to - 1 + 4) % 4;
else if (op == -1) to = (to + 1) % 4;
else {
auto [tx, ty] = nxt[to];
for (int i = 0; i < op; i++) {
if (ob.count((x + tx) * MX + y + ty)) break;
x += tx;
y += ty;
}
ans = max(ans, x * x + y * y);
}
}
return ans;
}
};
力扣每日一题2069-模拟行走机器人II
日期:2026-04-07
题意
给定 width * height 的网格图, 初始面朝东. 有多次询问, 可能使向面朝方向移动指定步数; 可能查询当前方向; 可能查询当前位置. 若下一步到达的格子会超出边界, 则会逆时针 90° 旋转后再继续移动.
思路
可能先想到按步数模拟即可, 但注意到当前数据范围可能不太支持如此简单实现. 手玩发现机器人只会在最外层绕圈, 可以考虑记录总步数再对周长取模, 根据余数判断位置与方向. 需注意, 除了最开始位于原点时面朝东, 其余情况原地应均往南.
实现
class Robot {
int w, h, cur;
bool f;
public:
Robot(int width, int height) {
w = width - 1;
h = height - 1;
cur = 0;
f = true;
}
void step(int num) {
f = false;
cur = (cur + num) % (2 * (w + h));
}
vector<int> getPos() {
if (cur >= 0 && cur < w) return {cur, 0};
else if (cur >= w && cur < w + h) return {w, cur - w};
else if (cur >= w + h && cur < w * 2 + h) return {2 * w + h - cur, h};
else return {0, 2 * (h + w) - cur};
}
string getDir() {
if (f) return "East";
if (cur > 0 && cur <= w) return "East";
else if (cur > w && cur <= w + h) return "North";
else if (cur > w + h && cur <= w * 2 + h) return "West";
else return "South";
}
};
/**
* Your Robot object will be instantiated and called as such:
* Robot* obj = new Robot(width, height);
* obj->step(num);
* vector<int> param_2 = obj->getPos();
* string param_3 = obj->getDir();
*/
力扣每日一题3653-区间乘法查询后的异或I
日期:2026-04-08
题意
给定整数数组 nums, 与多个询问 queries[i] = [l, r, k, v] 表示从下标 l 开始每隔 k 个元素使其值乘上 v 后对 1e9 + 7 取模直到下标超过 r. 求处理所有询问后 nums 中所有元素异或结果.
思路
只能想到暴力解法, 要么开个超级无敌大的数组牺牲空间去做差分, 要么暴力去处理请求牺牲时间, 那考虑如何去优化这个过程, 自然是想到了优雅的暴力 根号分治. 对较小的间隔使用差分, 对较大的间隔使用暴力, 间隔的划分我们使用数组长度开根号, 即可将时空消耗均控制在了 n * sqrt(n).
实现
using ll = long long;
static constexpr ll mod = 1e9 + 7;
ll powMod(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) {
res = res * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return res;
}
class Solution {
public:
int xorAfterQueries(vector<int>& nums, vector<vector<int>>& queries) {
const int n = nums.size();
const int bz = sqrt(n) + 1;
vector f(bz + 1, vector<ll> (n, 1));
for (const auto& q : queries) {
int l = q[0], r = q[1], k = q[2], v = q[3];
if (k <= bz) {
ll nv = powMod(v, mod - 2);
f[k][l] = f[k][l] * v % mod;
// int nxt = r / k * k + k;
int nxt = (r - l) / k * k + k + l;
if (nxt < n) {
f[k][nxt] = f[k][nxt] * nv % mod;
}
} else {
for (int i = l; i <= r; i += k) {
nums[i] = (1ll * nums[i] * v) % mod;
}
}
}
for (int k = 1; k <= bz; k++) {
for (int i = 0; i < n; i++) {
nums[i] = nums[i] * f[k][i] % mod;
if (i + k < n) f[k][i + k] = f[k][i + k] * f[k][i] % mod;
}
}
int ans = 0;
for (const auto& x : nums) {
ans ^= x;
}
return ans;
}
};
力扣每日一题3655-区间乘法查询后的异或II
日期:2026-04-09
题意
给定整数数组 nums, 与多个询问 queries[i] = [l, r, k, v] 表示从下标 l 开始每隔 k 个元素使其值乘上 v 后对 1e9 + 7 取模直到下标超过 r. 求处理所有询问后 nums 中所有元素异或结果.
思路
是的! 正是昨天的数据增强版, 但这次我依旧是把 hard 做了再把 hard 复制回 easy 的, 我们昨天的思路是完全可以解决今天的范围的!
实现
using ll = long long;
static constexpr ll mod = 1e9 + 7;
ll powMod(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) {
res = res * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return res;
}
class Solution {
public:
int xorAfterQueries(vector<int>& nums, vector<vector<int>>& queries) {
const int n = nums.size();
const int bz = sqrt(n) + 1;
vector f(bz + 1, vector<ll> (n, 1));
for (const auto& q : queries) {
int l = q[0], r = q[1], k = q[2], v = q[3];
if (k <= bz) {
ll nv = powMod(v, mod - 2);
f[k][l] = f[k][l] * v % mod;
// int nxt = r / k * k + k;
int nxt = (r - l) / k * k + k + l;
if (nxt < n) {
f[k][nxt] = f[k][nxt] * nv % mod;
}
} else {
for (int i = l; i <= r; i += k) {
nums[i] = (1ll * nums[i] * v) % mod;
}
}
}
for (int k = 1; k <= bz; k++) {
for (int i = 0; i < n; i++) {
nums[i] = nums[i] * f[k][i] % mod;
if (i + k < n) f[k][i + k] = f[k][i + k] * f[k][i] % mod;
}
}
int ans = 0;
for (const auto& x : nums) {
ans ^= x;
}
return ans;
}
};
力扣每日一题3740-三个相等元素之间的最小距离I
日期:2026-04-10
题意
给定正整数数组 nums, 求满足 nums[i] == nums[j] == nums[k] 的 abs(i - j) + abs(j - k) + abs(k - i) 的最小值.
思路
abs(i - j) + abs(j - k) + abs(k - i) 实际上就是 2 * (max(i, j, k) - min(i, j, k)), 那么显然 ijk 应是连续对应值的下标, 因此可以考虑使用哈希记录对应值前两次出现的位置.
实现
class Solution {
static constexpr int inf = 1e9;
public:
int minimumDistance(vector<int>& nums) {
int n = nums.size();
vector f(2, vector<int> (n, -1));
int ans = inf;
for (int i = 0; i < n; i++) {
int x = nums[i] - 1;
if (f[1][x] != -1) ans = min(ans, i - f[1][x] << 1);
f[1][x] = f[0][x];
f[0][x] = i;
}
return ans == inf ? -1 : ans;
}
};
力扣每日一题3741-三个相等元素之间的最小距离II
日期:2026-04-11
题意
给定正整数数组 nums, 求满足 nums[i] == nums[j] == nums[k] 的 abs(i - j) + abs(j - k) + abs(k - i) 的最小值.
思路
没错, 和昨天题意是完全一样的, 只是数据增强, 但我们昨天的思路仍是可行的.
实现
class Solution {
static constexpr int inf = 1e9;
public:
int minimumDistance(vector<int>& nums) {
int n = nums.size();
vector f(2, vector<int> (n, -1));
int ans = inf;
for (int i = 0; i < n; i++) {
int x = nums[i] - 1;
if (f[1][x] != -1) ans = min(ans, i - f[1][x] << 1);
f[1][x] = f[0][x];
f[0][x] = i;
}
return ans == inf ? -1 : ans;
}
};
力扣每日一题1320-二指输入的的最小距离
日期:2026-04-12
题意
将 26 个字母按字母表顺序放至每行 6 个字母的方格键盘. 问使用该键盘在仅使用两指的情况下输入字符串 word 手指所需移动的最少距离. 初始手指位置不设限, 定义移动距离为格子间的曼哈顿距离.
思路
感觉使用 dp 还是蛮明显的, 状态就定义为两根手指所在位置, 记录对应代价和即可. 因为一定有一根手指在上一输入字符处, 因此这里我压缩了一下空间.
实现
class Solution {
static int cal(int x, int y) {
if (x == 26 || y == 26) return 0;
return abs(x / 6 - y / 6) + abs(x % 6 - y % 6);
}
static constexpr int inf = 1e9;
static constexpr int N = 27;
public:
int minimumDistance(string word) {
int n = word.size();
array<int, N> f;
f.fill(inf);
f[26] = 0;
for (int i = 1; i < n; i++) {
array<int, N> nf;
nf.fill(inf);
int pre = word[i - 1] - 'A';
int cur = word[i] - 'A';
for (int j = 0; j <= 26; j++) {
nf[j] = min(nf[j], cal(pre, cur) + f[j]);
nf[pre] = min(nf[pre], cal(j, cur) + f[j]);
}
swap(f, nf);
}
return ranges::min(f);
}
};
力扣每日一题1848-到目标元素的最小距离
日期:2026-04-13
题意
给定整数数组 nums, 与两个整数 target 与 start, 求满足 nums[i] == target 的 abs(i - start) 的最小值.
思路
没什么特别的, 进行一个遍历求值即可.
实现
class Solution {
public:
int getMinDistance(vector<int>& nums, int target, int start) {
int n = nums.size();
int ans = n;
for (int i = 0; i < n; i++) {
if (nums[i] == target) ans = min(ans, abs(start - i));
}
return ans;
}
};
力扣每日一题2463-最小移动总距离
日期:2026-04-14
题意
给定一条坐标轴上的若干个机器人与工厂的位置以及每个工厂所能维修的机器人数量上限, 所有机器人初始均是坏的. 可在任意时刻修改任意机器人的走向, 若机器人经过一个未达上限的工厂则会停下被维修. 问使得所有机器人均被维修, 所有机器人所需移动的最小距离之和.
思路
要使得总移动距离最小, 显然每个工厂所维修的是连续一段的机器人. 同时注意到数据范围并不大 1 <= len(robot), len(factory) <= 100, 那直接枚举每个工厂枚举所维修的个数以及开始维修的机器人写一个三次方的 dp 即可.
实现
class Solution {
using ll = long long;
static constexpr ll inf = 1e18;
public:
ll minimumTotalDistance(vector<int>& robot, vector<vector<int>>& factory) {
int n = factory.size(), m = robot.size();
ranges::sort(robot);
ranges::sort(factory);
vector f(n + 1, vector<ll> (m + 1, inf));
f[0][0] = 0;
for (int i = 1; i <= n; i++) {
int x = factory[i - 1][0], limit = factory[i - 1][1];
f[i][0] = 0;
for (int j = 0; j <= m; j++) {
f[i][j] = f[i - 1][j];
ll res = 0;
for (int k = 1; k <= limit && k <= j; k++) {
res += abs(x - robot[j - k]);
f[i][j] = min(f[i][j], f[i - 1][j - k] + res);
}
}
}
return f.back().back();
}
};
力扣每日一题2515-到目标字符串的最短距离
日期:2026-04-15
题意
给定环形字符串数组 words, 问从下标 startIndex 出发到字符串 target 的最小距离.
思路
虽然是环形数组但给出我们的还是常见的一维数组, 那只有两种情况, 一种是不跨过边界找到目标, 另一种则是反向跨过边界. 遍历找目标然后取最小即可.
实现
class Solution {
public:
int closestTarget(vector<string>& words, string target, int startIndex) {
int n = words.size();
int ans = n;
for (int i = 0; i < n; i++) {
if (words[i] == target) {
int t = abs(i - startIndex);
ans = min({ans, t, n - t});
}
}
return ans == n ? -1 : ans;
}
};
力扣每日一题2388-距离最小相等元素查询
日期:2026-04-16
题意
给定环形数组 nums, 以及一组询问 queries. 对于每个查询 queries[i] 返回满足 nums[j] == nums[queries[i]] 的 j 与查询的最小距离.
思路
换言而之就是寻找每个询问的数的最近其它出现位置, 可以想到用一个哈希数组记录每个数出现过的位置, 对于每个询问进行二分找到最近的两个数然后计算取最小即可.
实现
class Solution {
public:
vector<int> solveQueries(vector<int>& nums, vector<int>& queries) {
int n = nums.size(), q = queries.size();
vector<int> ans(q, n);
unordered_map<int, vector<int>> ump;
for (int i = 0; i < n; i++) {
ump[nums[i]].push_back(i);
}
for (int i = 0; i < q; i++) {
int j = queries[i];
int x = nums[j];
auto& vec = ump[x];
int& res = ans[i];
if (vec.size() == 1) {
res = -1;
continue;
}
auto r = ranges::upper_bound(vec, j);
if (r == vec.end()) res = min(res, n - j + vec.front());
else res = min({res, (*r) - j, j + n - (*r)});
auto l = ranges::lower_bound(vec, j);
if (l == vec.begin()) res = min(res, n - vec.back() + j);
else {
l = prev(l);
res = min({res, j - (*l), n - j + (*l)});
}
}
return ans;
}
};
力扣每日一题3761-镜像对之间最小绝对距离
日期:2026-04-17
题意
给定整数数组 nums, 求满足 i < j && reverse(nums[i]) == nums[j] 的 j - i 的最小值.
思路
类似的题应该出现过好多次了, 这里我们只需要记录每个 reverse(x) 最后出现的位置即可.
实现
class Solution {
public:
int minMirrorPairDistance(vector<int>& nums) {
int n = nums.size();
int ans = n;
unordered_map<int, int> last;
for (int i = 0; i < n; i++) {
if (last.count(nums[i])) {
ans = min(ans, i - last[nums[i]]);
}
string s = to_string(nums[i]);
ranges::reverse(s);
last[stoi(s)] = i;
}
return ans == n ? -1 : ans;
}
};
力扣每日一题3783-整数的镜像距离
日期:2026-04-18
题意
给定正整数 n, 求 abs(n - reverse(n))
思路
没有什么特别的, 按题意求值即可.
实现
class Solution {
public:
int mirrorDistance(int n) {
string s = to_string(n);
ranges::reverse(s);
return abs(stoi(s) - n);
}
};
力扣每日一题1855-下标对中的最大距离
日期:2026-04-19
题意
给定两个非递增的数组 nums1 与 nums2, 求满足 i <= j && nums1[i] <= nums2[j] 的 j - i 最大值.
思路
两个有序的数组, 首先想到的是枚举一个二分另一个. 但仔细一想, 这么好的条件直接双指针不就可以了吗!
实现
class Solution {
public:
int maxDistance(vector<int>& nums1, vector<int>& nums2) {
int n = nums1.size(), m = nums2.size();
int ans = 0;
for (int i = 0, j = 0; j < m; j++) {
for ( ; i < n && i <= j && nums1[i] > nums2[j]; i++);
if (i == n) break;
ans = max(ans, j - i);
}
return ans;
}
};
力扣每日一题2078-两栋颜色不同且距离最远的房子
日期:2026-04-20
题意
给定整数数组 colors 表示一排房子的颜色, 求问两栋不同颜色房子之间的最大距离.
思路
那我们只需要记录坐标最小的两个异色房子作为可选左端点, 然后进行一个枚举右端点即可.
实现
class Solution {
public:
int maxDistance(vector<int>& colors) {
int mn = -1, se = -1;
int n = colors.size();
int ans = 0;
for (int i = 0; i < n; i++) {
if (mn == -1) mn = i;
else if (se == -1 && colors[i] != colors[mn]) se = i;
if (colors[i] != colors[mn]) ans = max(ans, i - mn);
else if (se != -1) ans = max(ans, i - se);
}
return ans;
}
};
力扣每日一题1722-执行交换操作后的最小汉明距离
日期:2026-04-21
题意
给定两个整数数组 source 与 target, 同时给定一个数组 allowedSwaps[i] = [a_i, b_i] 表示可以任意次交换 source 中的对应下标的两个数. 求任意次操作后 source 与 target 的最小汉明距离.
思路
两个位置可以互相交换, 那就是建立一条无向边, 同一个联通变量的数可以转为任意顺序. 由此统计一下对应位置的数的个数, 落单的即会贡献答案.
实现
class Solution {
public:
int minimumHammingDistance(vector<int>& source, vector<int>& target, vector<vector<int>>& allowedSwaps) {
int n = source.size();
vector<vector<int>> adj(n);
for (auto& e : allowedSwaps) {
int u = e[0], v = e[1];
adj[u].push_back(v);
adj[v].push_back(u);
}
int ans = 0;
vector<bool> vis(n);
for (int i = 0; i < n; i++) {
if (vis[i]) continue;
unordered_map<int, int> cnt;
auto dfs = [&](this auto&& self, int x) -> void {
if (vis[x]) return;
vis[x] = true;
cnt[source[x]]++;
cnt[target[x]]--;
for (auto nxt : adj[x]) {
if (vis[nxt]) continue;
self(nxt);
}
};
dfs(i);
for (auto [x, t] : cnt) {
ans += abs(t);
}
}
return ans / 2;
}
};
2452-距离字典两次编辑以内的单词
日期:2026-04-22
题意
给定字符串数组 queries 与 dictionary, 每次操作可以任选一个 queries 中字符串的某个字符将其变为其它字符. 问所有两次及以内操作可转变为 dictionary 中字符串的字符串.
思路
进行一个暴暴的力统统枚举就好.
实现
class Solution {
public:
vector<string> twoEditWords(vector<string>& queries, vector<string>& dictionary) {
int n = queries.back().size();
vector<string> ans;
for (auto& q : queries) {
for (auto& d : dictionary) {
int cnt = 0;
for (int i = 0; i < n && cnt < 3; i++) {
cnt += d[i] != q[i];
}
if (cnt < 3) {
ans.push_back(q);
break;
}
}
}
return ans;
}
};
力扣每日一题2615-等值距离和
日期:2026-04-23
题意
给定整数 nums, 求对应数组 arr, 其中
思路
画个图可能会好理解很多. 设 abcd 点为相同值的点, 假如我们已经处理好 b 点的答案即红色线段长度和; 想要更新得到 c 点的答案即蓝色线段长度和, 显然是 c 点之前的所有点相关线段长度加上 bc 长度, c 点之后所有点相关线段长度减去 bc 长度. 由此可以容易进行更新.

实现
class Solution {
using ll = long long;
public:
vector<long long> distance(vector<int>& nums) {
int n = nums.size();
vector<ll> ans(n);
unordered_map<int, vector<int>> loc;
unordered_map<int, ll> f;
for (int i = 0; i < n; i++) {
if (!loc[nums[i]].empty()) f[nums[i]] += i - loc[nums[i]].front();
loc[nums[i]].push_back(i);
}
for (auto& [_, vec] : loc) {
int m = vec.size();
if (m == 1) continue;
ans[vec[0]] = f[nums[vec[0]]];
for (int i = 1; i < m; i++) {
ans[vec[i]] = ans[vec[i - 1]] + (vec[i] - vec[i - 1]) * (2ll * i - m);
}
}
return ans;
}
};
力扣每日一题2833-距离原点最远的点
日期:2026-04-24
题意
给定字符串 moves, 其中若为字符 L 表示向左移动, 为 R 为向右移动, 为 _ 表示可以朝任意方向移动. 问最终离起点最远距离.
思路
显然应是 L R 之差的绝对值加上任意向的数量.
实现
class Solution {
public:
int furthestDistanceFromOrigin(string moves) {
int l = 0, r = 0, t = 0;
for (auto& ch : moves) {
if (ch == 'L') l++;
else if (ch == 'R') r++;
else t++;
}
return abs(l - r) + t;
}
};
力扣每日一题3464-正方形上的点之间的最大距离
日期:2026-04-25
题意
给定正整数 side 表示一个左下角为坐标原点的正方形边长. 给定一堆均在该正方形上的点 points. 选出 k 个点使得这 k 个点之间的最小曼哈顿距离最大化.
思路
应该是不会无故给出无用条件的, 所有的点均在正方形上, 手玩一会发现两点间的曼哈顿距离即为沿正方形边长移动的较短距离, 可以想到将正方形展开为线, 构成一个循环数组. 使得最小值最大, 那首先应该考虑的是二分. 二分答案的这个最小值, 然后贪心地寻找 k 个点进行 check.
实现
class Solution {
using ll = long long;
public:
int maxDistance(int side, vector<vector<int>>& points, int k) {
vector<ll> p;
for (auto& t : points) {
int x = t[0], y = t[1];
if (y == 0) p.push_back(x);
else if (x == side) p.push_back(side + y);
else if (y == side) p.push_back(side * 3ll - x);
else p.push_back(side * 4ll - y);
}
ranges::sort(p);
auto check = [&](ll x) -> bool {
for (auto s : p) {
ll mx = side * 4ll - x + s;
ll cur = s;
bool ok = true;
for (int i = 1; i < k && ok; i++) {
auto nxt = ranges::lower_bound(p, cur + x);
if (nxt == p.end() || *nxt > mx) ok = false;
else cur = *nxt;
}
if (ok) return true;
}
return false;
};
ll lo = 1, hi = 4ll * side / k + 1;
while (lo < hi) {
ll mid = (lo + hi + 1) / 2;
if (check(mid)) lo = mid;
else hi = mid - 1;
}
return lo;
}
};
力扣每日一题1559-二维网格图中探测环
日期:2026-04-26
题意
给定二维字符网格 grid, 判断其内是否有长度大于等于 4 首尾相同且路径上格子字符均相同的环.
思路
没什么特别的方法吧, 就是开搜.
实现
class Solution {
static constexpr array<int, 2> nxt[] = {
{0, 1}, {0, -1}, {1, 0}, {-1, 0}
};
public:
bool containsCycle(vector<vector<char>>& grid) {
int n = grid.size(), m = grid.back().size();
bool ok = false;
vector vis(n, vector<bool> (m));
for (int i = 0; i < n && !ok; i++) {
for (int j = 0; j < m && !ok; j++) {
auto dfs = [&](this auto&& self, int x, int y, int px, int py) -> void {
if (vis[x][y]) {
ok = true;
return;
}
vis[x][y] = true;
for (auto& [tx, ty] : nxt) {
int nx = tx + x, ny = ty + y;
if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
if (nx == px && ny == py) continue;
if (grid[x][y] == grid[nx][ny]) self(nx, ny, x, y);
if (ok) return;
}
};
if (!vis[i][j]) dfs(i, j, -1, -1);
}
}
return ok;
}
};
力扣每日一题1391-检查网格中是否存在有效路径
日期:2026-04-27
题意
给出六种联通方式不同的方格, 由此组成的图 grid, 判断是否可以从左上角到达右下角.
思路
没什么特别的, 就是按照给定的连接方式进行一个搜索, 看是否可达即可.
实现
class Solution {
static constexpr int nxt[6][2][2] = {
{{0, -1}, {0, 1}},
{{-1, 0}, {1, 0}},
{{0, -1}, {1, 0}},
{{0, 1}, {1, 0}},
{{0, -1}, {-1, 0}},
{{0, 1}, {-1, 0}},
};
public:
bool hasValidPath(vector<vector<int>>& grid) {
int n = grid.size(), m = grid.back().size();
vector vis(n, vector<bool> (m));
auto dfs = [&](this auto&& self, int x, int y) -> void{
if (vis[x][y]) return;
vis[x][y] = true;
for (auto [tx, ty] : nxt[grid[x][y] - 1]) {
int nx = x + tx, ny = y + ty;
if (nx < 0 || nx >= n || ny < 0 || ny >= m || vis[nx][ny]) continue;
auto [ax, ay] = nxt[grid[nx][ny] - 1][0];
auto [bx, by] = nxt[grid[nx][ny] - 1][1];
if ((-tx == ax && -ty == ay) || (-tx == bx && -ty == by)) self(nx, ny);
if (vis.back().back()) return;
}
};
dfs(0, 0);
return vis.back().back();
}
};
力扣每日一题2033-获取单值网格的最小操作数
日期:2026-04-28
题意
给定整数网格 grid, 每次操作可任选一个数使其加或减 x, 问是否可以使得网格内所有数相等, 若可以求最小操作次数.
思路
不妨想象所有数在坐标轴上, 加减操作即为从某点向左右跳跃. 显然若最终可归于一点, 任意两点间距离应为 x 的倍数; 同时应所有点往中点去跳所需次数最少.
实现
class Solution {
public:
int minOperations(vector<vector<int>>& grid, int x) {
int n = grid.size(), m = grid.back().size();
vector<int> p;
int t = grid[0][0] % x;
for (auto& vec : grid) {
for (auto& i : vec) {
if (i % x != t) return -1;
p.push_back(i);
}
}
int ans = 0;
ranges::sort(p);
int mid = p[p.size() >> 1];
for (auto& i : p) {
ans += abs((i - mid) / x);
}
return ans;
}
};
3225-网格图操作后的最大分数
日期:2026-04-29
题意
给定初始全为白格子的方阵 grid, 每次操作可任选某格子使得该列所有行号小于等于该格的格子染色为黑色. 方阵分数记为某左或右相邻格子为黑色的白格子的值之和. 求任意次操作后方阵和最大值.
思路
显然进行一个 dp, 但我的论文真的要写不完了, 今天就让我偷偷懒吧! T_T
实现
class Solution {
using ll = long long;
public:
long long maximumScore(vector<vector<int>>& grid) {
int n = grid.size();
vector pre(n + 1, vector<ll> (n + 1));
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
pre[i + 1][j] = pre[i][j] + grid[i][j];
}
vector f(n + 1, vector (n + 1, vector<ll> (2)));
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j <= n; j++) {
for (int k = 0; k < 2; k++) {
auto& res = f[i + 1][j][k];
for (int t = 0; t <= n; t++) {
if (t == j) res = max(res, f[i][t][0]);
else if (t < j) res = max(res, f[i][t][1] + pre[j][i] - pre[t][i]);
else if (k == 0) res = max(res, f[i][t][0] + pre[t][i + 1] - pre[j][i + 1]);
else if (j == 0) res = max(res, f[i][t][0]);
}
}
}
}
ll ans = 0;
for (auto& t : f[n - 1]) ans = max(ans, t[0]);
return ans;
}
};
力扣每日一题3742-网格中得分最大的路径
日期:2026-04-30
题意
给定二维矩阵 grid, 初始位于矩阵左上角, 目标右下角. 矩阵每格的值均大于等于零且小于等于二, 其值表示经过该格的收益, 经过该格的代价则为该格值与 1 取较小值. 求最多花费 k 的情况下最大收益是多少.
思路
显然是一个非常经典的 dp, 但是我的论文还是没有写完, 就饶了我吧 T_T
实现
class Solution {
static constexpr int inf = 1e9;
public:
int maxPathScore(vector<vector<int>>& grid, int k) {
int n = grid.size(), m = grid.back().size();
vector f(n, vector (m, vector<int> (k + 2, -inf)));
f[0][0][k] = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
int c = grid[i][j] == 0 ? 0 : 1;
int g = grid[i][j];
for (int o = k - c; o >= 0; o--) {
int& x = f[i][j][o];
if (i) x = max(x, f[i - 1][j][o + c] + g);
if (j) x = max(x, f[i][j - 1][o + c] + g);
x = max(x, f[i][j][o + 1]);
}
}
}
int ans = -inf;
for (int i = 0; i <= k; i++) ans = max(ans, f[n - 1][m - 1][i]);
return ans < 0 ? -1 : ans;
}
};