LeetCode每日十题---栈(难度:简单)

题目描述1

在这里插入图片描述

笔者解答1.1

在这里插入图片描述

笔者分析1.2

虽然执行结果通过了,但看到执行用时和内存消耗,真是有点头疼。想了想,这次刷的是栈,但自己根本没有用到栈,看了些大佬们的解法,做了些总结,呃。。。好像都差不多。。。(过)。

题目描述2

在这里插入图片描述

笔者解答2.1

class Solution {
    public int calPoints(String[] ops) {
      int i;
       int score=0;
       int last_get=0;
       int last_get2=0;
       int last_score=0;
       int last_score2=0;
       int last_score3=0;
       for(i=0;i<ops.length;i++){
           last_get=score-last_score;
           last_get2=last_score-last_score2;
          if(ops[i].equals("+"))
           {
               last_score3=last_score2;
               last_score2=last_score;
               last_score=score;
               score+=(last_get+last_get2);
           }else if(ops[i].equals("D"))
           {
               last_score3=last_score2;
                last_score2=last_score;
                last_score=score;
                score+=(last_get*2);
           }else if(ops[i].equals("C"))
           {
                score=last_score;
                last_score=last_score2;
                last_score2=last_score3;
           }
           else
           {
               int num2 = Integer.parseInt(ops[i]);
               last_score3=last_score2;
               last_score2=last_score;
               last_score=score;
               score+=num2;
           }
       }
       return score;
    }
}

笔者分析2.2

着实是很菜啊,这题只过了题目里的两个案例,而且写的还那么复杂。看了些大佬们的解法,思路和我的完全不同,很简洁。他们并不是存储每次的总分,而是存储每次得到的分数,最后求和来算总分,这比我每次都要通过计算上次获得的分数简单多了,而且他们的方法可以存储每次的得分,而我的只能是近几次的,肯定是通过不了的。下面给出大佬们的解法。还有,千万别急着写代码,一定要理清思路,更别曲解题目意思。

class Solution {
    public int calPoints(String[] ops) {
     int[] arr = new int[ops.length];
        int i=0;
        for(String s:ops){
            switch (s){
                case "+":arr[i]=arr[i-1]+arr[i-2];i++;break;
                case "D":arr[i]=2*arr[i-1];i++;break;
                case "C":arr[i-1]=0;i--;break;
                default:
                    arr[i]=Integer.valueOf(s);
                    i++;
            }
        }
        int sum=0;
        for (int j = 0; j <arr.length ; j++) {
            sum+=arr[j];
        }
        return sum;
    }
}

题目描述3

在这里插入图片描述

笔者解答3.1

class CQueue{
    LinkedList<Integer> stack1;
    LinkedList<Integer> stack2;
    public CQueue()
    {
        stack1=new LinkedList<>();
        stack2=new LinkedList<>();
    }
    public void appendTail(int value)
    {
        stack1.add(value);
    }
    public int deleteHead()
    {
        if(stack2.isEmpty())
        {
            if(stack1.isEmpty())return -1;
            while(!stack1.isEmpty())
            {
                stack2.add(stack1.pop());
            }
            return stack2.pop();
        }else return stack2.pop();
    }

}

笔者分析3.2

基本思想是用两个栈,其中一个用于存储数据即入队,另一个栈用于输出数据即出队,两个栈的关系是将栈A的数据以出栈的方式存入栈B,这样两个栈内的内容顺序便完全相反。

题目描述4

在这里插入图片描述

笔者解答4.1

class MinStack {
    LinkedList<Integer> stack;
    int min;
    int top;
    /** initialize your data structure here. */
    public MinStack() {
          stack=new LinkedList<>();
    }

    public void push(int x) {
        if(stack.isEmpty())
        {
            stack.add(x);
            min=x;
            top=x;
        }
        else
        {
            stack.add(x);
            if(x>top)top=x;
            if(x<min)min=x;
        }
    }
    public void pop() {
       int x= stack.pop();
    }

    public int top() {
         return top;
    }

    public int min() {
        return min;
    }
}

笔者分析4.2

时间复杂度为O(1),第一次插入元素时,显然该元素为最小值,之后每次插入一个元素都和当前最小值比较,更新最小值。但是,笔者的写法有些问题,就是当栈内弹出元素时,栈中的最小值并未更新,而如果说保存最小值和第二小的值,那么如果连续弹出几个元素,依然不奏效。这里遇到的问题是,如何保存每次的最小值,单从这一点和上面第二题类似。首先我们应该摆脱这样一个思维,链表不仅仅可以保存它自身的值和它下一个结点的值,又或者说上一个结点的值,它还可以保存任何你需要的数据,包括这题中的最小值。所以我们定义链表结构的时候,还应该多加一个最小值的数据,即从头结点到当前结点为止,最小值是多少,从而能够实现时间复杂度为O(1)的查询最小值,下面给出代码。

class MinStack {
   private Node head;
    /** initialize your data structure here. */
    public MinStack() {
    }

    public void push(int x) {
      if(head==null)
          head=new Node(x,x,null);
      else
          head=new Node(x,Math.min(head.min,x),head);
    }
    public void pop() {
      head=head.next;
    }

    public int top() {
      return head.val;
    }

    public int min() {
       return head.min;
    }
    private class Node{
        int val;
        int min;
        Node next;
        public Node(int val, int min,Node next){
            this.val=val;
            this.min=min;
            this.next=next;
        }
    }
}

题目描述5

在这里插入图片描述

笔者解答5.1

class Solution {
    public boolean isValid(String s) {
      LinkedList<Character> stack=new LinkedList<>();
      for(int i=0;i<s.length();i++)
      {
          if(s.charAt(i)=='(')stack.push('(');
          if(s.charAt(i)=='[')stack.push('[');
          if(s.charAt(i)=='{')stack.push('{');
          if(s.charAt(i)==')'){
               if(stack.isEmpty()) return false;
             char c= stack.pop();
             if(c!='(')return false;
          }
          if(s.charAt(i)==']'){
               if(stack.isEmpty()) return false;
              Character c= stack.pop();
              if(c!='[')return false;
          }
          if(s.charAt(i)=='}'){
               if(stack.isEmpty()) return false;
              char c= stack.pop();
              if(c!='{')return false;
          }
      }
      if(stack.isEmpty())return true;
      else return false;
    }
}

笔者分析5.2

看到大佬们的解答,越发觉得自己的代码不忍直视,他们的解法真的太巧妙了,而自己的只是普通的不能再普通了。下面分析一下大佬们的思路。记住,尽管传入的是一串字符,但只要能够实现统一功能,并非一定要存入原字符串,可适当变形。同时如果可以逆序解决的问题,顺序一样能解决,可能还会方便不少。

class Solution {
    public boolean isValid(String s) {
        Stack<Character>stack = new Stack<Character>();
        for(char c: s.toCharArray()){
            if(c=='(')stack.push(')');
            else if(c=='[')stack.push(']');
            else if(c=='{')stack.push('}');
            else if(stack.isEmpty()||c!=stack.pop())return false;
            //如果一开始就是"]",")","}"符号的话,显然不成立,这是stack.isEmpty为真,返回false;
            //否则,存入当前符号的匹配字符,判断下一个存入的字符是否相等,当然也可以存入下一个字符,判断前一个字符是否匹
            //配,只不过,这样会麻烦许多,总之很巧妙吧
        }
        return stack.isEmpty();
    }
}

题目描述6

在这里插入图片描述

笔者解答6.1

在这里插入图片描述

笔者分析6.2

虽然说方法用的不是太复杂,思路也还行,但是这执行用时和内存消耗也太大了,应该是substring捣的鬼。

题目描述7

在这里插入图片描述

笔者解答7.1

class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
         int[] compare=new int[nums1.length];
         for(int i=0;i<nums1.length;i++)
         {
             int a=nums1[i];
             boolean get=false;
             for(int j=0;j<nums2.length;j++)
             {
                if(nums2[j]==a)
                {
                   get=true;
                }
                if(get&&nums2[j]>a)
                {
                    compare[i]=nums2[j];break;
                }
                if(j==nums2.length-1)
                {
                    compare[i]=-1;break;
                }
             }
         }
         return compare;
    }
}

笔者分析7.2

自认为时间复杂度较高,但看了下数据貌似还行,但内存消耗有点大。

题目描述8

在这里插入图片描述

笔者解答8.2

class Solution {
    public String removeDuplicates(String S) {
       Stack<Character> stack=new Stack<Character>();
       int length=0;
       for(int i=0;i<S.length();i++)
       {
           if(stack.isEmpty()||stack.peek()!=S.charAt(i))
           {
               stack.push(S.charAt(i));
               length++;
           }
           else
           {
               if(stack.peek()==S.charAt(i))
               {
                   stack.pop();
                   length--;
               }
           }
       }
       char[] array=new char[length];
       int i=length-1;
       while(!stack.isEmpty())
       {
          array[i]=stack.pop();
          i--;
       }
       String s = String.valueOf(array);
       return s;
    }
}

笔者分析8.3

这其实就是栈的一个典型应用,每次入栈时都与栈顶元素比较,若相同,则将栈顶元素弹出,若不相同则入栈。只不过最后有一个小问题,因为栈是先进后出的,如果直接输出栈的话,它字符顺序是完全相反的,所以多了一步将栈中的数据元素存入一个新的数组,带来的问题是占用了更多的内存。其它方法也都大同小异。

题目描述9

在这里插入图片描述

笔者解答9.1

class Solution {
    public List<String> buildArray(int[] target, int n) {
        List<String> list=new ArrayList<String>();
        for(int i=0;i<target.length;i++){
            if(i==0)
            {
                int c=target[i];
                while(c>1){
                    list.add("Push");
                    list.add("Pop");
                    c--;
                }
                if(c==1)
                    list.add("Push");
            }else
            {
                int c=target[i]-target[i-1];
                while(c>1){
                    list.add("Push");
                    list.add("Pop");
                    c--;
                }
                if(c==1)
                    list.add("Push"); 
            }
        }
        return list;
    }
}

笔者分析9.2

这次的执行用时很客观,超过了百分之百的用户,但内存消耗属于垫底的那种,题目意思很简单,个人认为题目有多解,而且传入的参数n也是多余的。

题目描述10

在这里插入图片描述

笔者解答10.1

class MyStack {
     Queue<Integer> queue;
     Queue<Integer> queue2;
    /** Initialize your data structure here. */
    public MyStack() {
        queue=new LinkedList<Integer>();
        queue2=new LinkedList<Integer>();
    }
    
    /** Push element x onto stack. */
    public void push(int x) {
    if(queue.isEmpty())
     while(!queue2.isEmpty())
     {
         queue.offer(queue2.poll());
     }
       queue.offer(x);
    }
    
    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        int num=0;
        if(queue2.isEmpty()){
        while(!queue.isEmpty()){
            num=queue.poll();
            if(!queue.isEmpty())
            queue2.offer(num);
        }}
        else{
           while(!queue2.isEmpty()){
            num=queue2.poll();
            if(!queue2.isEmpty())
            queue.offer(num);
        }
        }
        return num;
    }
    
    /** Get the top element. */
    public int top() {
        int num=0;
        if(queue2.isEmpty()){
        while(!queue.isEmpty()){
            num=queue.poll();
            queue2.offer(num);
        }}
        else{
            while(!queue2.isEmpty()){
            num=queue2.poll();
            queue.offer(num);
        }
        }
        return num;
    }
    
    /** Returns whether the stack is empty. */
    public boolean empty() {
      if(queue.isEmpty()&&queue2.isEmpty())
      return true;
      else 
      return false;
    }
}

笔者分析10.2

我也不明白怎么写的这么复杂,肯定是有问题的,直到看到大佬们的解法才豁然开朗。要想实现栈,这里类比为将顺序改为逆序,那么你就得先存大的,再将之前小的存入。而这些小的需要保存起来,就是下面代码中的b。

class MyStack {
    private Queue<Integer> a;//输入队列
    private Queue<Integer> b;//输出队列
    
    public MyStack() {
        a = new LinkedList<>();
        b = new LinkedList<>();
    }
    
    public void push(int x) {
        a.offer(x);
        // 将b队列中元素全部转给a队列
        while(!b.isEmpty())
            a.offer(b.poll());
        // 交换a和b,使得a队列没有在push()的时候始终为空队列
        Queue temp = a;
        a = b;
        b = temp;
    }
    
    public int pop() {
        return b.poll();
    }
   
    public int top() {
        return b.peek();
    }
    
    public boolean empty() {
        return b.isEmpty();
    }
}

总结

到这里,leetcode里栈的简单题部分就完结了,一共十六题,部分题相似度太高,博客里只介绍了其中十题,明天开始栈的中等题部分。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赶路的苟狗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值