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. 再步骤一最大的元素的之后,继续遍历,寻找差值最大的两个元素 可以得出的是,遍历 ...
随机推荐
- mysql 创建++删除 数据库
创建RUNOOB数据库,并设定编码集为utf8 CREATE DATABASE IF NOT EXISTS RUNOOB DEFAULT CHARSET utf8 COLLATE utf8_gener ...
- POJ3009-Curling 2.0(WA)
POJ3009-Curling 2.0 题意: 要求把一个冰壶从起点“2”用最少的步数移动到终点“3” 其中0为移动区域,1为石头区域,冰壶一旦想着某个方向运动就不会停止,也不会改变方向(想想冰壶在冰 ...
- 解决“mysql不是内部/外部命令,也不是可执行程序,也不是批处理文件”
解决方案: 1.切换到mysql.exe文件所在目录: 2.将mysql.exe文件所在目录添加到操作系统内的环境变量中: 如何添加环境变量: 1.右击“我的电脑”——>属性——>高级—— ...
- 将蓝牙rssi(信号强度)转换成距离
遇到一个问题,是将蓝牙rssi(信号强度)转换成距离的问题. 这一问题没有准确的解决办法,但是有人做过一个拟合回归函数,其变化规律比较类似于rssi的变化规律,函数如下: d = ^(abs(rssi ...
- python从入门到放弃之Tensorflow(一)
Tensorflow使用错误集锦: 错误1 : FutureWarning: Conversion of the second argument of issubdtype from ‘float’ ...
- 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-6.微信扫码登录回调本地域名映射工具Ngrock
笔记 6.微信扫码登录回调本地域名映射工具Ngrock 简介:讲解微信扫码回调本地域名ngrock讲解 1.为什么要用这个,微信扫码需要配置回调,需要配置对应的域名 ...
- 搭建Kubernetes容器集群管理系统
1.Kubernetes 概述 Kubernetes 是 Google 开源的容器集群管理系统,基于 Docker 构建一个容器的调度服务,提供资源调度.均衡容灾.服务注册.劢态扩缩容等功能套件. 基 ...
- SpringBoot: 6.文件上传(转)
1.编写页面uploadFile.html <!DOCTYPE html> <html lang="en"> <head> <meta c ...
- GB、GBDT、XGboost理解
GBDT和xgboost在竞赛和工业界使用都非常频繁,能有效的应用到分类.回归.排序问题,虽然使用起来不难,但是要能完整的理解还是有一点麻烦的.本文尝试一步一步梳理GB.GBDT.xgboost,它们 ...
- k8s 网络模型解析之原理
今天研究了一下k8s的网络模型,该解析基于flannel vxlan+ kubeproxy iptables 模式. 一.Docker 首先分析一下Docker层面的网络模型,我们知道容器是基于内核的 ...