题目很简单,实现一个最小栈,能够以线形的时间获取栈中元素的最小值

自己的思路如下:

利用数组,以及两个变量, 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题--最小栈的更多相关文章

  1. LeetCode 腾讯精选50题--有效的括号

    根据题意,第一反应就是使用栈,左右括号相匹配,则将左括号出栈,否则将左括号入栈. 这里我用数组配合“指针”模拟栈的入栈与出栈操作,初始时指针位置指向0,表示空栈,凡遇上左括号则直接入栈,若遇上有括号, ...

  2. LeetCode 腾讯精选50题--二叉树中的最大路径和

    二叉树中的最大路径和 题目描述 给定一个非空二叉树,返回器最大路径和,路径指一条从任意节点出发,到达任意节点的序列,该路径至少包含一个节点,且不一定经过根节点 解题思路 树这一类数据结构我还不是很熟悉 ...

  3. LeetCode 腾讯精选50题--二叉树的最大深度

    求二叉树的最大深度, 基本思路如下: 设定一个全局变量记录二叉树的深度,利用递归,没遍历一层都将临时深度变量+1,并在每一节点递归结束后判断深度大小. 具体代码如下: package algorith ...

  4. LeetCode 腾讯精选50题--2的幂

    在二进制中,2的幂的数字用二进制表示时只会有一位表示为1,其余都为0,基于这个前提,可以有两种方案: 1. 做位移操作 2. 与数值取反并与原数值做与操作,判断是否与原来的数值相同 对于方案1,我的想 ...

  5. LeetCode 腾讯精选50题--求众数

    由于众数是指数组中相同元素的个数超过数组长度的一半,所以有两种思路,一. 先排序,后取排序后的数组的中间位置的值:二. 统计,设定一个变量统计相同元素出现的次数,遍历数组,若与选定的元素相同,统计变量 ...

  6. LeetCode 腾讯精选50题--只出现一次数字

    事先说明,如果不是评论区的大牛一语点破,我可能还会陷在死胡同里出不来,这道题其实很简单,利用了任何一个学过二进制的人都了解的定理,即: 1. 异或操作满足交换律 : a ^ b ^ c 等价于 a ^ ...

  7. LeetCode 腾讯精选50题--链表排序

    解题思路:归并 先把链表拆开,分为两部分,一直拆到只剩一个元素后,进行合并,利用一个临时节点记录重排后的链表的起始位置 合并不难,困难点在于如何拆分链表,自己的大体思路是利用两个指针,一个一次移动两位 ...

  8. LeetCode 腾讯精选50题--子集

    根据题意,找到几何中的所有子集,说实话子集是没有什么头绪的,因为如果采用遍历的方法,稍有遗漏不说,代码的嵌套循环层数随着数组大小的增加而增加,想了很久没有头绪后就去看了看评论,然后就被点破了解题的关键 ...

  9. LeetCode 腾讯精选50题-- 买卖股票的最佳时机 II

    贪心算法: 具体的解题思路如下: II 的解题思路可以分为两部分, 1. 找到数组中差值较大的两个元素,计算差值. 2. 再步骤一最大的元素的之后,继续遍历,寻找差值最大的两个元素 可以得出的是,遍历 ...

随机推荐

  1. 【MyBatis】从一千万记录中批量删除八百万条,耗时4m7s

    批量删除主要借助了MySql的limit函数,其次用了in删除. 代码如下: package com.hy.action; import java.io.Reader; import java.uti ...

  2. [MyBatis]最简MyBatis工程

    下载地址:https://files.cnblogs.com/files/xiandedanteng/fillMillionDatum01_191005.rar --END-- 2019年10月5日1 ...

  3. 浅谈WebViewClient与WebChromeClient

    简介:WebViewClient被用来传递单纯的加载一个链接时所发生的事件,比如开始加载,结束加载等,它代表这个链接加载时的最普通的和最笼统的事件,WebChromeClient更多的是传递JS对话框 ...

  4. web.config 配置无后缀文本的访问

    在 www.sslforfree.com 申请ssl免费证书,我参考了别人分享的方法,采用了文件验证的方式.可是按照步骤把文件放好后,一直访问不了,总是跳到了404. 确定文件路径和上传的文件都没问题 ...

  5. Qt编写自定义控件19-图片背景时钟

    前言 图片背景时钟控件,是全套控件(目前共145个)中唯一的几个贴图的控件,这个背景要是不贴图,会画到猝死,必须用美工做好的图贴图作为背景,此控件以前学C#的时候写过,后面在写Qt控件的过程中把他移植 ...

  6. Oracle数据库导入(expdp)和导出(impdp)

    文档最后,列出了常用的一些导入导出的场景,以及一些导入导出的属性说明. 一.数据库导出(expdp) 使用sys或system账号登录oracle 通过"Window + R" 打 ...

  7. Java NIO学习笔记九 NIO与IO对比

    Java NIO与IO Java nio 和io 到底有什么区别,以及什么时候使用nio和io,本文做一个比较. Java NIO和IO之间的主要区别 下表总结了Java NIO和IO之间的主要区别, ...

  8. Java中验证编码格式的一种方法

    package forlittlecatty; import java.io.File; import java.io.FileInputStream; import java.io.IOExcept ...

  9. 树莓派实现摄像头监控(使用motion和mjpg-streamer)

    购买raspBerryCarmen,大概20元, 启动树莓派,安装: `sudo apt install motion` 配置/etc/motion/motion.conf, `sudo vim /e ...

  10. python-Web-django-商城-购物车商品加减

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...