力扣每月题解汇总-2025年10月

目录


力扣每日一题1518-换水问题

日期:2025-10-01

题意

初始有 numBottles 瓶水,每 numExchange 个空瓶可以换一瓶水,问最多可以喝到多少瓶水。

思路

数据范围都是比较小的 1 <= numBottles <= 100, 2 <= numExchange <= 100 故而可以直接模拟(见cpp实现)

当然也是可以推一下公式的:相当于每次减少 (numExchange - 1) 瓶水可以减少多少次。(见python实现)

实现

class Solution {
public:
int numWaterBottles(int numBottles, int numExchange) {
int ans = numBottles;
for ( ; numBottles >= numExchange; ) {
ans += numBottles / numExchange;
numBottles = numBottles / numExchange + numBottles % numExchange;
}
return ans;
}
};
class Solution:
def numWaterBottles(self, numBottles: int, numExchange: int) -> int:
return numBottles + (numBottles - 1) // (numExchange - 1)

力扣每日一题3100-换水问题II

日期:2025-10-02

题意

初始有 numBottles 瓶水,每 numExchange 个空瓶可以换一瓶水,但每交换一瓶水 numExchage 会加 1 ,求最多可以喝多少瓶水。

思路

那和昨天是非常类似的,只是 numExchage 不再是定值。

推公式变得难推很多,所以咱们就简单问题简单做,进行一个模拟就好。

实现

class Solution {
public:
int maxBottlesDrunk(int numBottles, int numExchange) {
int ans = numBottles;
for ( ; numBottles >= numExchange; ) {
ans++;
numBottles -= numExchange - 1;
numExchange++;
}
return ans;
}
};

力扣每日一题407-接雨水II

日期:2025-10-03

题意

给定二维数组,表示各个单元格的高度,求所给几何体可以装多少水。

思路

大名鼎鼎的接雨水题,不过扩展到了三维情况。

咱们先手玩一下,不难发现最外围一圈格子一定是无法接水的。而次外围的格子所能装的一定不超过相邻最外围格子的最小值。这样一直往里推,即可求出各个单元格所能装水的高度,为了每次取最小我们使用优先队列模拟即可。

实现

class Solution {
static constexpr array<int, 2> to[] = {
{0, 1}, {0, -1}, {1, 0}, {-1, 0}
};
public:
int trapRainWater(vector<vector<int>>& heightMap) {
int n = heightMap.size(), m = heightMap.back().size();
priority_queue<array<int, 3>, vector<array<int, 3>>, greater<>> pq;

for (int i = 0; i < n; i++) {
pq.push({heightMap[i].front(), i, 0});
pq.push({heightMap[i].back(), i, m - 1});
heightMap[i][0] = heightMap[i][m - 1] = -1;
}
for (int i = 1; i < m - 1; i++) {
pq.push({heightMap[0][i], 0, i});
pq.push({heightMap[n - 1][i], n - 1, i});
heightMap[0][i] = heightMap[n - 1][i] = -1;
}

int ans = 0;
while (!pq.empty()) {
auto [h, x, y] = pq.top();
pq.pop();
for (auto [tx, ty] : to) {
int nx = x + tx, ny = y + ty;
if (nx < 0 || nx >= n || ny < 0 || ny >= m || heightMap[nx][ny] == -1) continue;
ans += max(0, h - heightMap[nx][ny]);
pq.push({max(heightMap[nx][ny], h), nx, ny});
heightMap[nx][ny] = -1;
}
}
return ans;
}
};

力扣每日一题11-盛最多水的容器

日期:2025-10-04

题意

给定数组 height 表示 x 轴上按次排序的各条垂线的高度,找出其中两条线使得它们与 x 轴构成的容器可装最多水。

(具体的 height[i] = h 表示第 i 条线两端点为 (i, 0)i, h

思路

可装水的体积以两条线之间的距离为底,以两线较短边为高。即若选 i, j 两条边所组成的体积为 (j - i) * min(height[i], height[j])

当取 height 两端点时有 (j - i) 取到最大值,此时我们考虑如何选择可能让体积变得更大:

无论移动哪一条边 (j - i) 必然减小,故而必须使 min(height[i], height[j]) 变大才可能使得体积增大。若移动较长边 min(height[i], height[j]) 必然不变或减小,因此我们固定较长边枚举较短边。

根据以上思路双指针遍历数组取最大作为答案即可。

实现

class Solution {
public:
int maxArea(vector<int>& height) {
int ans = 0;
for (int l = 0, r = height.size() - 1; l < r; ) {
ans = max(ans, min(height[l], height[r]) * (r - l));
if (height[l] < height[r]) l++;
else r--;
}
return ans;
}
};
class Solution:
def maxArea(self, height: List[int]) -> int:
ans = 0
l = 0
r = len(height) - 1
while l < r:
ans = max(ans, min(height[l], height[r]) * (r - l))
if height[l] < height[r]:
l += 1
else:
r -= 1
return ans

力扣每日一题417-太平洋大西洋水流问题

日期:2025-10-05

题意

给定二维数组 heights 表示一个矩形海岛各处的高度。若相邻格子高度小于等于当前格子高度,则当前格子的水可以流向相邻格子。

记海岛左侧与上侧为太平洋,右侧下侧为大西洋,求岛上有哪些格子的水可以同时流向太平洋与大西洋。

思路

这题的数据范围并不大,海岛的长宽均小于等于 200 ,那其实怎么做基本都可以接受的。

这里我们以左侧与上侧为起点做一趟bfs,标记所有可达太平洋的格子;再以右侧与下侧为起点做一趟bfs,标记所有可达大西洋的格子;在返回被标记两次的格子即可。

实现

class Solution {
static constexpr array<int, 2> to[] = {
{0, 1}, {0, -1}, {1, 0}, {-1, 0}
};
public:
vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {
int n = heights.size(), m = heights.back().size();
vector<vector<int>> ans;
vector<vector<int>> f(n, vector<int> (m));
vector<vector<bool>> vis(n, vector<bool> (m));

vector<array<int, 2>> q;
for (int i = 0; i < n; i++) q.push_back({i, 0});
for (int i = 1; i < m; i++) q.push_back({0, i});
for (int i = 0; i < q.size(); i++) {
auto [x, y] = q[i];
if (vis[x][y]) continue;
f[x][y] |= 1;
vis[x][y] = true;
for (auto [tx, ty] : to) {
int nx = x + tx, ny = y + ty;
if (nx < 0 || nx >= n || ny < 0 || ny >= m || vis[nx][ny]) continue;
if (heights[nx][ny] >= heights[x][y]) q.push_back({nx, ny});
}
}

q.clear();
for (int i = 0; i < n; i++) {q.push_back({i, m - 1}); fill(vis[i].begin(), vis[i].end(), false);}
for (int i = 0; i < m - 1; i++) q.push_back({n - 1, i});
for (int i = 0; i < q.size(); i++) {
auto [x, y] = q[i];
if (vis[x][y]) continue;
f[x][y] |= 2;
vis[x][y] = true;
for (auto [tx, ty] : to) {
int nx = x + tx, ny = y + ty;
if (nx < 0 || nx >= n || ny < 0 || ny >= m || vis[nx][ny]) continue;
if (heights[nx][ny] >= heights[x][y]) q.push_back({nx, ny});
}
}

for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (f[i][j] == 3) ans.push_back({i, j});

return ans;
}
};

力扣每日一题778-水位上升的泳池中游泳

日期:2025-10-06

题意

给定 n * n 的数组 grid 表示矩形水池中各个位置的高度。在时刻 t 水池的水位为 t ,可以在相邻的高度小于等于 t 的格子中任意不耗时地移动。初始位于水池的左上角 (0, 0) ,求到达水池右下角 (n - 1, n - 1) 的最短时间。

思路

第一想法是进行一个二分,二分最短时间然后从起点进行一个 bfs/dfs ,仅能经过高度小于等于 x 的格子,查看是否可达终点。

但是仔细一想这个过程是可以简化的:维护当前时刻,并用优先队列维护可达点,第一次到达终点的时刻即为答案。

实现

class Solution {
static constexpr array<int, 2> to[] = {
{1, 0}, {-1, 0}, {0, 1}, {0, -1}
};
public:
int swimInWater(vector<vector<int>>& grid) {
int cur = 0;
int n = grid.size();
vector vis(n, vector<bool> (n));
priority_queue<array<int, 3>, vector<array<int, 3>>, greater<>> pq;
pq.push({grid[0][0], 0, 0});

while (!pq.empty()) {
auto [c, x, y] = pq.top();
pq.pop();
if (vis[x][y]) continue;
vis[x][y] = true;
cur = max(cur, c);
if (x == n - 1 && y == n - 1) return cur;
for (auto [tx, ty] : to) {
int nx = x + tx, ny = y + ty;
if (nx < 0 || nx >= n || ny < 0 || ny >= n || vis[nx][ny]) continue;
pq.push({grid[nx][ny], nx, ny});
}
}
return -1;
}
};

力扣每日一题1488-避免洪水泛滥

日期:2025-10-07

题意

有很多初始为空的湖,若该湖雨前为空则雨后满,若该湖雨前已满则雨后发生洪水。给定数组 rains ,若 rains[i]0 表示当天湖 rains[i] 下雨,若 rains[i]0 表示当天无雨可任选一个湖进行抽水。求问是否有抽水策略可使不发生洪水,返回对应方案。

思路

那只需要记录每个湖上一次下雨的日期,以及还未安排抽水的日期,取第一个大于上次下雨的日期对该湖进行抽水即可。

实现

class Solution {
public:
vector<int> avoidFlood(vector<int>& rains) {
unordered_map<int, int> last;
set<int> st;
int n = rains.size();
vector<int> ans(n, -1);
for (int i = 0; i < n; i++) {
if (rains[i] == 0) {
st.insert(i);
continue;
}
if (last.count(rains[i])) {
int l = last[rains[i]];
auto it = st.lower_bound(l);
if (it == st.end()) return {};
ans[*it] = rains[i];
st.erase(it);
last[rains[i]] = i;
} else {
last[rains[i]] = i;
}
}
for (auto i : st) ans[i] = 1;
return ans;
}
};

力扣每日一题2300-咒语和药水的成功对数

日期:2025-10-08

题意

给定正整数数组 spellspotions 分别表示若干个咒语的强度和若干个药水的强度。同时给定正整数 success ,若咒语和药水的强度乘积大于等于 success 则视其为成功组合。求问每个咒语有多少个成功组合。

思路

potions 进行排序,找第一个与对应咒语乘积大于等于 success 的药水,其与其后的药水显然满足成功的条件。

欲使得某整数与 x 乘积大于等于 success 显然该数应大于等于

因此进行一个排序后二分即可。

实现

class Solution {
using ll = long long;
public:
vector<int> successfulPairs(vector<int>& spells, vector<int>& potions, ll success) {
int n = spells.size(), m = potions.size();
vector<int> ans(n);
ranges::sort(potions);

for (int i = 0; i < n; i++) {
ll need = (success + spells[i] - 1) / spells[i];
ans[i] = potions.end() - ranges::lower_bound(potions, need);
}

return ans;
}
};
class Solution:
def successfulPairs(self, spells: List[int], potions: List[int], success: int) -> List[int]:
potions.sort()
m = len(potions)
return [m - bisect_left(potions, (success + x - 1) // x) for x in spells]

力扣每日一题3494-酿造药水需要的最少总时间

日期:2025-10-09

题意

给定正整数数组 skillmana,分别表示各巫师的能力与各药水的法力。对于第 i 个巫师处理第 j 个药水所需的时间为 skill[i] * mana[j]

必须按顺序酿造药水,且每个药水均需经过每个巫师的处理,同时药水在当前巫师完成工作后必须立即传递给下一巫师开始处理。

求酿造好所有药水所需的最短时间。

思路

某药水被某巫师处理完毕后必须立刻由下一巫师开始进行处理,因此各个时间需要同步。

开一数组记录各个巫师处理完上一药水的时间,然后模拟处理每个药水的流程即可。

实现

class Solution {
using ll = long long;
public:
ll minTime(vector<int>& skill, vector<int>& mana) {
int n = skill.size(), m = mana.size();
vector<ll> t(n);
for (int i = 0; i < m; i++) {
ll start = 0;
for (int j = 0; j < n; j++) {
start = max(start, t[j]) + 1ll * skill[j] * mana[i];
}
t[n - 1] = start;
for (int j = n - 2; j >= 0; j--) {
t[j] = t[j + 1] - 1ll * skill[j + 1] * mana[i];
}
}
return t.back();
}
};

力扣每日一题3147-从魔法师身上吸取的最大能量

日期:2025-10-10

题意

n 个魔法师站成一排,他们能量 energy 有正有负,同时给定正整数 k ,可以任选一个魔法师开始,吸收其能量后跳跃到当前位置 + k 处继续吸收,直到到达魔法师队伍外。求可以获得的最大能量。

思路

那很明显就是一个 dp 题,显然当前位置可得能量大于零才会进行考虑,这里我选择了递推,当当前位置可得能量大于零则将当前格所得能量推给 + k 处。

实现

class Solution {
public:
int maximumEnergy(vector<int>& energy, int k) {
int n = energy.size();
vector<int> f = energy;
for (int i = 0; i < n; i++) {
if (f[i] > 0 && i + k < n) f[i + k] += f[i];
}
int ans = INT_MIN;
for (int i = n - k; i < n; i++) ans = max(ans, f[i]);
return ans;
}
};
class Solution:
def maximumEnergy(self, energy: List[int], k: int) -> int:
n = len(energy)
f = [0] * n
for i in range(n):
f[i] += energy[i]
if f[i] > 0 and i + k < n:
f[i + k] = f[i]
return max(f[n - k : ])

力扣每日一题3186-施咒的最大总伤害

日期:2025-10-11

题意

给定 power 表示一堆咒语的伤害,若使用了伤害为 x 的咒语,则不再可以使用伤害为 x - 1, x - 2, x + 1, x + 2 的咒语。求可造成的最大伤害和。

思路

那也很明显就是一个 dp 题,对各个咒语进行排序并计数去重后显然有:

进行一个双指针维护最大的 dp_j 即可 O(n) 完成

实现

class Solution {
using ll = long long;
public:
ll maximumTotalDamage(vector<int>& power) {
ranges::sort(power);
vector<array<int, 2>> cnt;
int m = power.size();
for (int i = 0, j = 0; i < m; i = j) {
for ( ; j < m && power[j] == power[i]; j++);
cnt.push_back({power[i], j - i});
}

int n = cnt.size();
vector<ll> f(n);
ll mx = 0;
int j = 0;
for (int i = 0; i < n; i++) {
for ( ; cnt[i][0] - cnt[j][0] > 2; j++) mx = max(mx, f[j]);
f[i] = mx + 1ll * cnt[i][0] * cnt[i][1];
}
for ( ; j < n; j++) mx = max(mx, f[j]);
return mx;
}
};

力扣每日一题3539-魔法序列的数组乘积之和

日期:2025-10-12


力扣每日一题2273-移除字母异位词后的结果数组

日期:2025-10-13

题意

若两字符串由相同的字母组成,称其为字母异位词。

给定字符串数组 words ,若 words 中存在相邻的字母异位词则删除较后的那一个字符串。返回最终的 words

思路

由相同的字母组成,python可以简单的直接 Counter ,cpp计数也可以,但就实现的复杂性来讲直接排序并比较即可。

遍历比较当前字符串是否与上一未删字符串相同即可。

实现

class Solution {
public:
vector<string> removeAnagrams(vector<string>& words) {
vector<string> ans;
string back = "";
for (auto& s : words) {
string t = s;
ranges::sort(t);
if (back == t) continue;
ans.push_back(s);
back = t;
}
return ans;
}
};
class Solution:
def removeAnagrams(self, words: List[str]) -> List[str]:
ans = [words[0]]
for i, j in pairwise(words):
if Counter(i) != Counter(j):
ans.append(j)
return ans

力扣每日一题3349-检测相邻递增子数组I

日期:2025-10-14

题意

给定整数数组 nums 与一正整数 k ,判断数组中是否存在两个相邻且长度为 k 的严格递增子数组。

思路

存在两个相邻且长度为 k 的严格递增子数组有两种情况:

  1. 存在一个长度大于等于 2 * k 的严格递增子数组,可以从中任截一段等于 2 * k 的子数组作为答案
  2. 存在两个相邻且长度大于等于 k 的严格递增子数组,从相邻部分开始各取长度为 k 的子数组即可

根据上述两种情况,双指针遍历一遍数组即可。

实现

class Solution {
public:
bool hasIncreasingSubarrays(vector<int>& nums, int k) {
int n = nums.size();
for (int i = 0, j = 0; i < n; ) {
for (j = i + 1; j < n && nums[j - 1] < nums[j]; j++);
if (j - i >= (k << 1)) return true;
else if (j - i < k) {
i = j;
continue;
}
if (j == n) return false;
int l = j, r = j + 1;
for ( ; r < n && nums[r - 1] < nums[r]; r++);
if (r - l >= k) return true;
i = r;
}
return false;
}
};

力扣每日一题3350-检测相邻递增子数组II

日期:2025-10-15

题意

就是昨天题目的升级版,此处给出整数数组 nums ,求最大的 k ,使得数组中存在两个相邻且长度为 k 的严格递增子数组。

思路

有两个思路,第一个比较简单,就是对答案进行二分,然后使用昨天的代码 check

第二个其实是对昨日思路的扩展,两个相邻且等长的递增子数组有两种情况:

  1. 有一个递增的子数组,将其拆分两半
  2. 有两个相邻的递增子数组,将较长的一个截至与较短的等长

根据以上思路在昨日基础上双指针求最大即可。

实现

class Solution {
public:
int maxIncreasingSubarrays(vector<int>& nums) {
int n = nums.size();
int ans = 0;
for (int i = 0, j = 0; i < n; ) {
for (j = max(i + 1, j); j < n && nums[j - 1] < nums[j]; j++);
ans = max(ans, j - i >> 1);
if (j == n) break;
int l = j, r = j + 1;
for ( ; r < n && nums[r - 1] < nums[r]; r++);
ans = max({ans, r - l >> 1, min(r - l, j - i)});
i = l; j = r;
}
return ans;
}
};

力扣每日一题2598-执行操作后的最大MEX

日期:2025-10-16

题意

给定整数数组 nums 以及一个正整数 value 。每次操作可任选 nums 中一数加或减 value 。求任意次操作后 nums 最大的 MEX 值。

思路

每个数均可以加减任意次 value,换而言之每个数均可以转换为任意同余 value 的数。故将 nums 中每个数按与 value 的模数分组,枚举 MEX 即可。

实现

class Solution {
public:
int findSmallestInteger(vector<int>& nums, int value) {
vector<int> cnt(value);
for (auto x : nums) {
cnt[(x % value + value) % value]++;
}
int ans = 0;
for ( ; cnt[ans % value]--; ans++);
return ans;
}
};
class Solution:
def findSmallestInteger(self, nums: List[int], value: int) -> int:
cnt = [0] * value
for x in nums:
cnt[x % value] += 1

return value * min(cnt) + cnt.index(min(cnt))

力扣每日一题3003-执行操作后的最大分割数量

日期:2025-10-17

题意

给定仅有小写字母的字符串 s 以及正整数 k

每次选择 s 的最长且仅含 k 各不同字符的前缀进行删除,直到字符串 s 为空,记删除次数为分割数量。

可以将 s 中至多一处替换为另一小写字母,求最大分割数量。

思路

数据范围并不是很大 1 <= s.size() <= 1e4 再加上仅含 26 个小写字母,咱们直接进行一个深搜 dfs 即可。

实现

class Solution:
def maxPartitionsAfterOperations(self, s: str, k: int) -> int:
@cache
def dfs(loc, cur, c):
if loc == len(s):
return 1
p = 1 << (ord(s[loc]) - ord('a'))
if (cur | p).bit_count() > k:
res = dfs(loc + 1, p, c) + 1
else:
res = dfs(loc + 1, cur | p, c)
if c == 0:
return res

for j in range(26):
if (cur | (1 << j)).bit_count() > k:
res = max(res, dfs(loc + 1, 1 << j, 0) + 1)
else:
res = max(res, dfs(loc + 1, cur | (1 << j), 0))
return res

return dfs(0, 0, 1)

力扣每日一题3397-执行操作后不同元素的最大数量

日期:2025-10-18

题意

给定正整数数组 nums 和一个正整数 k ,对于 nums 中每个元素均可以使其加一个 [-k, k] 的元素一次。求操作过后 nums 中最多有多少不同元素。

思路

没什么特别好的想法,故进行一个排序,每个数选择将其变为可达不同的最小数进行贪心。

实现

class Solution {
public:
int maxDistinctElements(vector<int>& nums, int k) {
ranges::sort(nums);
int last = -1e9;
int ans = 0;
for (auto x : nums) {
int mn = x - k, mx = x + k;
if (last >= mx) continue;
last = max(last + 1, mn);
ans++;
}
return ans;
}
};
class Solution:
def maxDistinctElements(self, nums: List[int], k: int) -> int:
nums.sort()
last = -1e9
ans = 0
for x in nums:
mn, mx = x - k, x + k
if last >= mx:
continue
ans += 1
last = max(last + 1, mn)
return ans

力扣每日一题1625-执行操作后字典序最小的字符串

日期:2025-10-19

题意

给定偶长的数字字符串 s 以及两个正整数 ab ,可以任意顺序执行任意次以下操作:

  • s 中所有奇数位的元素加 a10
  • s 向右轮转 b

求上述操作后可得的字典序最小的字符串。

思路

数据范围实在是不大 2 <= s.size() <= 100

同时由于操作一为加 a10 ,显然最少加 10 次就重复了,用裴蜀定理也可以得更小,但总之是不大的操作。并且字符串固定偶长,当 b 为偶数时就仅可能给奇数位加数。一通分析发现状态数很少,故而直接写了暴力。

实现

class Solution {
public:
string findLexSmallestString(string s, int a, int b) {
string ans = s;
int n = s.size();
int t = gcd(b, n);

for (int x = 0; x < 10; x++) {
string tmp = s;
for (int j = 1; j < n; j += 2) {
tmp[j] = char((tmp[j] - '0' + x * a) % 10 + '0');
}
if (b & 1) {
for (int y = 0; y < 10; y++) {
string tmp2 = tmp;
for (int j = 0; j < n; j += 2) {
tmp2[j] = char((tmp2[j] - '0' + y * a) % 10 + '0');
}
for (int i = 0; i < n; i += t) {
ans = min(ans, tmp2.substr(i) + tmp2.substr(0, i));
}
}
} else {
for (int i = 0; i < n; i += t) {
ans = min(ans, tmp.substr(i) + tmp.substr(0, i));
}
}
}
return ans;
}
};

力扣每日一题2011-执行操作后的变量值

日期:2025-10-20

题意

给定初值为 0 的变量 x ,与一堆操作 operations ,其中若操作为 ++xx++ 表示 x 加一,若为 x----x 表示 x 减一,求所有操作后的 x 值。

思路

非常简单的模拟题,判断每个操作第一位与最后一位是否为 +- 进行计算即可。

实现

class Solution {
public:
int finalValueAfterOperations(vector<string>& operations) {
int ans = 0;
for (const auto& s : operations) {
if (s[0] == '+' || s[2] == '+') ans++;
else ans--;
}
return ans;
}
};
class Solution:
def finalValueAfterOperations(self, operations: List[str]) -> int:
ans = 0
for s in operations:
if s[0] == '+' or s[-1] == '+':
ans += 1
else:
ans -= 1
return ans

力扣每日一题3346-执行操作后元素的最高频率I

日期:2025-10-21

题意

给定整数数组 nums 与两个整数 knumOperations。必须对 nums 操作 numOperations 次,每次操作可任选一个未选择过的 nums 中元素使其加上 [-k, k] 的整数。求操作结束后 nums 中出现频率最高元素的出现次数。

思路

出现次数最高的元素有两种可能:

  1. 该元素原本就在 nums
  2. 该元素不在 nums

第一种情况我们可以进行一个枚举该元素,同时维护左右端点,出现次数即为其窗口大小与该数次数加上最多操作数的最小值。

第二种情况我们直接滑动窗口维护被操作的左右端点即可,最终注意操作数即答案不能超过操作次数上限。

实现

class Solution {
public:
int maxFrequency(vector<int>& nums, int k, int numOperations) {
ranges::sort(nums);
int n = nums.size();

int ans = 0;
for (int i = 0, l = 0, r = 0, j = 0; i < n; i = j) {
for (j = i + 1; j < n && nums[i] == nums[j]; j++);
for ( ; l < i && nums[l] + k < nums[i]; l++);
for (r = max(r, j); r < n && nums[r] - k <= nums[i]; r++);
ans = max(ans, min(r - l, j - i + numOperations));
}
if (ans >= numOperations) return ans;
for (int l = 0, r = 0; r < n; r++) {
for ( ; nums[l] < nums[r] - 2 * k; l++);
ans = max(ans, r - l + 1);
}
return min(ans, numOperations);
}
};

力扣每日一题3347-执行操作后元素的最高频率II

日期:2025-10-22

题意

给定整数数组 nums 与两个整数 knumOperations。必须对 nums 操作 numOperations 次,每次操作可任选一个未选择过的 nums 中元素使其加上 [-k, k] 的整数。求操作结束后 nums 中出现频率最高元素的出现次数。

思路

是的,和昨天的题目完全一样,只是数据范围进行加强,昨日 nums.size() k nums[i] 均小于等于 1e5, 今日 knums[i] 增强到了 1e9。但昨天所做其实就可以过了,但可能方便阅读一些,我复制过来了。

出现次数最高的元素有两种可能:

  1. 该元素原本就在 nums
  2. 该元素不在 nums

第一种情况我们可以进行一个枚举该元素,同时维护左右端点,出现次数即为其窗口大小与该数次数加上最多操作数的最小值。

第二种情况我们直接滑动窗口维护被操作的左右端点即可,最终注意操作数即答案不能超过操作次数上限。

实现

class Solution {
public:
int maxFrequency(vector<int>& nums, int k, int numOperations) {
ranges::sort(nums);
int n = nums.size();

int ans = 0;
for (int i = 0, l = 0, r = 0, j = 0; i < n; i = j) {
for (j = i + 1; j < n && nums[i] == nums[j]; j++);
for ( ; l < i && nums[l] + k < nums[i]; l++);
for (r = max(r, j); r < n && nums[r] - k <= nums[i]; r++);
ans = max(ans, min(r - l, j - i + numOperations));
}
if (ans >= numOperations) return ans;
for (int l = 0, r = 0; r < n; r++) {
for ( ; nums[l] < nums[r] - 2 * k; l++);
ans = max(ans, r - l + 1);
}
return min(ans, numOperations);
}
};

力扣每日一题3461-判断操作后字符串中的数字是否相等I

日期:2025-10-23

题意

给定一个数字字符串 s。重复操作直到字符串仅剩两字符:令 s[i] 代表的数字与 s[i + 1] 代表的数字相加模 10 替换掉 s[i]。判断最后两字符是否相同。

思路

如果不考虑模 10 操作的就非常像陈辉三角,那就有非常多的性质可以用了。但是注意到这里数据范围真的很小 3 <= s.size() <= 100 。故而我们就不折磨自己简单问题简单做,进行一个模拟即可。

实现

class Solution {
public:
bool hasSameDigits(string s) {
int n = s.size();
for (int i = n - 1; i > 1; i--) {
for (int j = 0; j < i; j++) {
s[j] = (s[j] - '0' + s[j + 1] - '0') % 10 + '0';
}
}
return s[0] == s[1];
}
};

力扣每日一题2048-下一个更大的数值平衡数

日期:2025-10-24

题意

如果整数 x 的每个数位 d 恰好在 x 中出现 d 次,则称其为数值平衡数。对于给定的正整数 n ,求出最小严格大于 n 的数值平衡数。

思路

数据范围并不是很大 1 <= n <= 1e6,故而可以直接暴力(见 python 写法)。

也可以首先通过 dfs 预处理出所有数值平衡数,进行一个排序后每次查询进行二分即可。

实现

vector<int> ans;
int init = []() {
string s = "";
auto dfs = [&](this auto&& self, int i) -> void {
if (s.size() == 7) {
ans.push_back(stoi(s));
return;
} else if (s.size() > 7) {
return;
}
if (i > 7) return;
if (!s.empty())
do {
ans.push_back(stoi(s));
} while (next_permutation(s.begin(), s.end()));

self(i + 1);
if (s.size() + i > 7) return;
for (int j = 0; j < i; j++) s += char(i + '0');
self(i + 1);
for (int j = 0; j < i; j++) s.pop_back();
};
dfs(1);
ranges::sort(ans);
ans.erase(unique(ans.begin(), ans.end()), ans.end());
return 0;
} ();

class Solution {
public:
int nextBeautifulNumber(int n) {
return *ranges::upper_bound(ans, n);
}
};
class Solution:
def nextBeautifulNumber(self, n: int) -> int:
def check(s):
cnt = Counter(str(s))
if all(int(i) == t for i, t in cnt.items()):
return True
return False
while True:
n += 1
if check(n):
return n

力扣每日一题1716-计算力扣银行的钱

日期:2025-10-25

题意

每周内每天会比前一天多存 1 块,而下周一会比这周一多存 1 块。现在在第一个周一存 1 块连续存 n 天,问最终存了多少。

思路

这题数据范围依旧不大 1 <= n <= 1e3 大可直接进行模拟。比较简单就是算一下等差求和:将存钱分成两个部分,第一部分是可以存完整一周的,第二部分是剩余不足一周的几天。第一周共可存 28 块且此后每周多存 7 块;最后一个周一会存 块,接下来每天多存 1 块。简单计算一下即可。

实现

class Solution {
public:
int totalMoney(int n) {
int weeks = n / 7;
int days = n % 7;
return (28 + 21 + weeks * 7) * (weeks) / 2 + (weeks + 1 + weeks + days) * (days) / 2;
}
};

力扣每日一题2043-简易银行系统

日期:2025-10-26

题意

实现一个简单的银行系统,包含使用数组初始化所有账户信息、用户1给用户2转账,用户存取款功能。转账存取款操作返回操作是否成功。

思路

那就是一个非常简单的模拟题,注意先判断账户是否存在,账户余额是否足够即可。

实现

class Bank {
using ll = long long;
vector<ll> count;
int n;
public:
Bank(vector<long long>& balance) {
count = move(balance);
n = count.size();
}

bool transfer(int account1, int account2, long long money) {
if (account1 > n || account2 > n || count[account1 - 1] < money) return false;
count[account1 - 1] -= money;
count[account2 - 1] += money;
return true;
}

bool deposit(int account, long long money) {
if (account > n) return false;
count[account - 1] += money;
return true;
}

bool withdraw(int account, long long money) {
if (account > n || count[account - 1] < money) return false;
count[account - 1] -= money;
return true;
}
};

/**
* Your Bank object will be instantiated and called as such:
* Bank* obj = new Bank(balance);
* bool param_1 = obj->transfer(account1,account2,money);
* bool param_2 = obj->deposit(account,money);
* bool param_3 = obj->withdraw(account,money);
*/

力扣每日一题2125-银行中的激光束数量

日期:2025-10-27

题意

给定字符串数组 bank 其中 bank[i][j] 表示第 ij 列有一个安全设备。若某两行有安全设备且这两行件的其他行无设备,这两行的设备会两两用激光连接。问共有多少条激光。

思路

两行之间的激光就是两行设备数的乘积,故而仅需记录上一有设备行的设备数,进行一次模拟计算即可。

实现

class Solution {
public:
int numberOfBeams(vector<string>& bank) {
int ans = 0;
int pre = 0;
for (const auto& s : bank) {
int cur = count(s.begin(), s.end(), '1');
ans += cur * pre;
if (cur) pre = cur;
}
return ans;
}
};

力扣每日一题3354-使数组元素等于零

日期:2025-10-28

题意

给定非负整数数组 nums,可以任选一个初始值为 0 的点以及一个方向,会从初始点向方向蔓延直到遇到第一个大于 0 的数使其减一后转向,一直蔓延直到越界为止。问有多少种选择可使数组变为全 0 数组。

思路

显然有两种情况可以使得数组变为全零。第一种是 0 左右两侧和相等,可以贡献左右两种答案;第二种是 0 左右侧和差值为 1 ,可以贡献往和较大一侧的一个答案。

实现

class Solution {
public:
int countValidSelections(vector<int>& nums) {
int sum = accumulate(nums.begin(), nums.end(), 0);
int ans = 0, cur = 0;
for (auto x : nums) {
cur += x;
if (x == 0 && cur == sum - cur) ans += 2;
else if (x == 0 && abs(sum - cur - cur) == 1) ans += 1;
if (cur > sum + 1) break;
}
return ans;
}
};

力扣每日一题3370-仅含置位位的最小整数

日期:2025-10-29

题意

给定正整数 n ,找出二进制下全为 1 且最小的大于等于 n 的数。

思路

二进制下全为 1 可以直接通过将 1 左移一定位数后减一得到,问题就可以转换为最小大于等于 n 的二的次幂,那也就是求 nbit_width ,直接调函数或其他方法均可以。

实现

class Solution {
public:
int smallestNumber(int n) {
return (1 << __lg(n) + 1) - 1;
}
};
class Solution:
def smallestNumber(self, n: int) -> int:
ans = 1
while ans < n:
ans = ans << 1 | 1
return ans

力扣每日一题1526-形成目标数组的子数组最少增加次数

日期:2025-10-30

题意

给定正整数数组 target 和等长的初始全为 0initial 数组,每次操作可任选 initial 中的子数组使其中元素均加 1 ,问使 initialtarget 相同的最小操作次数。

思路

贪心地想,每次操作应尽可能选择足够长的子数组,这样一想可以发现在全加几次后数组就会被最小的几个数断成了几个子数组,每个子数组的操作次数应该是其内的最大值。由此可以想到用个单调栈类似物记录某段的最大值,记录上一段的最小值,操作数即为该段最大值减去上段的最小。

到这一步又想到,这个栈似乎完全没有必要,使用一个双指针直接模拟记录就好。

然后又可以注意到,这个双指针其实也没太必要的,若该数大于等于前一数,需要多操作的次数即为该数与前一数之差;若该数小于前一数,该数即可不用操作。

实现

cpp 用栈

class Solution {
public:
int minNumberOperations(vector<int>& target) {
int n = target.size();
int last = 0;
int ans = 0;
vector<int> stk;
for (auto x : target) {
if (stk.empty() || x <= stk.back()) {
} else {
ans += stk.front() - last;
last = stk.back();
stk.clear();
}
stk.push_back(x);
}
if (!stk.empty()) ans += stk.front() - last;
return ans;
}
};

cpp 直接遍历

class Solution {
public:
int minNumberOperations(vector<int>& target) {
int n = target.size();
int ans = target.front();
for (int i = 1; i < n; i++) {
if (target[i] > target[i - 1]) ans += target[i] - target[i - 1];
}
return ans;
}
};

python 双指针

class Solution:
def minNumberOperations(self, target: List[int]) -> int:
ans = last = 0
l = 0
r = 1
while r < len(target):
if target[r] > target[r - 1]:
ans += target[l] - last
last = target[r - 1]
l = r
r += 1
ans += target[l] - last
return ans

力扣每日一题3289-数字小镇中的捣蛋鬼

日期:2025-10-31

题意

给定数组 nums ,其中包含从 0n - 1 的数,同时除两个数出现了两次外其余数均出现且仅出现一次。求出现两次的这两个数。

思路

数据范围很小很小 1 <= n <= 100 因此虽然有一个异或求解的方法,但还是直接进行一个哈希求解就好。

实现

class Solution {
public:
vector<int> getSneakyNumbers(vector<int>& nums) {
array<int, 101> cnt;
cnt.fill(0);
vector<int> ans;
for (auto x : nums) {
if (cnt[x]) ans.push_back(x);
cnt[x]++;
}
return ans;
}
};