LeetCode 腾讯精选50题--最小栈
题目很简单,实现一个最小栈,能够以线形的时间获取栈中元素的最小值
自己的思路如下:
利用数组,以及两个变量, last用于记录栈顶元素的位置,min用于记录栈中元素的最小值;
每一次push,都比较min与x的大小,其次,push操作执行时若数组已满,这需要进行扩容,将数组长度扩大为原来的两倍,并进行数组的迁移。每一次 pop 时,若删除的是最小元素,则遍历数组重新找到最小的元素,然后删除栈顶元素。
时间分析:
push: 最坏情况为O(n),其余为O(1)
pop:最坏情况:O(n),其余为O(1)
top:O(1)
getMin: O(1)
以下是代码:
private int[] array;
private int last;
private int min;
public MinStack() {
array = new int[16];
last=0;
min = 0;
} public void push(int x) {
if(last >= array.length){
this.array = expand(this.array);
}
array[last++] = x;
if(min > x || last==1){
this.min = x;
}
}
public void pop() {
if(last -1 <0){
return;
}
if(this.min == array[last-1]){
this.min = findMin(array,last-1);
}
this.last = this.last - 1;
this.last = this.last < 0 ? 0:this.last;
} public int top() {
if(last -1 <0){
return 0;
}
int result = this.array[last-1];
return result;
} public int getMin() {
return this.min;
} private int[] expand(int[] array){ int[] tempArray = new int[array.length*2];
for (int i=0;i<array.length;i++){
tempArray[i] = array[i];
} return tempArray;
} private int findMin(int array[],int last){ if(last <=0){
return 0;
}
int tempMin = array[last-1];
for (int i=last-1;i>=0;i--){
tempMin = Math.min(array[i],tempMin);
}
return tempMin; }
--------------------------------------------------------我是分割线----------------------------------------------------------------------------
好了,经过讨论学习,学会了一种新的解法:
在上面介绍的基础上在添加一个公式:
首先先介绍一下 一个公式:2*x-minEle_1 < x 其中 x是当前插入的值,minEle_1 是x插入前的最小值
详细思路如下:
入栈:
1.使用一个变量minEle 记录当前栈中的元素 (是真实值)
2.每一次插入一个元素x,比较 x 与 minEle,有如下两种情况:
1)、若x > = minEle,那么直接push进栈,minEle不变
2)、若x < minEle,那么执行以下操作:
a、首先计算要入栈的虚拟值y:y=2*x - minEle ,y入栈(注意此处y不是真实值,但是可以肯定 y < x 原因:因为x < minEle 故 x-minEle < 0 ; x+一个小于0的值一定小于x)
b、其次更新minEle 为 x
以上步骤只为保存前一个最小的值。
出栈:
1、出栈前,比较当前出栈的值Y,存在两种情况:
1)、若Y > minEle 那么直接出栈
2)、若 Y < minEle,那么要执行如下操作:
a、X = 2*minEle - Y ,
b、讲 minEle出栈,同事更新minEle= X
以上步骤用于还原前一次的最小值
根据此算法可以保证 更新minEle的时间复杂度为O(1),弥补了之前自己想法上的不足,同时又不需要使用另一个辅助栈,节约了空间(虽然空间复杂度都是O(N),但是O(N) 与 O(2N)还是有差别的)
以下是写的代码:(注意:由于int 最大值为 2147483647 最小值为 -2147483648 ,所以需要针对极限值做一次单独的转换:
入栈:
当 x - Integer.MIN_VALUE < minEle 时:
int record = last; (此处记录特殊处理的位置,当到此位置时另行处理)
int reminder = minEle % 10 (保存余数);
设Y为要存入的值:Y = x/10 *2 - minEle/10 ,然后将Y入栈
出栈:
判断当前位置 last == record:
若是 : minEle = (x/10 *2 - 当前出栈的值)*10 + reminder
判断当前出栈元素是否小于 minEle
若是: minEle = (x*2 - 当前出栈的值)
否则直接出栈,无需操作
package algorithm;
import java.util.Stack; public class MinStack { private int[] array; private int last; private int min; private int record; private int min_remainder; public MinStack() {
array = new int[16];
last=0;
min = 0;
record=-1;
min_remainder = -1;
} public void push(int x) {
if(last >= array.length){
this.array = expand(this.array);
}
if(last==0){
this.min = x;
array[last++] = x;
}else if(this.min > x){
if(x - (Integer.MIN_VALUE+1) < this.min){
array[last++] = createVirtual(x);
}else {
array[last++] = (x<<1) - this.min;
}
this.min = x; }else {
array[last++] = x;
}
} public void pop() {
if(last -1 <0){
return;
}
if(record == last){
this.min = (this.min/10 - array[last-1] + this.min/10)*10+min_remainder;
}else {
if(array[last-1] < this.min){
int temp = this.min<<1 - array[last-1];
this.min = temp;
}
}
this.last = this.last - 1;
this.last = this.last < 0 ? 0:this.last;
} public int top() {
if(last -1 <0){
return 0;
}
int result = 0;
if(record == last || array[last-1] < this.min){
result = this.min;
}else {
result = this.array[last-1];
}
return result;
} public int getMin() {
return this.min;
} private int[] expand(int[] array){
int[] tempArray = new int[array.length*2];
for (int i=0;i<array.length;i++){
tempArray[i] = array[i];
}
return tempArray;
} private int createVirtual(int x){
int temp = 0;
if(x - (Integer.MIN_VALUE+1) < this.min){
record = this.last;
min_remainder = this.min%10;
temp = x/10 - this.min/10 + x/10; return temp;
}else {
temp = x << 1 - this.min;
} return temp;
} public static void main(String[] args){
MinStack min = new MinStack();
min.push(2147483646);
min.push(2147483646);
min.push(2147483647);
min.top();
min.pop();
System.out.println("min:"+min.getMin());
min.pop();
System.out.println("min:"+min.getMin());
min.pop();
min.push(2147483647);
min.top();
min.push(-2147483648);
System.out.println("top"+min.top());
System.out.println("min:"+min.getMin());
min.pop();
System.out.println("min:"+min.getMin()); } }
LeetCode 腾讯精选50题--最小栈的更多相关文章
- LeetCode 腾讯精选50题--有效的括号
根据题意,第一反应就是使用栈,左右括号相匹配,则将左括号出栈,否则将左括号入栈. 这里我用数组配合“指针”模拟栈的入栈与出栈操作,初始时指针位置指向0,表示空栈,凡遇上左括号则直接入栈,若遇上有括号, ...
- LeetCode 腾讯精选50题--二叉树中的最大路径和
二叉树中的最大路径和 题目描述 给定一个非空二叉树,返回器最大路径和,路径指一条从任意节点出发,到达任意节点的序列,该路径至少包含一个节点,且不一定经过根节点 解题思路 树这一类数据结构我还不是很熟悉 ...
- LeetCode 腾讯精选50题--二叉树的最大深度
求二叉树的最大深度, 基本思路如下: 设定一个全局变量记录二叉树的深度,利用递归,没遍历一层都将临时深度变量+1,并在每一节点递归结束后判断深度大小. 具体代码如下: package algorith ...
- LeetCode 腾讯精选50题--2的幂
在二进制中,2的幂的数字用二进制表示时只会有一位表示为1,其余都为0,基于这个前提,可以有两种方案: 1. 做位移操作 2. 与数值取反并与原数值做与操作,判断是否与原来的数值相同 对于方案1,我的想 ...
- LeetCode 腾讯精选50题--求众数
由于众数是指数组中相同元素的个数超过数组长度的一半,所以有两种思路,一. 先排序,后取排序后的数组的中间位置的值:二. 统计,设定一个变量统计相同元素出现的次数,遍历数组,若与选定的元素相同,统计变量 ...
- LeetCode 腾讯精选50题--只出现一次数字
事先说明,如果不是评论区的大牛一语点破,我可能还会陷在死胡同里出不来,这道题其实很简单,利用了任何一个学过二进制的人都了解的定理,即: 1. 异或操作满足交换律 : a ^ b ^ c 等价于 a ^ ...
- LeetCode 腾讯精选50题--链表排序
解题思路:归并 先把链表拆开,分为两部分,一直拆到只剩一个元素后,进行合并,利用一个临时节点记录重排后的链表的起始位置 合并不难,困难点在于如何拆分链表,自己的大体思路是利用两个指针,一个一次移动两位 ...
- LeetCode 腾讯精选50题--子集
根据题意,找到几何中的所有子集,说实话子集是没有什么头绪的,因为如果采用遍历的方法,稍有遗漏不说,代码的嵌套循环层数随着数组大小的增加而增加,想了很久没有头绪后就去看了看评论,然后就被点破了解题的关键 ...
- LeetCode 腾讯精选50题-- 买卖股票的最佳时机 II
贪心算法: 具体的解题思路如下: II 的解题思路可以分为两部分, 1. 找到数组中差值较大的两个元素,计算差值. 2. 再步骤一最大的元素的之后,继续遍历,寻找差值最大的两个元素 可以得出的是,遍历 ...
随机推荐
- Ajax/Highcharts—动态图表
前面写过“Highcharts的用法总结”,当然了,在实际应用中,图表数据都是要从后台获取的,根据之前的使用,贴一些例子来分享学习. 首先,如果没有获取后台数据,又希望呈现一个动态图表的话,可以很轻易 ...
- 排错:Unable to create a new session key. It is likely that the cache is unavailable.
排错:Unable to create a new session key. It is likely that the cache is unavailable. 问题 登录openstack页面, ...
- backbone之collection
最近要用到backbone.js,网上也找了些资料,但是就看到一个开头还可以,往下看基本就看不下去了,幸好有这本书[LeanpubRead] Backbone.Marionette.js A Gent ...
- Python实现的寻找前5个默尼森数算法示例
Python实现的寻找前5个默尼森数算法示例 本文实例讲述了Python实现的寻找前5个默尼森数算法.分享给大家供大家参考,具体如下: 找前5个默尼森数. 若P是素数且M也是素数,并且满足等式M=2* ...
- Springboot入门5-项目打包部署(转载)
前言 本文主要介绍SpringBoot的一些打包事项和项目部署以及在其中遇到一些问题的解决方案. SpringBoot打包 在SpringBoot打包这块,我们就用之前的一个web项目来进行打包.首先 ...
- linux无密钥登陆
1.在用户目录下执行命令 ssh-keygen -t rsa 一路回车: 2.在当前用户目录下,进入.ssh文件夹(.ssh文件夹为隐藏文件夹,直接进去即可). 在.ssh文件夹下执行命令: cat ...
- Visual Studio Code的设置及插件同步
Visual Studio Code的设置及插件同步 使用Visual Studio Code开发有一段时间了,用起来是极其的顺手,但是唯独一点不爽的就是,Visual Studio Code不像Vi ...
- Java 基础篇之泛型
背景 在没有泛型前,一旦把一个对象丢进集合中,集合就会忘记对象的类型,把所有的对象都当成 Object 类型处理.当程序从集合中取出对象后,就需要进行强制类型转换,这种转换很容易引起 ClassCas ...
- Pandas导入导出&pickle文件模块
Pandas可以读取与存储的文件格式有很多 像csv,excel,json,html等,详细请看官方文档https://pandas.pydata.org/pandas-docs/stable/use ...
- java使用validator进行校验
不管是html页面表单提交的对象数据还是和第三方公司进行接口对接,都需要对接收到的数据进行校验(非空.长度.格式等等).如果使用if一个个进行校验(字段非常多),这是让人崩溃的过程.幸好jdk或hib ...