有趣的找括号的练习题

270 阅读4分钟

今天又到了熟悉的刷题环节,最近可能是过年🧨有点懒了,好多东西都挤在了一起,好想多几个脑袋瓜和多几双手来帮帮我,哈哈。

最近看到了涉及到括号相关的算法题,就优先做了一些整理我怕一拖就拖没了。那么现在我们就开始进入正题:

20. 有效的括号

image.png

可能这道题并不是很难,我之前做会比较慢,可能是没有找到解题的具体思路;后来一直跟着大佬的教程去刷题,慢慢的也在学习解题的相关的思路:

可以从最简单的思路出发, 比如说我只需要去匹配一个 "()"应该怎么去做呢?

其实就是通过定一个变量left,有左括号呢,我们就去+1;遇到右括号了,我们就去-1; 等到结束后,我们去查看left是否等于0。 等于0就是说左右括号一一进行匹配了,那我们可以来试一试

// 两个()
var isVaild = function(s) {
    let left = 0;
    
    for (let i = 0; i < s.length; i++) {
        if (s[i] === '(') {
           left++;
        } else {
           left--;
        }
        // 因为是一一对应的关系
        if (left < 0) return false;
    }
    return left === 0
}

现在,我们来思考一下如果是多种括号的情况下,这种思路是否是可行的呢?

假设的是可行的,我们分别去定义left1, left2,left3, ...leftn,这种方案是否是合适的呢?我们其实可以通过刚才的思路和代码,去想一想利用什么样的数据结构也可以做到同样的效果呢?

我想试试的结构能不能解决问题,依次将左边的括号的进栈, 如果和右边的括号有匹配到的;那么我们就将其出栈。这样我们就只需要最后看一下栈中是否还有元素来看是否合法。

代码实现:

var isVaild = function(s) {
    // 定义栈
    let left = [];
    
    for (let i = 0; i< s.length; i++) {
        if (s[i] === "(" || s[i] === "[" || s[i] === "{") {
           left.push(s[i])
        } else {
             if (left.length && findTop(s[i]) === left[left.length-1]) {
                 left.pop();
             } else {
                return false;
             }
        }
    }
    
    return left.length === 0;
}
findTop(value) {
   if (value === '[') return ']';
   if (value === '{') return '}';
   return ')';
}

921. 使括号有效的最少添加

image.png

其实这道题,可以从上面的题解中得到一点思路就是说,()是需要一一匹配的;那么同样的 一个( 需要一个 ); 一个右括号呢,也需要一个左括号;我们能做的事情就是如何给它匹配上, 匹配上的个数不就是我们想要的答案嘛。

代码实现:

/**
 * @param {string} s
 * @return {number}
 */
var minAddToMakeValid = function(s) {

    let all_need = 0, right_need = 0;
    
    for (let i = 0; i < s.length; i++) {
        // 如果是左括号
        if (s[i] === '(') {
           // 需要一个右括号
           right_need++;
        }
        
        // 如果是右括号
        if (s[i] === ')' ) {
            // 就不需要 右括号了 这里是重要‼️
            right_need--;
            
            // 如果每次遍历 right_need都减1
            // 我们需要做两件事
            if (right_need === -1) {
               // 1 重置 right_need
               right_need = 0;
               // 2. 说明我需要左括号了
               left_need++;
            }
        }
    }
    
    return right_need + all_need;
}

其实这道题,我去书写代码的时候,只关注了一个变量right_need的变化:

首先,最开始的时候如果有遇到(的时候,我们肯定是需要 的;

那么如果我们没有遇到 呢?是不是就不需要 了呢? 没错是这样的。

比如说 ))此时我需要并不是左括号,而是右括号。

right_need === -1 的存在就是为了应对上面提到的情况,满足我们对的需求。

right_need + all_need 其实就已经很明显了, 需要将各自对于()的需求进

行计算,并返回最终的结果。

1541. 平衡括号字符串的最少插入次数

image.png

具体的实现思路和上面的题目是一致的,只不过需要注意的是两点:

  1. 一个左括号需要消耗点 2个右括号
  2. 右括号的数量必须时刻保持为偶数个

代码实现:

/**
 * @param {string} s
 * @return {number}
 */
var minInsertions = function(s) {
    // 核心思路之前的几乎是一样的
    // 只不过中间有一些处理的细节需要细细的斟酌一下
    
    let all_need = 0, right_need = 0;
    
    for (let i = 0; i < s.length; i++) {
        if (s[i] === "(") {
           right_need += 2;
           
           // 如果 right_need 不是偶数呢
           if (right_need % 2 === 1) {
               // 需要一个右括号
               all_need++;
               // 一个左括号需要两个右括号, 右括号必须为偶数
               right_need -= 1;
           }
        }
        
        
        if (s[i] === ")") {
           right_need--;
           
           if (right_need === -1) {
              // 说明是 ")"多了
              // 需要左括号了
              all_need++;
              // 消耗掉两个 右括号
              right_need = right_need + 2;
           }
        }
    }
    
    return all_need + right_need;
}
32. 最长有效括号

image.png

这道代码题实现的比较匆忙,可能是中午喝的酒还没有褪去,多少有点迷糊。有不正确的地方希望可以批评指正

代码实现:

/**
 * @param {string} s
 * @return {number}
 */
var longestValidParentheses = function(s) {
    // 使用到了 dp[i] 去存储每次的长度值
    let stack = [];
    let dp = new Array(s.length+1).fill(0);
    
    for (let i = 0; i < s.length; i++) {
        if (s[i] === '(') {
           stack.push(i);
            // dp[i+1]
            dp[i+1] = 0;
        } else {
        
            if (stack.length) {
                let left_index = stack.pop();
                let len = i - left_index + 1 + dp[left_index];
                dp[i+1] = len;
            } else {
                dp[i+1] = 0;
            }
        }
    } 
    
    // 结果
    let res = 0;
    for (let i = 0; i < dp.length; i++) {
        res = Math.max(res, dp[i])
    }
    return res;
}

今天的刷题任务暂时告一段落,我的肚子好像在叫,我去补充点能量了,明天见!!!

参考答案