代码随想录算法训练营第十一天 | 20. 有效的括号、1047. 删除字符串中的所有相邻重复项、150. 逆波兰表达式求值

91 阅读1分钟

20. 有效的括号

链接

题目链接

文章链接

第一想法

由于之前知道单调栈,所以这一道题立马想到了单调栈,用stack表示单调栈,如果是"{"、"["、"(",则存储在单调栈中,如果是右括号,则看stack的栈顶元素是否相匹配,不匹配则返回false,匹配则删除栈顶元素,代码如下:

function isValid(s: string): boolean {
  let stack:string[]=[]
  for(let i=0;i<s.length;i++){
    if(s[i]=='{'||s[i]=='['||s[i]=='(') stack.push(s[i])
    if(s[i]=='}'){
        if(stack[stack.length-1]=='{') stack.pop()
        else return false
    }
    if(s[i]==')'){
        if(stack[stack.length-1]=='(') stack.pop()
        else return false
    }
    if(s[i]==']'){
        if(stack[stack.length-1]=='[') stack.pop()
        else return false
    }
  }
  return stack.length===0 //这里不能直接是true 因为存在s为'['的情况
};

看完文章后的想法

文章的整体思路和我的类似,但是比我的细,而且stack存储的是右括号,我存储的是左括号,括号不匹配总共分为三种情况: 1.第一种情况,字符串里左方向的括号多余了,所以不匹配。

image.png

2.第二种情况,括号没有多余,但是括号的类型没有匹配上

image.png

3.第三种情况,字符串里右方向的括号多余了,所以不匹配

image.png PS:图片来源于代码随想录 代码随想录中解决这三种情况的动态图: 代码随想录 下面是一种优化的版本:

function isValid(s: string): boolean {
  let stack:string[]=[]
  type stackMap={
      [key:string]:string
  }
  let stackmap:stackMap={
      '{':'}',
      '[':']',
      '(':')',
  }
  for(let value of s){
      if(stackmap.hasOwnProperty(value)){
          stack.push(stackmap[value])
      }else if(stack?.[stack.length-1]==value) stack.pop()
      else return false
  }
  return stack.length===0
};

思考

这道题整体不难,但是优化版本不好想,需要多次回顾。同时面对括号问题要首先想到利用单调栈来解决问题。

1047. 删除字符串中的所有相邻重复项

链接

题目链接

文章链接

第一想法

删除相邻重复的字母,这道题通过它的讲解不难看出是利用单调栈,如果栈顶元素和当前元素相同则删除栈顶元素,否则就加入栈中,最终栈中剩余的字母就是所求结果,代码如下:

function removeDuplicates(s: string): string {
 let stack:string[]=[]
 for(let value of s){
     if(value==stack[stack.length-1]){
         stack.pop()
     }else stack.push(value)
 }
 return stack.join("")
};

看完文章后的想法

代码随想录中的解题思路与我的思路很类似,下面是代码随想录中的动态图,帮助理解:

下面是双指针的解法,一个指向栈顶,一个指向s字符串,代码如下:

function removeDuplicates(s: string): string {
 let stack:string[]=[]
 let top:number=-1 //指向栈顶
 for(let i=0;i<s.length;i++){
     if(top==-1||stack[top]!=s[i]) stack[++top]=s[i];
     else {
         stack.pop() 
         top-- //这里要-- 是因为下标要回退
     }
 }
 return stack.join("")
};

思考

这道题也是利用单调栈来解决问题的,思路不难,主要是会模拟过程图就可以了,同时双指针的写法没想到,但是双指针的写法一定要把top指针想清楚,因为删除相邻相同的字母时top要回退

150. 逆波兰表达式求值

链接

文章链接

题目链接

第一想法

还是单调栈,如果进入的数字则直接进入,如果是运算符号,则取出栈顶的两个元素进行运算,逆波兰表达式一般都用单调栈求解,代码如下:

function evalRPN(tokens: string[]): number {
  let stack:number[]=[]
  for(let s of tokens){
      if(!isNaN(Number(s))){
          stack.push(Number(s))
      }else{
          let num1:number=stack.pop()!
          let num2:number=stack.pop()!
          if(s=='*') stack.push(num1*num2);
          if(s=='/') stack.push(~~(num2/num1));
          if(s=='+') stack.push(num1+num2);
          if(s=='-') stack.push(num2-num1);
      }
  }
  return stack[0]
};

看完文章后的想法

文章的想法和我的想法完全一致,所以不再多赘述,代码随想录中有张图片很好的可以表达这个过程:

代码随想录 ts还有一种高级的写法:

function evalRPN(tokens: string[]): number {
  let stack:number[]=[]
  let map:Map<string,(a:number,b:number)=>number>=new Map([
      ['*',(a,b)=>a*b],
      ['/',(a,b)=>Math.trunc(a/b)],
      ['+',(a,b)=>a+b],
      ['-',(a,b)=>a-b],
  ])
  for(let s of tokens){
      if(!isNaN(Number(s))){
          stack.push(Number(s))
      }else{
          let num1:number=stack.pop()!
          let num2:number=stack.pop()!
          //看清除数与被除数
          stack.push(map.get(s)!(num2,num1))
      }
  }
  return stack[0]
};

思考

这道题不难,用单调栈很容易就解出答案,但是有个细节要知道,那个是除数哪个是被除数,但是ts的高级写法看完才懂,自己是写不出来的。

总结

今天是大年初四,哈哈哈哈还在国内,多余的就不说了,今年的题都是可以用单调栈解决的,由于之前了解过,所以比较容易上手。今日学习2小时。