LeetCode每日十题---栈(难度:中等)二

题目描述1

在这里插入图片描述

笔者解答1.1

class Solution {
    
    
    public String removeKdigits(String num, int k) {
    
    
          Stack<Character> stack=new Stack<Character>();
          stack.push(num.charAt(0));
          for(int i=1;i<num.length();i++){
    
    
               char last=stack.peek();
               char c=num.charAt(i);
               while(c<last&&k>=1)
               {
    
    
                   last=stack.pop();
                   k--;
               }
                stack.push(c);
               
          }
       char[] str=new char[num.length()];
       int length=0;
       while(!stack.isEmpty()){
    
    
           str[length]=stack.pop();
           length++;
       }
       String str2="";
       boolean getfirst_notzero=false;
       for(int i=length-1;i>=k;i--){
    
    
           if(getfirst_notzero||str[i]!='0'){
    
    
               str2+=""+str[i];
               getfirst_notzero=true;
           }
       }
       if(str2.equals(""))
       return "0";
       return str2;
    }
}

笔者分析1.2

这题思路挺简单的,但我写的代码还有写用例过不去,很难受。看了下评论区解答,发现思路都差不多,但他们的方法和代码量明显会简洁好多。思路就是,从左到右,找第一个比后面大的字符,删除,清零,k次扫描,代码如下。

class Solution {
    
    
    public String removeKdigits(String num, int k) {
    
    
        if (num.length() == k) return "0";
        StringBuilder s = new StringBuilder(num);
        for (int i = 0; i < k; i++) {
    
    
            int idx = 0;
            for (int j = 1; j < s.length() && s.charAt(j) >= s.charAt(j - 1); j++) idx = j;
            s.delete(idx, idx + 1);
            while (s.length() > 1 && s.charAt(0) == '0') s.delete(0, 1);
        }
        return s.toString();
    }
}

题目描述2

在这里插入图片描述

笔者解答2.1

class Solution {
    
    
    public boolean find132pattern(int[] nums) {
    
    
       for(int i=0;i<nums.length-2;i++){
    
    
           int a=nums[i];
           for(int j=i+1;j<nums.length-1;j++){
    
    
               int b=nums[j];
                   if(b>a){
    
    
                   for(int k=j+1;k<nums.length;k++){
    
    
                       int c=nums[k];
                       if(c<b&&c>a)
                       return true;
                   }
               }
           }
       }
       return false;
    }
}

笔者分析2.2

挺有意思的一道题目,上面是我的最初想法,很明显时间超时了,待我再想想。。。好吧,我是废物!
大佬思路:我们首先考虑啊a[i]<a[j]的部分。当我们固定了j时,我们可以再j的左侧找出一个最小的数作为a[i],这是因为最终我们需要满足a[i]<a[k]<a[j],那么a[i]一定越小越好。因此我们可以对数组a维护前缀最小值,即min[j]=min(a[1…j]),这样对于一个固定的j,min[j]即为最优的a[i]。
随后我们再考虑a[k],其中a[k]需要满足a[i]<a[k]<a[j],即min[j]<a[k]<a[j]。我们可以从数组a的末尾开始,从后向前寻找a[k]。
我们可以用栈来存储所有的a[k]。再栈中,所有候选的a[k]保持降序,即栈顶的元素最小,栈底的元素最大。即如果我们遇到一个新的a[k],那么我们会将栈定的元素依次出栈,直到新的a[k]为栈中的最小元素。我们在从右向左便利数组a时,假设我们当前位于a[j],首先我们判断是否右nums[j]>min[j],如果不成立,那么我们要跳过这个a[j],否则我们将栈顶的元素依次出栈,直到栈顶元素stack[top]满足stack[top]>min[j]。在这之后,我们可以确定栈中的所有元素都大于min[j]因此如果此时栈顶的元素和j可以满足132模式,那么我们就找到了一组合法的满足132模式的i,j,k,否则我们继续寻找,此时需要吧a[j]入栈。如果在便利结束后,我们仍然没有找到满足132模式的i,j,k,那么我们需要返回False。代码如下

public class Solution {
    
    
    public boolean find132pattern(int[] nums) {
    
    
        if (nums.length < 3)
            return false;
        Stack < Integer > stack = new Stack < > ();
        int[] min = new int[nums.length];
        min[0] = nums[0];
        for (int i = 1; i < nums.length; i++)
            min[i] = Math.min(min[i - 1], nums[i]);
        for (int j = nums.length - 1; j >= 0; j--) {
    
    
            if (nums[j] > min[j]) {
    
    
                while (!stack.isEmpty() && stack.peek() <= min[j])
                    stack.pop();
                if (!stack.isEmpty() && stack.peek() < nums[j])
                    return true;
                stack.push(nums[j]);
            }
        }
        return false;
    }
}

题目描述3

在这里插入图片描述

笔者解答3.1

class Solution {
    
    
    public boolean validateStackSequences(int[] pushed, int[] popped) {
    
    
     Stack<Integer> stack=new Stack<Integer>();
     for(int i=0,j=0;i<pushed.length;i++){
    
    
         stack.push(pushed[i]);
         while(stack.peek()==popped[j]){
    
    
           stack.pop();j++;
           if(stack.isEmpty())break;
         }
     }
     if(!stack.isEmpty())
     return false;
     return true;
    }
}

笔者分析3.2

这题虽然没啥难度,但个人认为还是比较典型的。主要思路是,遍历pushed序列,如果何popped序列中的元素值相等,则在pushed序列中弹出该元素,这里是个While循环。直到对应元素不等,则将pushed序列i+1至下一个元素。最后若栈为空则返回true,否则false。

题目描述4

在这里插入图片描述

笔者解答4.1

class Solution {
    
    
    public int[] nextGreaterElements(int[] nums) {
    
    
      int[] str=new int[nums.length];
      for(int i=0;i<nums.length;i++){
    
    
          int a=nums[i];
          int j;
          for(j=(i+1)%nums.length;j!=i;j=(j+1)%nums.length){
    
    
             if(nums[j]>a)
             {
    
    
                 str[i]=nums[j];break;
             }
          }
          if(j==i)str[i]=-1;
      }
      return str;
    }
}

笔者分析4.2

说来惭愧,看到这题我的第一反应还是用两个for循环,执行用时击败了0.05的用户。丢人啊,只好再去评论区学习一下大佬们的方法。
单调栈:我们首先把第一个元素A[1]放入栈,随后对于第二个元素A[2],如果A[2]>A[1],那么我们就找到了A[1]的下一个更大元素A[2],此时就可以把A[1]出栈并把A[2]入栈;如果A[2]<=A[1],我们就仅把A[2]入栈。对于第三个元素A[3],此时栈中有若干个元素,那么所有比A[3]小的元素都找到了下一个更大的元素(即A[3]),因此可以出栈,在这之后,我们将A[3]入栈,以此类推。代码如下:

class Solution {
    
    
    public int[] nextGreaterElements(int[] nums) {
    
    
        int n = nums.length;
        int [] res = new int[n];
        Arrays.fill(res, -1);
        Stack <Integer> stack = new Stack<>();
        for (int i = 0; i < n*2; i++){
    
    
            int num = nums[i % n];
            while(!stack.isEmpty() && num > nums[stack.peek()]){
    
    
                res[stack.pop()] = num;
            }
            if(i < n) stack.add(i);
        }
        return res;
    }
}

题目描述5

在这里插入图片描述

笔者解答5.1

class Solution {
    
    
    public int[] asteroidCollision(int[] asteroids) {
    
    
        Stack<Integer> stack=new Stack<Integer>();
        int[] str=new int[asteroids.length];
        int count=0;
        int count_stack=0;
        for(int i=0;i<asteroids.length;i++){
    
    
            int temp=asteroids[i];
            while(!stack.isEmpty()){
    
    
                if(temp<0)
                  {
    
    
                    if(stack.peek()>0-temp){
    
    
                        temp=0;
                          break;
                    }else if(stack.peek()==0-temp)
                     {
    
    
                            stack.pop();
                            count_stack--;
                            temp=0;break;
                     }
                    else
                    {
    
    
                        stack.pop();
                        count_stack--;
                    }
                  }
                 else{
    
    
                     stack.push(temp);temp=0;
                     count_stack++;break;
                 } 
            }
            if(stack.isEmpty()&&temp>0)
             {
    
    
                   stack.push(temp);
                   count_stack++;
             }
            if(temp<0)
             {
    
    
                 str[count]=temp;
                 count++;
             }
        }
        int[] strout=new int[count+count_stack];
        for(int i=0;i<count;i++)
           strout[i]=str[i];
        while(!stack.isEmpty()){
    
    
            strout[count+count_stack-1]=stack.pop();
            count_stack--;
        }
        return strout;
        
    }
}

笔者分析5.2

总体来说还是挺简单的,像我这种菜鸡都能一遍过。主要还是围绕栈来展开的,如果开始进入的为负数,那么直接将它存入最后的结果当中,因为它不肯能爆炸,追不上,遍历到第一个正数时,将其入栈。若接下来遇到的都是正数,也直接入站,若为负数,则比较绝对值大小,按情况分析,这里是一个while循环,因为一个大的负数,能把栈内路过的小正数都给炸没了,而不是只炸一次,若炸完了栈中所有正数,负数还存活的话,就相当于一开始进入的为负数,那么这时就要将其存入最后的结果当中,不必入栈。遍历完之后,栈要么为空,要么全是正数,谁都追不上谁,最后结果要加上这剩余栈中的正数。这里有个小问题,返回的数组大小要和它包含有效数据的个数一致,空间不能开大了,否则会自动用0填充。

题目描述6

在这里插入图片描述

笔者解答6.1

class Solution {
    
    
    public int[] dailyTemperatures(int[] T) {
    
    
        Stack<Integer> stack=new Stack<Integer>();
        Stack<Integer> stack_id=new Stack<Integer>();
        int[] str=new int[T.length];
        stack.push(T[0]);
        stack_id.push(0);
        for(int i=1;i<T.length;i++){
    
    
            while(!stack.isEmpty()&&T[i]>stack.peek()){
    
    
                stack.pop();
                int id=stack_id.pop();
                str[id]=i-id;
            }
            stack.push(T[i]);
            stack_id.push(i);
            if(T[i]<=stack.peek()){
    
    
                stack.push(T[i]);
                stack_id.push(i);
            }
        }
        while(!stack_id.isEmpty()){
    
    
            int id=stack_id.pop();
            str[id]=0;
        }
        return str;
    }
}

笔者分析6.2

好像是和上面找下一个最大元素题是一样的,用的是单调栈,具体就不重复介绍了。

总结

有点意思,至少可以在自己的代码里找到算法的感觉了,每日十题打卡第三天,以下图为证。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Achenming1314/article/details/108303097