LeetCode 每日一题 2026/3/30-2026/4/5

记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步


目录

      • [3/30 2840. 判断通过操作能否让字符串相等 II](#3/30 2840. 判断通过操作能否让字符串相等 II)
      • [3/31 3474. 字典序最小的生成字符串](#3/31 3474. 字典序最小的生成字符串)
      • [4/1 2751. 机器人碰撞](#4/1 2751. 机器人碰撞)
      • [4/2 3418. 机器人可以获得的最大金币数](#4/2 3418. 机器人可以获得的最大金币数)
      • [4/3 3661. 可以被机器人摧毁的最大墙壁数目](#4/3 3661. 可以被机器人摧毁的最大墙壁数目)
      • 4/4
      • 4/5

3/30 2840. 判断通过操作能否让字符串相等 II

奇数位偶数位分别统计

先遍历奇数位 记录s1中字符出现次数是否和s2相同 cnt1[x]记录字符x出现次数 在s1中+1 在s2中-1

再遍历偶数位 记录s1中字符出现次数是否和s2相同 cnt2同上

python 复制代码
def checkStrings(s1, s2):
    """
    :type s1: str
    :type s2: str
    :rtype: bool
    """
    cnt1 = [0]*26
    cnt2 = [0]*26
    for i in range(len(s1)):
        if i%2:
            cnt1[ord(s1[i])-ord('a')]+=1
            cnt1[ord(s2[i])-ord('a')]-=1
        else:
            cnt2[ord(s1[i])-ord('a')]+=1
            cnt2[ord(s2[i])-ord('a')]-=1
    return all(x==0 for x in cnt1) and all(x==0 for x in cnt2)

3/31 3474. 字典序最小的生成字符串

先处理T窗口的强制匹配

再处理F窗口: 若当前仍可能完全等于str2 则必须在该窗口内挑一个未强制位置改成不等字符

为保证字典序最小 每次优先改最靠右的位置

python 复制代码
def generateString(str1, str2):
    """
    :type str1: str
    :type str2: str
    :rtype: str
    """
    n, m = len(str1), len(str2)
    L = n + m - 1
    ans = ["?"] * L
    forced = [False] * L

    # 1) 先满足所有T窗口
    for i, flag in enumerate(str1):
        if flag != "T":
            continue
        for j in range(m):
            p = i + j
            c = str2[j]
            if ans[p] != "?" and ans[p] != c:
                return ""
            ans[p] = c
            forced[p] = True

    # 2) 未强制位置先填'a',得到当前字典序最小串
    for i in range(L):
        if ans[i] == "?":
            ans[i] = "a"

    # 3) 处理F窗口:仅当窗口刚好等于str2时,才在最右可改位改成'b'
    for i, flag in enumerate(str1):
        if flag != "F":
            continue
        ok = False
        for j in range(m):
            if ans[i + j] != str2[j]:
                ok = True
                break
        if ok:
            continue

        changed = False
        for j in range(m - 1, -1, -1):
            p = i + j
            if not forced[p]:
                ans[p] = "b"
                changed = True
                break
        if not changed:
            return ""

    res = "".join(ans)

    # 4) 最终校验
    for i, flag in enumerate(str1):
        sub = res[i:i + m]
        if (flag == "T" and sub != str2) or (flag == "F" and sub == str2):
            return ""
    return res

4/1 2751. 机器人碰撞

按位置从小到大处理 只会发生R与后续L的碰撞

用栈维护尚未碰撞掉的向右机器人(下标)

遇到L机器人时不断与栈顶R机器人对撞:

health大者减1并存活 health相等则同归于尽

python 复制代码
def survivedRobotsHealths(positions, healths, directions):
    """
    :type positions: List[int]
    :type healths: List[int]
    :type directions: str
    :rtype: List[int]
    """
    n = len(positions)
    ids = sorted(range(n), key=lambda i: positions[i])
    h = healths[:]
    alive = [True] * n
    stack = []

    for i in ids:
        if directions[i] == "R":
            stack.append(i)
            continue

        # 当前是L,尝试与之前的R碰撞
        while stack and alive[i]:
            j = stack[-1]
            if not alive[j]:
                stack.pop()
                continue

            if h[j] < h[i]:
                alive[j] = False
                h[i] -= 1
                stack.pop()
            elif h[j] > h[i]:
                alive[i] = False
                h[j] -= 1
            else:
                alive[j] = False
                alive[i] = False
                stack.pop()

    return [h[i] for i in range(n) if alive[i]]

4/2 3418. 机器人可以获得的最大金币数

迭代 DP:

dp[i][j][k] 表示走到(i,j)且已感化k次(0<=k<=2)时的最大金币。

每个格子两种选择:

  1. 不感化:加上 coins[i][j]
  2. 若 coins[i][j] < 0 且 k < 2,可感化:该格子按 0 计,并将感化次数 +1
python 复制代码
def maximumAmount(coins):
    """
    :type coins: List[List[int]]
    :rtype: int
    """
    m, n = len(coins), len(coins[0])
    NEG = -10**18

    # 仅保留上一行,空间 O(n*3)
    prev = [[NEG, NEG, NEG] for _ in range(n)]

    for i in range(m):
        cur = [[NEG, NEG, NEG] for _ in range(n)]
        for j in range(n):
            v = coins[i][j]

            in0 = in1 = in2 = NEG

            # 起点:进入起点前金币为0,感化次数为0
            if i == 0 and j == 0:
                in0 = 0

            # 来自上方
            if i > 0:
                up = prev[j]
                if up[0] > in0:
                    in0 = up[0]
                if up[1] > in1:
                    in1 = up[1]
                if up[2] > in2:
                    in2 = up[2]

            # 来自左方
            if j > 0:
                left = cur[j - 1]
                if left[0] > in0:
                    in0 = left[0]
                if left[1] > in1:
                    in1 = left[1]
                if left[2] > in2:
                    in2 = left[2]

            out = cur[j]

            # 不感化当前格子
            if in0 != NEG:
                out[0] = in0 + v
            if in1 != NEG:
                out[1] = in1 + v
            if in2 != NEG:
                out[2] = in2 + v

            # 感化当前负数格子:该格子记0,并消耗一次感化
            if v < 0:
                if in0 > out[1]:
                    out[1] = in0
                if in1 > out[2]:
                    out[2] = in1

        prev = cur

    end = prev[n - 1]
    return max(end[0], end[1], end[2])

4/3 3661. 可以被机器人摧毁的最大墙壁数目

1.先将机器人按位置排序,墙位置也排序,便于后续用二分统计区间内墙数。

2.每个机器人只能左射或右射。左射区间为 [x-d, x],但会被左侧最近机器人阻挡,

所以左端应修正为 max(x-d, prev_robot_x+1)

3 右射区间为 [x, x+d],会被右侧最近机器人阻挡。并且右侧机器人若选择左射,

还会额外占用一段左射程,因此要区分两种"右邻状态"。

4.设 dp(i, j):

i 表示处理到第 i 个机器人

j=0/1 表示右侧相邻机器人对应的状态(影响当前机器人右射上界)

转移时在"当前左射"和"当前右射"中取最大值。

5.区间墙数通过二分统计:

count([l, r]) = lower_bound(r+1) - lower_bound(l)。

6.用滚动变量迭代 DP(prev0, prev1)替代递归,避免递归深度问题。

python 复制代码
def maxWalls(robots, distance, walls):
    """
    :type robots: List[int]
    :type distance: List[int]
    :type walls: List[int]
    :rtype: int
    """
    from bisect import bisect_left

    n = len(robots)
    arr = sorted(zip(robots, distance))  # (位置, 射程)
    walls.sort()

    def count_in_range(l, r):
        if l > r:
            return 0
        return bisect_left(walls, r + 1) - bisect_left(walls, l)

    # prev0 = dfs(i-1, 0), prev1 = dfs(i-1, 1)
    # 其中 dfs(i, j) 表示处理到第 i 个机器人时,且"右侧相邻机器人方向状态"为 j 的最优值
    prev0 = 0
    prev1 = 0

    for i in range(n):
        x, d = arr[i]

        # 当前机器人向左射击,子弹会被左侧最近机器人阻挡
        left_l = x - d
        if i > 0:
            left_l = max(left_l, arr[i - 1][0] + 1)
        left_cnt = count_in_range(left_l, x)

        # 当前机器人向右射击,右端受右侧机器人影响
        # j = 0: 右侧相邻机器人向左,需额外避开其左射程
        # j = 1: 右侧相邻机器人向右,只需避开其位置
        right0 = x + d
        right1 = x + d
        if i + 1 < n:
            nx, nd = arr[i + 1]
            right0 = min(right0, nx - nd - 1)
            right1 = min(right1, nx - 1)

        right_cnt0 = count_in_range(x, right0)
        right_cnt1 = count_in_range(x, right1)

        cur0 = max(prev0 + left_cnt, prev1 + right_cnt0)
        cur1 = max(prev0 + left_cnt, prev1 + right_cnt1)
        prev0, prev1 = cur0, cur1

    return prev1

4/4

python 复制代码

4/5

python 复制代码

相关推荐
圣保罗的大教堂10 小时前
leetcode 3418. 机器人可以获得的最大金币数 中等
leetcode
workflower12 小时前
用硬件换时间”与“用算法降成本”之间的博弈
人工智能·算法·安全·集成测试·无人机·ai编程
重生之我是Java开发战士13 小时前
【动态规划】简单多状态dp问题:按摩师,打家劫舍,删除并获得点数,粉刷房子,买卖股票的最佳时机
算法·动态规划·哈希算法
KAU的云实验台14 小时前
单/多UAV、静/动态路径规划,基于PlatEMO平台的带约束多目标优化 本文核心内容:
算法·matlab·无人机
Liangwei Lin14 小时前
洛谷 P1807 最长路
数据结构·算法
会编程的土豆15 小时前
【数据结构与算法】二叉树从建立开始
数据结构·c++·算法
_日拱一卒15 小时前
LeetCode:最大子数组和
数据结构·算法·leetcode
计算机安禾15 小时前
【数据结构与算法】第22篇:线索二叉树(Threaded Binary Tree)
c语言·开发语言·数据结构·学习·算法·链表·visual studio code