力扣10.12

2267. 检查是否有合法括号字符串路径

题目链接

一个括号字符串是一个 非空 且只包含 和 的字符串。如果下面 任意 条件为 真 ,那么这个括号字符串就是 合法的 。'('')'

字符串是 。()

字符串可以表示为 连接, 和 都是合法括号序列。AB``A``B``A``B

字符串可以表示为 ,其中 是合法括号序列。(A)A

给你一个 的括号网格图矩阵 。网格图中一个 合法括号路径 是满足以下所有条件的一条路径:m x ngrid

路径开始于左上角格子 。(0, 0)

路径结束于右下角格子 。(m - 1, n - 1)

路径每次只会向 下 或者向 右 移动。

路径经过的格子组成的括号字符串是 合法 的。

如果网格图中存在一条 合法括号路径 ,请返回 ,否则返回 。true``false

数据范围

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 100
  • grid[i][j] 要么是 ,要么是 。'('')'

分析

记忆化搜索+剪枝,dfs传入的参数为当前位置坐标(x,y)和此时左括号和右括号的差值c,只有在终点且c==0才满足条件,有几个优化,首先c不能小于0(否则就说明左括号比右括号少,必然不成立),n+m-1必须为偶数,否则差值不可能为偶数

代码

c 复制代码
class Solution {
public:
    const static int N = 105;
    int dp[N][N][N];
    int dx[2] = {0, 1};
    int dy[2] = {1, 0};
    int n, m;
    int dfs(int x, int y, vector<vector<char>>& grid, int c) {
        if(x < 0 || y < 0 || x >= n || y >= m) return 0;
        if(grid[x][y] == '(') c ++ ;
        else c -- ;
        if(c < 0) return 0;
        int &t = dp[x][y][c];
        if(t != -1) return t;
        if(x == n - 1 && y == m - 1) {
            if(c == 0) return t = 1;
            else return t = 0;
        }
        t = 0;
        for(int i = 0; i < 2; i ++ ) {
            int nx = x + dx[i];
            int ny = y + dy[i];
            if(dfs(nx, ny, grid ,c)) t = 1; 
        }
        return t;
    }
    bool hasValidPath(vector<vector<char>>& grid) {
        n = grid.size();
        m = grid[0].size();
        for(int i = 0; i < n; i ++ ) {
            for(int j = 0; j < m; j ++ ) {
                for(int k = 0; k <= (n + m) / 2; k ++ ) {
                    dp[i][j][k] = -1;
                }
            }
        }
        if((n + m - 1) % 2) return false;
        if(grid[0][0] == ')') return false;
        int res = dfs(0, 0, grid, 0);
        return res;
    }
};

1937. 扣分后的最大得分

给你一个 m x n 的整数矩阵 points (下标从 0 开始)。一开始你的得分为 0 ,你想最大化从矩阵中得到的分数。

你的得分方式为:每一行 中选取一个格子,选中坐标为 (r, c) 的格子会给你的总得分 增加 points[r][c]

然而,相邻行之间被选中的格子如果隔得太远,你会失去一些得分。对于相邻行 rr + 1 (其中 0 <= r < m - 1),选中坐标为 (r, c1)(r + 1, c2) 的格子,你的总得分 减少 abs(c1 - c2)

请你返回你能得到的 最大 得分。

abs(x) 定义为:

如果 x >= 0 ,那么值为 x

如果 x < 0 ,那么值为-x

数据范围

  • m == points.length
  • n == points[r].length
  • 1 <= m, n <= 105
  • 1 <= m * n <= 105
  • 0 <= points[r][c] <= 105

分析

令dpij表示选择pointsij的最大得分,暴力枚举上一行的所有列k,则

  • d p i j = d p i − 1 k + p o i n t s i j − ∣ k − j ∣ dpij=dpi-1k+pointsij-|k-j| dpij=dpi−1k+pointsij−∣k−j∣
    但是这样子时间复杂度为 O ( n m 2 ) O(nm^2) O(nm2),会超时,得考虑优化
    我们去掉绝对值
  • d p i j = { p o i n t s i j + m a x ( d p i − 1 k ) − ( j − k ) , k ≤ j p o i n t s i j + m a x ( d p i − 1 k ) − ( k − j ) , k > j dpij=\begin{cases} pointsij+max(dpi-1k)-(j-k),k\le j \\ pointsij+max(dpi-1k)-(k-j),k\gt j \end{cases} dpij={pointsij+max(dpi−1k)−(j−k),k≤jpointsij+max(dpi−1k)−(k−j),k>j

在提出 j j j

  • d p i j = { p o i n t s i j − j + m a x ( d p i − 1 k ) + k ) , k ≤ j p o i n t s i j + j + m a x ( d p i − 1 k ) − k , k > j dpij=\begin{cases} pointsij - j +max(dpi-1k) + k),k\le j \\ pointsij + j +max(dpi-1k)- k,k\gt j \end{cases} dpij={pointsij−j+max(dpi−1k)+k),k≤jpointsij+j+max(dpi−1k)−k,k>j

此时可以考虑优化了,只要找到一行中 j j j左边 d p i − 1 k + k dpi-1k+k dpi−1k+k的最大值和 j j j右边 d p i − 1 k − k dpi-1k-k dpi−1k−k的最大值,这个可以用两个一维数组表示,

  • m a x x 1 j maxx1j maxx1j表示 j j j左边 d p i − 1 k + k dpi-1k+k dpi−1k+k的最大值
  • 同理可以定义 m a x x 2 j maxx2j maxx2j

这两个数组可以在计算完每行的 d p i dpi dpi进行处理,初始化处理 m a x x 1 j = j , m a x x 2 j = − j maxx1j=j,maxx2j=-j maxx1j=j,maxx2j=−j

此时状态转移就变成了这样

  • d p i j = m a x ( p o i n t s i j − j + m a x x 1 j , p o i n t s i j + j + m a x x 2 j ) dpij=max(pointsij - j +maxx1j, pointsij + j +maxx2j) dpij=max(pointsij−j+maxx1j,pointsij+j+maxx2j)

注意:处理maxx2时需要从大到小遍历

代码

c 复制代码
typedef long long LL;
class Solution {
public:
    int n, m;
    const static int N = 1e5 + 5;
    LL maxx1[N], maxx2[N];
    LL maxPoints(vector<vector<int>>& points) {
        n = points.size();
        m = points[0].size();
        vector<vector<LL>> dp(n + 1);
        for(int i = 1; i <= n; i ++ ) {
            dp[i].resize(m + 1);
        }
        LL res = 0;
        for(int j = 1; j <= m; j ++ ) {
            maxx1[j] = dp[1][j] + j;
            maxx2[j] = dp[1][j] - j;
        }

        for(int i = 1; i <= n; i ++ ) {
            for(int j = 1; j <= m; j ++ ) {
                dp[i][j] = max(points[i - 1][j - 1] - j + maxx1[j], points[i - 1][j - 1] + j + maxx2[j]);
                res = max(res, dp[i][j]);
            }
            LL tmax = LLONG_MIN;
            for(int j = 1; j <= m; j ++ ) {
                tmax = max(tmax, dp[i][j] + j);
                maxx1[j] = tmax;
            }
            tmax = LLONG_MIN;
            for(int j = m; j >= 1; j -- ) {
                tmax = max(tmax, dp[i][j] - j);
                maxx2[j] = tmax;
            }
        }
        return res;
    }
    
};
相关推荐
KaMeidebaby6 小时前
卡梅德生物技术快报|组蛋白乙酰化修饰调控动脉粥样硬化的分子机制及中药表观干预研究
网络·人工智能·网络协议·tcp/ip·算法
Fms_Sa6 小时前
分治法—最大子段问题
算法·c#
Galerkin码农选手6 小时前
awq_marlin和gptq_marlin量化算法简要介绍
算法
buhuizhiyuci6 小时前
【算法篇】动态规划——斐波那契数列模型
算法·动态规划
棱镜研途6 小时前
学习笔记丨模式识别与机器学习5大核心赛道解析(IC-IPPR 2026)
人工智能·神经网络·算法·机器学习·模式识别·学术会议·智能计算
SuperHeroWu76 小时前
【算法】逻辑回归虽然名字中有“回归“,但通常用于二分类任务。如何理解学习?
算法·回归·逻辑回归·二分类任务
gCode Teacher 格码致知6 小时前
Python教学:十六进制编码的显示方法-由Deepseek产生
开发语言·python·算法
05候补工程师6 小时前
【408数据结构】核心考点:图(Graph)精炼笔记与算法直觉
数据结构·经验分享·笔记·考研·算法·图论
靠沿6 小时前
【动态规划算法】专题三——简单多状态dp问题
算法·动态规划
吃好睡好便好6 小时前
矩阵秩的计算
人工智能·学习·线性代数·算法·机器学习·matlab·矩阵