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

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


目录

      • [4/27 1391. 检查网格中是否存在有效路径](#4/27 1391. 检查网格中是否存在有效路径)
      • [4/28 2033. 获取单值网格的最小操作数](#4/28 2033. 获取单值网格的最小操作数)
      • [4/29 3225. 网格图操作后的最大分数](#4/29 3225. 网格图操作后的最大分数)
      • [4/30 3742. 网格中得分最大的路径](#4/30 3742. 网格中得分最大的路径)
      • 5/1
      • 5/2
      • 5/3

4/27 1391. 检查网格中是否存在有效路径

1 每种街道类型对应可走的方向集合。

2 从 (0, 0) 开始 BFS,尝试走到相邻格子 (nx, ny)。

3 只有当"当前格子可朝该方向走"且"相邻格子可从反方向接入"时,这一步才合法。

4 BFS 过程中若到达右下角,返回 True;遍历结束仍未到达则返回 False。

python 复制代码
def hasValidPath(grid):
    """
    :type grid: List[List[int]]
    :rtype: bool
    """
    n, m = len(grid), len(grid[0])
    if n == 1 and m == 1:
        return True

    # 方向编码:0=上, 1=右, 2=下, 3=左
    dirs = [(-1, 0), (0, 1), (1, 0), (0, -1)]
    opposite = [2, 3, 0, 1]

    # 每种街道可连接的方向
    street = {
        1: {1, 3},  # 左右
        2: {0, 2},  # 上下
        3: {3, 2},  # 左下
        4: {1, 2},  # 右下
        5: {3, 0},  # 左上
        6: {1, 0},  # 右上
    }

    from collections import deque

    q = deque([(0, 0)])
    vis = {(0, 0)}

    while q:
        x, y = q.popleft()
        if x == n - 1 and y == m - 1:
            return True

        t = grid[x][y]
        for d in street[t]:
            dx, dy = dirs[d]
            nx, ny = x + dx, y + dy
            if nx < 0 or nx >= n or ny < 0 or ny >= m:
                continue

            nt = grid[nx][ny]
            if opposite[d] not in street[nt]:
                continue

            if (nx, ny) not in vis:
                vis.add((nx, ny))
                q.append((nx, ny))

    return False

4/28 2033. 获取单值网格的最小操作数

将所有数对 x 取模必须一致,否则不可能通过 ±x 变成同一个值

将数组排序 取中位数 计算每个数与中位数的差值 除以x 即为操作数

python 复制代码
def minOperations(grid, x):
    """
    :type grid: List[List[int]]
    :type x: int
    :rtype: int
    """
    nums = [num for row in grid for num in row]

    mod = nums[0] % x
    for num in nums:
        if num % x != mod:
            return -1

    nums.sort()
    target = nums[len(nums) // 2] 

    ops = 0
    for num in nums:
        ops += abs(num - target) // x
    return ops

4/29 3225. 网格图操作后的最大分数

把每一列最终被染黑的深度记为 d[j](取值 0...n,表示该列前 d[j] 个格子是黑色)。

一个白格能计分,当且仅当它左右有黑格。按列转移时,只和相邻列深度关系有关。

设列前缀和 prefix[j][k] 表示第 j 列前 k 个数之和,可求一段贡献。

状态压缩 DP(按列推进):

prev_pick[x]:处理到前一列时,前一列深度为 x 的最大分数(当前列会"拿"与前一列比较产生的贡献)。

prev_skip[x]:处理到前一列时,前一列深度为 x 的最大分数(当前列不拿这部分贡献,留给下一次比较)。

转移当前列深度 curr,枚举前一列深度 prev:

1 curr > prev:

说明上一列有区间 [prev, curr) 在本列更深时可形成横向相邻黑白,贡献来自第 j-1 列该段。

2 curr <= prev:

说明当前列有区间 [curr, prev) 在前一列更深时可形成贡献,来自第 j 列该段。

python 复制代码
def maximumScore(grid):
    """
    :type grid: List[List[int]]
    :rtype: int
    """
    n = len(grid)

    # prefix[j][k] = 第 j 列前 k 个元素和(k 从 0 到 n)
    prefix = [[0] * (n + 1) for _ in range(n)]
    for j in range(n):
        for i in range(n):
            prefix[j][i + 1] = prefix[j][i] + grid[i][j]

    prev_pick = [0] * (n + 1)
    prev_skip = [0] * (n + 1)

    for j in range(1, n):
        curr_pick = [0] * (n + 1)
        curr_skip = [0] * (n + 1)

        for curr in range(n + 1):
            for prev in range(n + 1):
                if curr > prev:
                    score = prefix[j - 1][curr] - prefix[j - 1][prev]
                    val = prev_skip[prev] + score
                    if val > curr_pick[curr]:
                        curr_pick[curr] = val
                    if val > curr_skip[curr]:
                        curr_skip[curr] = val
                else:
                    score = prefix[j][prev] - prefix[j][curr]
                    val_pick = prev_pick[prev] + score
                    if val_pick > curr_pick[curr]:
                        curr_pick[curr] = val_pick
                    if prev_pick[prev] > curr_skip[curr]:
                        curr_skip[curr] = prev_pick[prev]

        prev_pick = curr_pick
        prev_skip = curr_skip

    return max(prev_pick)

4/30 3742. 网格中得分最大的路径

从 (0,0) 走到 (m-1,n-1),每个格子既有得分也有花费:

0 -> 得分0 花费0

1 -> 得分1 花费1

2 -> 得分2 花费1

要求总花费 <= k 时路径得分最大。

定义 dp[i][j][c]:到达 (i,j) 且总花费恰好为 c 时的最大得分。

转移来自上方或左方,当前格子的花费是 cost(值为 0 时 cost=0,否则 cost=1):

dp[i][j][c] = max(dp[i-1][j][c-cost], dp[i][j-1][c-cost]) + grid[i][j]

起点 (0,0) 特殊:dp[0][0][0] = 0(题目保证 grid[0][0]=0)。

直接开三维数组会占用 O(mn k) 空间,容易 MLE。

由于第 i 行只依赖第 i-1 行和当前行左侧,因此可做滚动优化:

prev[j][c] 表示上一行,curr[j][c] 表示当前行,空间降为 O(nk)。
时间复杂度 O(m
nk),空间复杂度 O(nk)。

python 复制代码
def maxPathScore(grid, k):
    """
    :type grid: List[List[int]]
    :type k: int
    :rtype: int
    """
    m, n = len(grid), len(grid[0])
    neg_inf = -10 ** 15

    prev = [[neg_inf] * (k + 1) for _ in range(n)]

    for i in range(m):
        curr = [[neg_inf] * (k + 1) for _ in range(n)]
        for j in range(n):
            if i == 0 and j == 0:
                curr[0][0] = 0
                continue

            val = grid[i][j]
            cost = 1 if val > 0 else 0

            up = prev[j] if i > 0 else None
            left = curr[j - 1] if j > 0 else None

            for c in range(cost, k + 1):
                best = neg_inf
                pre_c = c - cost
                if up is not None and up[pre_c] > best:
                    best = up[pre_c]
                if left is not None and left[pre_c] > best:
                    best = left[pre_c]
                if best != neg_inf:
                    curr[j][c] = best + val

        prev = curr

    ans = max(prev[n - 1])
    return -1 if ans < 0 else ans

5/1

python 复制代码

5/2

python 复制代码

5/3

python 复制代码

相关推荐
穿越临界点6 小时前
动态规划(DP)
算法·动态规划·贝尔曼
leoufung6 小时前
LeetCode 50. Pow(x, n):从 O(n) 到 O(log n) 的快速幂彻底搞懂
算法·leetcode·职场和发展
@小码农6 小时前
2026年信息素养大赛【星火征途】图形化编程复赛和决赛模拟题B
开发语言·数据结构·c++·算法
人道领域7 小时前
【LeetCode刷题日记】347.前k个高频元素
java·数据结构·算法·leetcode
七颗糖很甜7 小时前
台风数据免费获取教程
大数据·python·算法
AI科技星7 小时前
《全域数学》第一部·数术本源
算法·机器学习·数学建模·数据挖掘·量子计算
阿Y加油吧7 小时前
二刷 LeetCode:118. 杨辉三角 & 198. 打家劫舍 复盘笔记
笔记·算法·leetcode
深邃-7 小时前
【数据结构与算法】-二叉树(1):树的概念与结构,二叉树的概念与结构
数据结构·算法·链表·二叉树··顺序表
风筝在晴天搁浅7 小时前
手撕归并排序
数据结构·算法·排序算法