[100天算法】-最长有效括号(day 38)

news2024/11/17 1:51:59

题目描述

给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。

示例 1:

输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"
示例 2:

输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-valid-parentheses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

方法 1:滑动窗口

思路

  1. 首先最短的有效括号字符串就是一对括号 (),那我们可以先在字符串 s 中找到这样一对括号。

  2. 然后,把这对括号作为一个滑动窗口的中心,分别向左右两侧扩大滑动窗口,窗口内是有效括号。

  3. 当滑动窗口不能再扩大时,把当前窗口的左右边界记录下来,然后,从这个窗口的右边界开始,重复步骤 1 到 3,直到字符串遍历结束。

  4. 等等,还漏了一种情况。当我们在扩大滑动窗口的时候,如果碰到了另一个窗口的边界,那这两个窗口加起来也是一个有效括号字符串。所以,我们得把这两个窗口作为新的滑动窗口中心,然后向两侧扩大窗口。

  5. 因为我们是从左往右遍历字符串,所以窗口相碰的情况只有一种,就是当前窗口的左边界碰到了前一个窗口的右边界,我们只要判断这种情况就行。

图解

代码

JavaScript Code

/**
 * @param {string} s
 * @return {number}
 */
var longestValidParentheses = function (s) {
    const expand = (s, l, r) => {
        while (s[l - 1] === '(' && s[r + 1] === ')') {
            l--;
            r++;
        }
        return [l, r];
    };

    const map = {};

    let l = 0,
        r = 0,
        max = 0;
    while (true) {
        // 以括号对为中心
        l = s.indexOf('()', r);
        if (l === -1) break;

        r = l + 1;
        // 向左右两边不断扩大滑动窗口
        [l, r] = expand(s, l, r);

        // 当窗口扩大到最大时,
        // 如果当前窗口的左边界刚好挨着前一个窗口的右边界,那么,
        // 合并这两个窗口,再以这个新合并的窗口为中心,向两侧扩大滑动窗口
        while (l - 1 in map) {
            [l, r] = expand(s, map[l - 1], r);
        }
        // 记录当前窗口的左右边界,key 是窗口右边界,value 是窗口左边界
        map[r] = l;
        // 更新最大窗口
        max = Math.max(max, r - l + 1);
    }

    return max;
};

复杂度分析

  • 时间复杂度:$O(n)$,n 为字符串的长度。
  • 空间复杂度:$O(n)$,n 为字符串的长度。

方法 2:动态规划

思路

我们可以用一个一维数组 dp 来记录 以当前坐标为结尾的有效括号字符串的长度是多少 这个状态。

关键是,怎么找到当前坐标的状态 dp[i] 跟 i 之前坐标的状态的依赖关系。

  • 如果当前坐标 i 是一个左括号 '(',很明显有效字符串不会以左括号为结尾,所以这个状态是 0;
  • 如果当前坐标 i 是一个右括号 ')',那么:
    • 如果它前一个 i - 1 是 '(',它们可以组成一对儿,那么 dp[i] 至少是 2
    • 如果它前一个 i - 1 是 ')',虽然它们不能成对儿,但是,')' 说明它可能是某个有效字符串的结尾,那我们就得检查这个坐标 i - 1 的状态了:
      • 如果 dp[i-1] 是 0,那就没戏了,dp[i] 也只能是 0 了
      • 如果 dp[i-1] > 0,那么,i 的前面有一段有效括号字符串,那只要判断这段字符串前面的那个字符是不是 ( 就好了,如果是,dp[i] = dp[i-1] + 2,如果不是,dp[i] = 0
    • 等等,还没有结束,如果到了这里,dp[i] 大于 0 的话,还有一种情况,跟滑动窗口解法里面的一样,它的左边可能还有一段紧挨着的有效括号字符串,所以我们得把这段字符串的长度也加到 dp[i] 中。

图解

代码

JavaScript Code

/**
 * @param {string} s
 * @return {number}
 */
var longestValidParentheses = function (s) {
    // 状态:以当前字符结尾的字符串,最长的有效括号长度是多大
    const dp = Array(s.length).fill(0);

    for (let i = 1; i < s.length; i++) {
        // 有效括号只能是以 ')' 结尾的
        // 所以,以 '(' 结尾的字符串,最长有效括号长度就是 0,不用管
        if (s[i] === ')') {
            // 遇到 ')' 时,往左边去找跟它匹配的 '(',如果存在,那么有效长度在 dp[i - 1] 基础上加 2

            // dp[i - 1] 是以 s[i - 1] 结尾的字符串的最长有效括号长度,设它为 k,
            // 也就是 [i - k, i - 1] 这段是有效括号字符串,
            // 如果这段字符串前面的那个字符 s[i - k - 1] 是 '(' 的话,那么有效长度加 2
            if (i - dp[i - 1] - 1 >= 0 && s[i - dp[i - 1] - 1] === '(') {
                dp[i] = dp[i - 1] + 2;

                // 如果匹配到的 '(' 前面还有有效长度的话,也加上
                if (i - dp[i - 1] - 2 > 0) {
                    dp[i] += dp[i - dp[i - 1] - 2];
                }
            }
        }
    }
    return Math.max(...dp, 0);
};

复杂度分析

  • 时间复杂度:$O(n)$,n 为字符串的长度。
  • 空间复杂度:$O(n)$,n 为字符串的长度。

方法 3:栈

思路

用一个栈来检查括号的有效性,用一个数组 valid 来记录匹配括号对的位置。

  • 栈的用法跟20.有效括号里的一样,不过入栈的不是 (,而是它们的下标。
  • 在遍历过程中,如果碰到 ),就从栈中弹出一个元素,这个元素就是 ) 对应的 ( 的下标。
  • 接着我们在 valid 中这两个下标对应的位置做个标识 1,说明这里找到了一对有效括号。
  • 等遍历结束之后,在 valid 中找到连续最长的 1 序列。

代码

JavaScript Code

/**
 * @param {string} s
 * @return {number}
 */
var longestValidParentheses = function (s) {
    const valid = Array(s.length).fill(0);
    const stack = [];

    for (let i = 0; i < s.length; i++) {
        if (s[i] === '(') stack.push(i);

        if (s[i] === ')' && stack.length > 0) {
            // Mark the open and close indices as 1 in valid.
            valid[i] = 1;
            valid[stack.pop()] = 1;
        }
    }

    // Find longest sequence of 1s.
    let count = 0,
        max = 0;
    for (let v of valid) {
        v && count++;
        v || (count = 0);
        count > max && (max = count);
    }
    return max;
};

复杂度分析

  • 时间复杂度:$O(n)$,n 为字符串的长度。
  • 空间复杂度:$O(n)$,n 为字符串的长度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1130210.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows与Linux服务器互传文件

使用winscp实现图形化拖动的方式互传文件. 1.下载winscp软件并安装&#xff0c;官方地址&#xff1a; https://winscp.net/eng/index.php 2.打开软件&#xff1a; 文件协议选择scp&#xff0c;输入linux服务器的IP和端口号&#xff0c;然后输入你的用户名和密码就可以登陆了。…

在nodejs中实现实时通信的几种方式

在nodejs中实现实时通信的几种方式 在当今世界中&#xff0c;实时通信至关重要。无论是聊天应用程序还是实时体育更新&#xff0c;实时通信都是保持用户活跃度所必需的。Node.js 因其速度、可扩展性和可靠性而成为开发实时应用程序的流行工具。在本文中&#xff0c;我们将探讨…

【学习笔记】记录一个win 11 操作文件卡顿,Windows 资源管理器CPU占用飙升问题

【学习笔记】记录一个win 11 操作文件卡顿&#xff0c;Windows 资源管理器CPU占用飙升问题 前段时间忽然发现电脑操作文件都会特别的卡&#xff0c;例如复制粘贴文件&#xff0c;写入文件等操作&#xff0c;卡的怀疑人生&#xff0c;原本以为是电脑太久没重启&#xff0c;重启…

如何将本地 PDF 文件进行翻译

在日常工作和学习中&#xff0c;我们经常会遇到需要翻译 PDF 文件的情况。比如&#xff0c;我们需要将一份英文的技术文档翻译成中文&#xff0c;或者将一份中文的法律文件翻译成英文。 传统上&#xff0c;我们可以使用专业翻译软件或服务来翻译 PDF 文件。但是&#xff0c;这…

【产品经理】APP备案(阿里云)

工信部《关于开展移动互联网应用程序备案工作的通知》 工业和信息化部印发了《关于开展移动互联网应用程序备案工作的通知》&#xff0c;“在中华人民共和国境内从事互联网信息服务的App主办者&#xff0c;应当依照相关法律法规等规定履行备案手续&#xff0c;未履行备案手续的…

Linux shell编程学习笔记15:定义数组、获取数组元素值和长度

一、 Linux shell 脚本编程中的数组概述 数组是一种常见的数据结构。跟大多数编程语言一样&#xff0c;大多数Linux shell脚本支持数组&#xff0c;但对数组的支持程度各不相同&#xff0c;比如数组的维度&#xff0c;是支持一维数组还是多维数组&#xff1f;再如&#xff0c;…

MongoDB 的集群架构与设计

一、前言 MongoDB 有三种集群架构模式&#xff0c;分别为主从复制&#xff08;Master-Slaver&#xff09;、副本集&#xff08;Replica Set&#xff09;和分片&#xff08;Sharding&#xff09;模式。 Master-Slaver 是一种主从复制的模式&#xff0c;目前已经不推荐使用。Re…

threejs(3)-详解材质与纹理

一、Matcap(MeshMatcapMaterial)材质原理与应用 Matcap是一张含有光照信息的贴图&#xff0c;通常是直接截取材质球截图来使用。因此Matcap可以很好的模拟静止光源下的光照效果。 最直接的方式就是直接使用在View空间下的模型法向量的xy分量去采样Matcap。 另外还有一种常见…

STM32F103单片机内部RTC实时时钟驱动程序

一、STM32f103系列RTC功能 RTC实时时钟功能是嵌入式软件开发中比较常用的功能&#xff0c;一般MCU的RTC功能都带有年月日时间寄存器&#xff0c;比如STM32F4xx系列&#xff0c;RTC描述如下&#xff1a; 可见F4系列的RTC功能比较强大&#xff0c;设置好初始时间后&#xff0c;读…

Power BI 傻瓜入门 8. 制作数据模型

本章内容包含&#xff1a; 描述不同的数据建模技术配置属性以满足数据模型要求设计模型以满足性能要求 您可能认为&#xff0c;通过Power BI对数据进行转换后&#xff0c;您将一帆风顺。在某些情况下&#xff0c;这是正确的。当然&#xff0c;当您创建了一个包含许多表的详细…

OpenCV 笔记(3):基本图形的绘制

Part11. 绘制简单的图形 绘图功能是 OpenCV 最基础的功能&#xff0c;OpenCV 提供了基础的绘制函数&#xff0c;用于帮助我们绘制一些基本的图形。通过这些函数的组合&#xff0c;我们也可以做一些高级的应用。 11.1 绘制点和圆 OpenCV 的绘制函数相对简单&#xff0c;而且很多…

[Unity]将所有 TGA、TIFF、PSD 和 BMP(可自定义)纹理转换为 PNG,以减小项目大小,而不会在 Unity 中造成任何质量损失

如何使用 只需在“项目”窗口中创建一个名为“编辑器”的文件夹&#xff0c;然后在其中添加此脚本即可。然后&#xff0c;打开窗口-Convert Textures to PNG&#xff0c;配置参数并点击“Convert to PNG&#xff01; ”。 就我而言&#xff0c;它已将某些 3D 资源的总文件大小…

C语言汇总

汇总一&#xff08;linux环境&#xff09; /bin &#xff1a;bin是二进制&#xff08;binary&#xff09;英文缩写。 /boot&#xff1a;存放的都是系统启动时要用到的程序。 /dev&#xff1a;包含了所有Linux系统中使用的外部设备。 /etc&#xff1a;存放了系统管理时要用到的…

uniapp中 background-image 设置背景图片不展示问题

有问题 <view class"file-picker__box jsz" tap"jszxszUpload(jsz)"></view>.jsz {background-image: url(../../static/example_drive.png); }解决1 <view class"file-picker__box jsz" :style"{ background-image: url(…

Android APP 隐藏系统软键盘的方法

1.场景描述&#xff1a; 1) APP项目中经常会开发自定义软键盘&#xff1b;同时在使用EditText时&#xff0c;也会常常遇到自动弹出系统自带的软键盘&#xff0c;与自定义的软键盘产生冲突的情况&#xff1b;此时需要禁止EditText自动弹出系统软键盘&#xff0c;从而使自定义的…

汽车电子专有名词与相应技术

1.EEA &#xff08;Electronic & Electrical Architecture 电子电气架构&#xff09; EEA在宏观上概括为物理架构与逻辑架构的结合&#xff0c;微观上通过众多电子元器件的协同配合&#xff0c;或集成式或分布式的系统级电子电气架构&#xff0c;具体详见专栏 新能源汽车电…

volatile 关键字有什么用?它的实现原理是什么?

volatile volatile是Java中的一个关键字&#xff0c;用于修饰变量&#xff0c;表示该变量是“易变的”&#xff08;Volatile&#xff09;。 volatile 关键字有两个作用&#xff1a; 可以保证在多线程环境下共享变量的可见性。 通过增加内存屏障防止多个指令之间的重排序。 可见…

【图结构从入门到应用】图的表示和遍历,图搜索算法详解与示例

1图的概念 图是一种非常常见的数据结构&#xff0c;用于表示对象之间的关系。在计算机科学中&#xff0c;有许多不同的图类型&#xff0c;包括有向图&#xff08;Directed Graph&#xff09;和无向图&#xff08;Undirected Graph&#xff09;。图通常由节点&#xff08;顶点&a…

vscode json文件添加注释报错

在vscode中创建json文件&#xff0c;想要注释一波时&#xff0c;发现报了个错&#xff1a;Comments are not permitted in JSON. (521)&#xff0c;意思是JSON中不允许注释 以下为解决方法&#xff1a; 在vscode的右下角中找到这个&#xff0c;点击 在出现的弹窗中输入json wit…

Python 自动化(十五)请求和响应

准备工作 将不同day下的代码分目录管理&#xff0c;方便后续复习查阅 (testenv) [rootlocalhost projects]# ls mysite1 (testenv) [rootlocalhost projects]# mkdir day01 day02 (testenv) [rootlocalhost projects]# cp -rf mysite1/ day01/ (testenv) [rootlocalhost proj…