leetcode刷题——栈和队列

目录

1、替换数字

2、lmplement Queue using Stacks

3、lmplement Stack using Queues

4、Valid Parentheses

5、Remove All Adjacent Duplicates In String

6、Evaluate Reverse Polish Notation

7、Sliding Window Maximum

8、Top K Frequent Elements


1、替换数字

给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number。

例如,对于输入字符串 "a1b2c3",函数应该将其转换为 "anumberbnumbercnumber"。

对于输入字符串 "a5b",函数应该将其转换为 "anumberb"

输入:一个字符串 s,s 仅包含小写字母和数字字符。

输出:打印一个新的字符串,其中每个数字字符都被替换为了number

样例输入:a1b2c3

样例输出:anumberbnumbercnumber

数据范围:1 <= s.length < 10000。

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        String ss=sc.next();
        int len=ss.length();
        for(int i=0;i<ss.length();i++){
            //这里ss.length();注意不能用会变的len当做长度
            if(ss.charAt(i)>='0'&&ss.charAt(i)<='9'){
                len+=5;
            }
        }
        char[] newSS=new char[len];
        len=len-1;
        for(int i=ss.length()-1;i>=0;i--){
            if(ss.charAt(i)>='0'&&ss.charAt(i)<='9'){
                //这里犯错了,数组的索引从len-1开始,不是从len
                newSS[len--]='r';
                newSS[len--]='e';
                newSS[len--]='b';
                newSS[len--]='m';
                newSS[len--]='u';
                newSS[len--]='n';
            }
            else{
                newSS[len--]=ss.charAt(i);
            }
        }
        System.out.println(new String(newSS)); 
    }
}

纠正自己代码习惯错误:

(1)注意一下是否可以用后面会变化的变量来当作for循环的结束条件

(2)数组的长度是length 字符串的长度是length()

(3)注意数组的末尾的下标是 【 len-1】

java栈的基本方法 pop push peek isEmpty

java队列的基本方法 add poll peek isEmpty

2、lmplement Queue using Stacks用栈实现队列

Implement a first in first out (FIFO) queue using only two stacks. The implemented queue should support all the functions of a normal queue (pushpeekpop, and empty).

Implement the MyQueue class:

  • void push(int x) Pushes element x to the back of the queue.
  • int pop() Removes the element from the front of the queue and returns it.
  • int peek() Returns the element at the front of the queue.
  • boolean empty() Returns true if the queue is empty, false otherwise
class MyQueue {


/**
需要2个栈实现一个队列,输入栈就是照常输入,再来一个输出栈就是数字顺序再倒过来,就恢复正常队列顺序了
push:数据放进输入栈
pop:输出栈如果为空,就把进栈数据【全部导入】进来,再从出栈弹出数据,如果输出栈不为空,则直接从出栈弹出数据就可以了
peek:和pop逻辑一致
Empty:判断2个栈都为空才返回空
 */
    Stack<Integer> in;
    Stack<Integer> out;
    public MyQueue() {
        in =new Stack<>();
        out=new Stack<>();
    } 
    public void push(int x) {
        in.push(x);
    } 
    public int pop() {
        pushInToOut();
        return (out.pop());
    }  
    public int peek() {
        pushInToOut();
        return( out.peek());
    }
    
    public boolean empty() {
        if(in.isEmpty()&&out.isEmpty())
            return true;
        return false;
    }
    public void pushInToOut(){
         if(out.isEmpty()){
            while(!in.isEmpty()){
                int xx=in.pop();
                out.push(xx);
            }  
        }
    }
}

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue obj = new MyQueue();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.peek();
 * boolean param_4 = obj.empty();
 */

3、lmplement Stack using Queues用队列实现栈

mplement a last-in-first-out (LIFO) stack using only two queues. The implemented stack should support all the functions of a normal stack (pushtoppop, and empty).

Implement the MyStack class:

  • void push(int x) Pushes element x to the top of the stack.
  • int pop() Removes the element on the top of the stack and returns it.
  • int top() Returns the element on the top of the stack.
  • boolean empty() Returns true if the stack is empty, false otherwise.

class MyStack {
    Queue<Integer> que;

    /**
    使用一个队列实现
    当需要pop的时候,把前面所有元素重新添加到队尾,然后队列头部就是之前的最后一个元素
    peak:这里需要注意,获取最后一个元素,只能先pop一下,然后再重新添加回去
     */

    public MyStack() {
        que=new LinkedList<>();//Java队列使用链表实现
    }
    
    public void push(int x) {
        que.add(x);
    }
    
    public int pop() {
        moveToBack();
        return que.poll();

    }
    
    public int top() {
        // moveToBack();
        // int x=que.poll();
        // que.add(x);
        // return x;
        int x=pop();
        que.add(x);
        return x;


    }
    
    public boolean empty() {
        return que.isEmpty();

    }
    public void moveToBack(){
        int size=que.size();
        while(size>1){
            que.add(que.poll());
            size--;
        }
    }
}

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack obj = new MyStack();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.top();
 * boolean param_4 = obj.empty();
 */

4、Valid Parentheses有效的括号

Given a string s containing just the characters '('')''{''}''[' and ']', determine if the input string is valid.

An input string is valid if:

  1. Open brackets must be closed by the same type of brackets.
  2. Open brackets must be closed in the correct order.
  3. Every close bracket has a corresponding open bracket of the same type.

class Solution {
    public boolean isValid(String s) {

        /**
        括号匹配,使用一个栈实现
        当遇到左括号,就push对应匹配的右括号
        当遇到右括号,需要检查一下:
        (1)栈是否是空的,空的那肯定是不匹配了
        (2)栈不为空,比较栈顶部的右括号和当前遍历的右括号是否相同,不同就返回false,
        如果相同就是需要消消乐,把栈里面的首部元素删除

         */
        Stack<Character> stack=new Stack<>();
        for(int i=0;i<s.length();i++){
            if(s.charAt(i)=='('){
                stack.push(')');
            }
            else if(s.charAt(i)=='{'){
                stack.push('}');
            }
            else if(s.charAt(i)=='['){
                stack.push(']');
            }
            else if(stack.isEmpty()||s.charAt(i)!=stack.peek()){
                return false;
            }
            else{
                stack.pop();
            }
        }
        return stack.isEmpty();

    }
}

5、Remove All Adjacent Duplicates In String删除字符串中的所有相邻重复项

You are given a string s consisting of lowercase English letters. A duplicate removal consists of choosing two adjacent and equal letters and removing them.

We repeatedly make duplicate removals on s until we no longer can.

Return the final string after all such duplicate removals have been made. It can be proven that the answer is unique.

class Solution {
    public String removeDuplicates(String s) {
        /**
        这个和括号匹配问题相似,就是消消乐
        最后剩下的元素需要转换成string
         */
        Stack<Character> stack=new Stack<>();
        for(int i=0;i<s.length();i++){
            if(!stack.isEmpty()&&stack.peek()==s.charAt(i)){
                stack.pop();
            }
            else{
                stack.push(s.charAt(i));
            }
        }
        char cc[]=new char[stack.size()];
        int j=stack.size()-1;
        while(!stack.isEmpty()){
            cc[j--]=stack.pop();
        }
        return new String(cc);

    }
}

6、Evaluate Reverse Polish Notation逆波兰表达式求值

You are given an array of strings tokens that represents an arithmetic expression in a Reverse Polish Notation.

Evaluate the expression. Return an integer that represents the value of the expression.

Note that:

  • The valid operators are '+''-''*', and '/'.
  • Each operand may be an integer or another expression.
  • The division between two integers always truncates toward zero.
  • There will not be any division by zero.
  • The input represents a valid arithmetic expression in a reverse polish notation.
  • The answer and all the intermediate calculations can be represented in a 32-bit integer.
class Solution {
    public int evalRPN(String[] tokens) {
        /**
        遇到数字则入栈;遇到运算符则取出栈顶两个数字进行计算,并将结果压入栈中
        这里需要注意数字先后顺序,对于除法和减法是有顺序要求的
         */
         Stack<Integer> num=new Stack<>();
         Stack<Integer> opt=new Stack<>();
         for(int i=0;i<tokens.length;i++){
            if(tokens[i].equals("+")){
                int res=num.pop()+num.pop();
                num.push(res);
            }
            else if(tokens[i].equals("-")){
                int n1=num.pop();
                int n2=num.pop();
                num.push(n2-n1);
            }
            else if(tokens[i].equals("/")){
                int n1=num.pop();
                int n2=num.pop();
                num.push(n2/n1);
            }
            else if(tokens[i].equals("*")){
                int res=num.pop()*num.pop();
                num.push(res);
            }
            else{
                num.push(Integer.parseInt(tokens[i]));
            }
         }
         return num.pop();

    }
}

7、Sliding Window Maximum滑动窗口最大值

You are given an array of integers nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position.

Return the max sliding window.

Example 1:

Input: nums = [1,3,-1,-3,5,3,6,7], k = 3
Output: [3,3,5,5,6,7]
Explanation: 
Window position                Max
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7
class Mydequeue{
    Deque<Integer> que;
    public Mydequeue(){
        que=new LinkedList<>();
        //que的方法有 peek poll add addLast removeLast getLast
    }
    public int peek(){
        //直接返回头部元素值,也是最大值
        return que.peek();
    }
    public void add(int val){
        //添加元素,不为空且val如果大于队列末尾元素就要移除末尾元素,这个是循环的,保证val插入是形成递减队列
        //比如 5 2 3插入4 那最终队列为5 4
        //3 2 1 插入 5 那最终队列为5
        while(!que.isEmpty()&&val>que.getLast()){
            que.removeLast();//移除尾部
        }
        //这里的val是肯定要插入的,记得是插入尾部
        que.addLast(val);
    }
    public void poll(int val){
        //如果移除的元素等于队列头部元素,那就弹出
        if(val==que.peek()){
            que.poll();
        }
    }
}
class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        /**
利用一个队列dequeue维护有可能成为窗口里最大值的元素,同时排序由大到小
poll:如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作
add:如果add的元素value大于入口元素的数值,那么就将队列入口的元素弹出,
直到add元素的数值小于等于队列入口元素的数值
nums = [1,3,-1,-3,5,3,6,7], k = 3
滑动窗口 队列元素的值变化 每次滑动到一个新的窗口,队列只维持最大元素开始的顺序
(1) 3,-1  
(2)3,-1,-3
(3)5
(4)5 3
(5)6
(6)7
这里注意,队列里面的元素是单调递减的,并且元素之间的顺序和原始数组中元素的顺序是相对一致的
所以不可能出现队列中第二最大值先被弹出来,肯定都是【比他最大的值且在数组中排序在它前面的】先被弹出来,再到自己
         */
         Mydequeue que=new Mydequeue();
         int[] res=new int[nums.length-k+1];
         for(int i=0;i<k;i++){
            que.add(nums[i]);
         }
         res[0]=que.peek();//res返回结果数组
         for(int i=k,j=1;i<nums.length;i++,j++){   
            que.add(nums[i]);//移动窗口进来新得元素
            que.poll(nums[i-k]); //移动窗口移除旧得元素  
            res[j]=que.peek();
         }
         return res;

    }
}

8、Top K Frequent Elements前 K 个高频元素

Given an integer array nums and an integer k, return the k most frequent elements. You may return the answer in any order.

Example 1:

Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]

Example 2:

Input: nums = [1], k = 1
Output: [1]
class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        /**
        思路:
        1、统计每个数字出现频率:用map
        2、对频率进行排序,选择k个最大的频率:使用优先队列priorityqueue
        优先队列的底层实现是堆(大顶堆和小顶堆)  
        先把每个频率放入堆中进行排序,超过k个就把堆顶最小值弹出来,遍历结束剩下的就全部是k个最大的
         */
         Map<Integer,Integer> map=new HashMap<>();
         for(int n:nums){
            //统计频率
            map.put(n,map.getOrDefault(n,0)+1);
         }
         //实现小顶堆,堆顶元素是最小值
          o1 - o2 是升序排序从小到大,o2 - o1 是降序排序,
         //这里优先队列的元素是一对二元组,为了对应数字和频率
         PriorityQueue<int[]> pq=new PriorityQueue<>((a,b)->a[1]-b[1]);
         //这里a1-b1如果结果为负,那么第一个形参a排前面,也就是a的频率低就排在前面,所以就是升序
         for(var mm:map.entrySet()){//这里的var也可以变成Map.Entry<Integer,Integer>
            int[] tem=new int[2];
            tem[0]=mm.getKey();
            tem[1]=mm.getValue();
            pq.add(tem);//先添加再判断是否超过k个,超过就弹出堆顶最小值
            if(pq.size()>k){
                pq.poll();
            }
         }
         int[] res=new int[k];
         int j=0;
         while(!pq.isEmpty()){
            res[j++]=pq.poll()[0];
         }
         return res;

    }
}

  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值