leetcode 堆栈(栈+优先队列)——java实现

news2024/11/18 22:50:11

java创建堆栈和操作函数

Queue<String> queue = new LinkedList<String> ();//队列定义
Deque<String> stack= new LinkedList<String>();//堆栈
队列方法:
queue.offer(e) null
queue.poll() 返回移除的值
queue.peek()
堆栈方法:
stack.push(e) null
stack.pop()返回移除的值
stack.peek()返回栈顶的元素但不移除它
stack.size()返回栈中元素2 (假设栈里有1,5两个元素)
stack.search(2));返回从栈顶往前数第2个元素1

堆的逻辑结构是一颗完全二叉树
堆的物理结构是一个数组
大根堆就是整个完全二叉树,任意一个根节点的值都比左右子树的值大
小根堆表示整个完全二叉树,任意一个根节点的值都比左右子树的值小。

leetcode

20. 有效的括号

给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
也就是说:括号可以互相包含,但不能参差摆放,如下例: “{[]}()” true ({)} false

遇到左括号入栈
遇到右括号检验栈顶元素是否和它匹配,匹配则出栈,否则False
最后栈空则true

class Solution {
    public boolean isValid(String s) {
        //括号可以互相包含,但不能参差摆放,如下例: "{[]}()" true ({)} false 
        Deque<Character> sta = new LinkedList<Character>();
        HashMap<Character,Character> map = new HashMap<Character,Character>();
        map.put('(',')');
        map.put('[',']');
        map.put('{','}');
        for(int i=0;i<s.length();i++){
            if(s.charAt(i)=='('||s.charAt(i)=='['||s.charAt(i)=='{'){
                sta.push(s.charAt(i));
            }
            else if(s.charAt(i)==')'||s.charAt(i)==']'||s.charAt(i)=='}'){
                if(!sta.isEmpty() &&map.get(sta.peek())==s.charAt(i)){//匹配上了
                    sta.pop();
                }
                else return false;
            }
        }
        return sta.isEmpty();
    }
}

155. 最小栈

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:
MinStack() 初始化堆栈对象。
void push(int val) 将元素val推入堆栈。
void pop() 删除堆栈顶部的元素。
int top() 获取堆栈顶部的元素。
int getMin() 获取堆栈中的最小元素。

关键在于:建两个栈,一个存正常放入的数,另一个存小值使得栈顶是当前时刻最小的值。

class MinStack {
   Deque<Integer> mstack;
   Deque<Integer> stackmin;

    int min;
    public MinStack() {
        mstack = new LinkedList<Integer>();
        stackmin = new LinkedList<Integer>();//存min的栈,栈顶是当前时刻最小的值

    }
    
    public void push(int val) {
        mstack.push(val);
        if(!stackmin.isEmpty()){
            if(val<=stackmin.peek()){//比栈顶值小就入栈
                stackmin.push(val);
            }
        }
        else{
            stackmin.push(val);
        }
        

    }
    
    public void pop() {
        int top = mstack.pop();
        if(top==stackmin.peek()){
            stackmin.pop();
        }
    }
    
    public int top() {
        return mstack.peek();

    }
    
    public int getMin() {
        return stackmin.peek();
    }
}

394. 字符串解码

给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。
(重点样例)
输入:s = “3[a2[c]]”
输出:“accaccacc”
输入:s=b2[c]
输出:abcc

重点注意:在什么时候数组字母入栈和出栈
以及动态更新字母串用StringBuilder或StringBuffer

class Solution {
    public String decodeString(String s) {
        //有嵌套的情况
        //数字存放在数字栈,字符串存放在字符串栈,遇到右括号时候弹出一个数字栈,字母栈弹到左括号为止。
        //关键点:(1)处理多位数(2)遇到 '[',将当前的字符串和数字推入各自的栈(3)遇到 ']'开始解码
        Deque<Integer> numStack = new LinkedList<Integer>();
        Deque<String> strStack = new LinkedList<String>();
        int number=0;
        String str="";
        for(int i=0;i<s.length();i++){
            if(Character.isDigit(s.charAt(i))){//是数字
                number = number*10+s.charAt(i)-'0';//处理多位数
            }
            else if(s.charAt(i)=='['){//数字结束,字母开始
                numStack.push(number);
                number=0;
                strStack.push(str);
                str="";
            }
            else if(s.charAt(i)==']'){//字母结束,处理一次数字加字母
                StringBuilder strb = new StringBuilder(strStack.pop());//用str栈顶的初始化一个stringbuilder
                int n=numStack.pop();
                for(int j=0;j<n;j++){
                    strb.append(str);
                }
                str=strb.toString();//更新当前字符串
            }
            else{//是字母
                str+=s.charAt(i);
            }
        }
        return str;
    }
}

739. 每日温度

给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。
示例 1:
输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
示例 2:
输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]
示例 3:
输入: temperatures = [30,60,90]
输出: [1,1,0]

单调栈:在单调栈基础题中,经常需要类似这种的解题思路:在 O(n) 的时间复杂度内求出数组中各个元素右侧第一个更大的元素及其下标,然后一并得到其他信息。
下图摘自leetcode:
栈中存入下标,并维持栈中下标对应的元素从左到右非递增。
arr[0],arr[1],arr[2]非递增依次入栈
在这里插入图片描述
arr[2]出栈,arr[3]入栈,以此同时记录result[2]=3-2;(这个result是题目要求的下一个更大元素)
在这里插入图片描述
arr[3],arr[1],arr[0]都出栈,并记录result[3]=4-3,result[1]=4-1,result[0]=4-0;
至于右侧没有更大元素的在result数组里没填过值,就默认为0了。【而按照下一题,HashMap里没有默认值,所以是map.containsKey为空判断一下然后取值-1】

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        //单调栈
        Deque<Integer> decStack = new LinkedList<Integer>();
        int[] result = new int[temperatures.length];
        for(int i=0;i<temperatures.length;i++){
            while(!decStack.isEmpty()&&temperatures[i]>temperatures[decStack.peek()]){
                int m = decStack.pop();
                result[m]=i-m;//记录差距填数
            }
            decStack.push(i);//记录下标
        }
        return result;
    }
}

496. 下一个更大元素 I

nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。
给你两个 没有重复元素 的数组 nums1 和 nums2 ,下标从 0 开始计数,其中nums1 是 nums2 的子集。
对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j] 的 下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1 。
返回一个长度为 nums1.length 的数组 ans 作为答案,满足 ans[i] 是如上所述的 下一个更大元素 。

示例 1:
输入:nums1 = [4,1,2], nums2 = [1,3,4,2].
输出:[-1,3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:

  • 4 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
  • 1 ,用加粗斜体标识,nums2 = [1,3,4,2]。下一个更大元素是 3 。
  • 2 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
    示例 2:
    输入:nums1 = [2,4], nums2 = [1,2,3,4].
    输出:[3,-1]
    解释:nums1 中每个值的下一个更大元素如下所述:
  • 2 ,用加粗斜体标识,nums2 = [1,2,3,4]。下一个更大元素是 3 。
  • 4 ,用加粗斜体标识,nums2 = [1,2,3,4]。不存在下一个更大元素,所以答案是 -1 。
class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        //下一个更大的元素,就是用单调栈解
        Deque<Integer> decStack = new LinkedList<Integer>();
        int[] result = new int[nums1.length];
        HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();//因为num1是num2的子集且打乱顺序,就用HashMap记录
        for(int i=0;i<nums2.length;i++){
            while(!decStack.isEmpty()&&nums2[i]>decStack.peek()){
                int m=decStack.pop();
                map.put(m,nums2[i]);
            }                
            decStack.push(nums2[i]);//这回是直接记录值

        }
        for(int i=0;i<nums1.length;i++){
            result[i]= map.containsKey(nums1[i])? map.get(nums1[i]):-1;
        }
        return result;
    }
}

215. 数组中的第K个最大元素

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例 1:
输入: [3,2,1,5,6,4], k = 2
输出: 5
示例 2:

输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4

Arrays.sort(nums) 默认使用快排

  1. 快排
class Solution {
    public int findKthLargest(int[] nums, int k) {

        Arrays.sort(nums);//快排
        return nums[nums.length-k];

    }
}
  1. 优先队列
    优先队列的思路是很朴素的。由于找第 K 大元素,其实就是整个数组排序以后后半部分最小的那个元素。因此,我们可以维护一个有 K 个元素的最小堆

新遍历到的数大于堆顶的时候,才将堆顶拿出,然后放入新读到的数,进而让堆自己去调整内部结构。

PriorityQueue 底层是动态数组,底层是基于堆实现。

class Solution {
    public int findKthLargest(int[] nums, int k) {
        //维护一个k大小的小顶堆,直接使PriorityQueue不用手动实现堆操作了
        PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>();//小顶堆
        for(int i=0;i<k;i++){//建大小为k的堆
            minHeap.offer(nums[i]);
        }

        for(int i=k;i<nums.length;i++){//相当于从全部数组里提出len-k个小值就得到了第k大的值
            if(nums[i]>minHeap.peek()){//比堆顶大,就提出堆顶小值,把nums[i]放进去
                minHeap.poll();
                minHeap.offer(nums[i]);
            }
        }
        return minHeap.peek();
    }
}

347. 前 K 个高频元素

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:

输入: nums = [1], k = 1
输出: [1]

依旧是k大小的小顶堆【优先队列】

重点注意:

用HashMap统计元素出现次数,以及优先队列里元素的存储形式。
还有HashMap的遍历方式

HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
//优先队列里元素的存储形式是int[]的数组,[0]存key[1]存value
PriorityQueue<int[]> minHeap = new PriorityQueue<int[]>(n,new Comparator<int[]>(){//定义比较方式
    public int compare(int[] a,int[] b){
        return a[1]-b[1];//按value升序,即小顶堆
    }
} );

整体代码:

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        //先统计每个数出现次数,再建k大小的小顶堆
        HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
        for(int i=0;i<nums.length;i++){
            if(map.containsKey(nums[i])){
                int cn=map.get(nums[i])+1;
                map.put(nums[i],cn);
            }
            else{
                map.put(nums[i],1);
            }
        }
        int n=map.size();
        //优先队列里元素的存储形式是int[]的数组,[0]存key[1]存value
        PriorityQueue<int[]> minHeap = new PriorityQueue<int[]>(n,new Comparator<int[]>(){//定义比较方式
            public int compare(int[] a,int[] b){
                return a[1]-b[1];//按value升序,即小顶堆
            }
        } );
        int cn=0,kk=0;
        //放前k个
        for(Integer key:map.keySet()){
            cn++;
            if(cn>k){
                break;
            }
            int value=map.get(key);
            minHeap.offer(new int[]{key,value});
        }
        int cnn=0;
        //继续后n-k个
        for(Integer key:map.keySet()){
            cnn++;
            if(cnn>k){
                int value=map.get(key);
                if(value>minHeap.peek()[1]){
                    minHeap.poll();
                    minHeap.offer(new int[]{key,value});
                }
            }
        }
        
        //最后数组存放k大小堆中的值,不按照顺序
        int[] a=new int[k];
        for(int i=0;i<k;i++){
            System.out.println(minHeap.peek()[0]+":"+minHeap.peek()[1]);
            a[i]=minHeap.poll()[0];
            
        }
        return a;

    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2052234.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从零开始学cv-8:直方图操作进阶:直方图匹配,局部直方图均衡化,彩色直方图均衡化

文章目录 一&#xff0c;简介二、直方图匹配三、局部直方图均衡化四、彩色直方图均衡化4.1 rgb彩色直方图均衡化4.2 ycrb 彩色直方图均衡化 一&#xff0c;简介 在上一篇文章中&#xff0c;我们探讨了直方图的基本概念&#xff0c;并详细讲解了如何利用OpenCV来查看图像直方图…

MATLAB 大场景建筑物点云提取方法实现(75)

MATLAB 大场景建筑物点云提取方法实现(75) 一、算法介绍二、算法实现1.代码2.效果展示总结一、算法介绍 本章手动实现了一种建筑物点云提取方法,可以对室外的大规模场景点云中的建筑物进行有效提取,下面是实现的效果和具体的实现方法,直接复制粘贴代码即可使用, 二、算…

【基础算法总结】多源 BFS_多源最短路问题

多源 BFS_多源最短路问题 1.多源 BFS_多源最短路问题2.01 矩阵3.飞地的数量4.地图中的最高点5.地图分析 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&…

springboot纹理生成图片系统--论文源码调试讲解

第2章 程序开发技术 2.1 MySQL数据库 开发的程序面向用户的只是程序的功能界面&#xff0c;让用户操作程序界面的各个功能&#xff0c;那么很多人就会问&#xff0c;用户使用程序功能生成的数据信息放在哪里的&#xff1f;这个就需要涉及到数据库的知识了&#xff0c;一般来说…

Maven继承和聚合特性

目录 Maven继承关系 1.继承概念 父POM 子模块 2.继承机制 3.示例 4.继承作用 背景 需求 5.注意事项 Maven聚合关系 1. 定义与概念 2. 实现方式 3. 特性与优势 4. 示例 5. 注意事项 Maven继承关系 1.继承概念 Maven 继承是指在 Maven 的项目中&#xff0c;定义…

沉浸式技术

沉浸式技术是一种通过创造逼真的虚拟或增强现实环境&#xff0c;使用户感到自己仿佛身处另一个世界的技术。它主要依赖于视觉、听觉、触觉等多种感官的调动&#xff0c;带来身临其境的体验。随着技术的发展&#xff0c;沉浸式技术正迅速改变着娱乐、教育、医疗等众多领域。本文…

Golang | Leetcode Golang题解之第345题反转字符串中的元音字母

题目&#xff1a; 题解&#xff1a; func reverseVowels(s string) string {t : []byte(s)n : len(t)i, j : 0, n-1for i < j {for i < n && !strings.Contains("aeiouAEIOU", string(t[i])) {i}for j > 0 && !strings.Contains("aei…

牛客周赛 Round 56

牛客周赛 Round 56 A 面包店故事 链接&#xff1a;https://ac.nowcoder.com/acm/contest/88392/A 来源&#xff1a;牛客网 题目描述 小镇上有一家面包店&#xff0c;面包以 &#x1d465; 元的价格出售&#xff0c;加 &#x1d466; 元可以多加几块培根。小歪带着 &#x1d4…

蔚来汽车拥抱AI

30多个传感器&#xff0c;车上实时收集数 为什么要造手机 领航辅助驾驶 端到端AEB

Spring动态代理与AOP

AOP中的Before是如何实现的&#xff1f; 在AOP&#xff08;面向切面编程&#xff09;中&#xff0c;Before注解通常用于定义一个在方法执行前执行的前置通知&#xff08;advice&#xff09;。在Spring框架中&#xff0c;实现Before功能的底层机制主要基于代理&#xff08;Prox…

JSON Web Token (JWT): 理解与应用

JWT&#xff08;JSON Web Token&#xff09;是一种开放标准&#xff08;RFC 7519&#xff09;&#xff0c;它定义了一种紧凑且自包含的方式&#xff0c;用于在各方之间以JSON对象的形式安全地传输信息。JWT通常用于身份验证和授权目的&#xff0c;因为它可以使用JSON对象在各方…

4.5、配置vtp域

一、了解vtp域 VTP&#xff08;VLAN Trunking Protocol&#xff09;域是一个在网络中用于管理和同步VLAN配置信息的概念。它使得多个交换机可以在同一VTP域中共享VLAN信息&#xff0c;从而简化了VLAN的配置和管理。 三种主要模式 Server模式&#xff1a; 交换机可以创建、修…

Nginx的进程模型:Master-Worker架构解析

Nginx的进程模型&#xff1a;Master-Worker架构解析 一、Master-Worker架构概述二、Master进程的职责三、Worker进程的特点四、与Apache进程模型的对比 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; Nginx作为高性能Web服务器&#xff0c…

代码随想录算法训练营day45:动态规划part12:115.不同的子序列;583. 两个字符串的删除操作;72. 编辑距离

目录 115.不同的子序列 分析&#xff1a; 583. 两个字符串的删除操作 72. 编辑距离 115.不同的子序列 力扣题目链接(opens new window) 给定一个字符串 s 和一个字符串 t &#xff0c;计算在 s 的子序列中 t 出现的个数。 字符串的一个 子序列 是指&#xff0c;通过删除…

初识Linux · 基本指令(1)

目录 前言&#xff1a; 基本指令 1.1 pwd 1.2 ls 1.3 mkdir cd clear 1.4 touch 1.5 ls部分补充 1.6 whoami 1.7 有关目录以及路径 前言&#xff1a; 今天是Linux系列的第一章节&#xff0c;对于Linux的主线学习大概会更新两个半月左右&#xff0c;中间穿插着算法…

vue中 在scoped下通过@import引入scss的作用域?

<style lang"scss" src"./index.scss" scoped></style>人工智能学习网站 https://chat.xutongbao.top

nbcio-boot基于flowable6.7.2的流程模型版本管理-前端与界面

更多技术支持与服务请加入我的知识星球。 这部分主要讲前端与功能界面方面 1、首先增加发布列表与修改状态api接口 // 查询流程发布列表 export function listPublish(query) {return request({url: /flowable/definition/publishList,method: get,params: query})}// 激活/挂…

pytorch之nn.Module使用介绍

在 PyTorch 中&#xff0c;nn.Module 是所有神经网络模型的基类&#xff0c;提供了许多重要的成员函数。以下是一些常用的成员函数及其功能&#xff1a; 1. __init__(self) 描述&#xff1a;初始化模块。在用户定义的模型中&#xff0c;通常用来定义层和其他模块。 示例&…

【hot100篇-python刷题记录】【最大子数组和】

R5-普通数组 印象题&#xff0c;讲思路&#xff1a; 1.0个元素&#xff0c;返回0 2.将从left到right的计算简化为为left-mid&#xff0c;mid1-right 以及left-mid-right 3者的最大值&#xff08;因为有负数&#xff09; 3.上面左右两边的计算可以递归调用本身函数&#xff0…

第二十二节、创建人物状态栏

一、可视化插件 在层级面板名字加上对应的图标&#xff0c;会显示颜色&#xff0c;需要运行一下 二、UI 1、创建一个画布 由于使用新的新输入系统&#xff0c;需要替换一下 2、设置锚点 作用是&#xff1a;当屏幕分辨率更改后&#xff0c;ui图标不会位移 3、设置填充 4、制…