Leetcode面T3(1-5)栈

class TripleInOne {

private int[] arr = {};

private int[] size = {};

private int stackSize;

public TripleInOne(int stackSize) {

this.stackSize = stackSize;

// 第一个栈 [0stackSize, 1stackSize),第二个栈 [1stackSize, 2stackSize),第三个栈 [2stackSize, 3stackSize)

arr = new int[3*stackSize];

size = new int[] {0, 0, 0};

}

public void push(int stackNum, int value) {

int length = size[stackNum];

if (length < stackSize) {

arr[stackNum*stackSize+length] = value;

size[stackNum] = length + 1;

}

}

public int pop(int stackNum) {

int topVal = peek(stackNum);

if (size[stackNum] > 0)

size[stackNum] -= 1;

return topVal;

}

public int peek(int stackNum) {

if (size[stackNum] == 0)

return -1;

return arr[stackNum*stackSize+size[stackNum]-1];

}

public boolean isEmpty(int stackNum) {

return size[stackNum] == 0;

}

}

Q3.2 栈的最小值

请设计一个栈,除了常规栈支持的pop与push函数以外,还支持min函数,该函数返回栈元素中的最小值。执行push、pop和min操作的时间复杂度必须为O(1)。

示例:

MinStack minStack = new MinStack();

minStack.push(-2);

minStack.push(0);

minStack.push(-3);

minStack.getMin(); --> 返回 -3.

minStack.pop();

minStack.top(); --> 返回 0.

minStack.getMin(); --> 返回 -2.

思路:

利用一个min变量标记当前的最小栈内元素。压栈时,如果最小元素发生变更,就把当前最小元素也进行压栈,标记这一次的最小元素变更情况。出栈时,如果遇到当前最小值与栈顶元素相同的情况,就连着这个元素一起弹出,并将当前最小值更新为这个元素的下一个元素。理论上这个方式比双栈更省空间。

class MinStack {

/**

  • initialize your data structure here.

*/

Stack stack;

//将最小值初始化为整型的最大值

int min = Integer.MAX_VALUE;

public MinStack() {

//初始化一个栈

stack = new Stack();

}

public void push(int x) {

//当min==x时要重新存一下最小值,否则最小的值min会出现两次

//一次是当前的min,一次是维护当前min的第一个值

//如果if的条件改为min>x,则会影响pop()出栈的逻辑

if (min >= x) {

stack.push(min);

//维护最小值序列的第一个值(最小),并赋值给min

min = x;

}

//入栈

stack.push(x);

}

public void pop() {

//栈为空时返回空即可

if (stack.isEmpty()) {

return;

}

//长度为1时其实只存了min的初值,没有存其他值

if (stack.size() == 1) {

min = Integer.MAX_VALUE;

//min==top()说明栈顶元素是一段维护最小值序列的第一个值(即最小值)

} else if (min == top()) {

//先把这个最小值弹出

stack.pop();

//此时的栈顶元素是之前入栈时额外存入的最小值

min = top();

}

//出栈

stack.pop();

}

public int top() {

//此处直接调用java中与stack相关的API即可

return (int)stack.peek();

}

public int getMin() {

//min可以随时返回,达到了时间复杂度必须为O(1)的要求

return min;

}

}

/**

  • Your MinStack object will be instantiated and called as such:

  • MinStack obj = new MinStack();

  • obj.push(x);

  • obj.pop();

  • int param_3 = obj.top();

  • int param_4 = obj.getMin();

*/

Q3.3 堆盘子

堆盘子。设想有一堆盘子,堆太高可能会倒下来。因此,在现实生活中,盘子堆到一定高度时,我们就会另外堆一堆盘子。请实现数据结构SetOfStacks,模拟这种行为。SetOfStacks应该由多个栈组成,并且在前一个栈填满时新建一个栈。此外,SetOfStacks.push()和SetOfStacks.pop()应该与普通栈的操作方法相同(也就是说,pop()返回的值,应该跟只有一个栈时的情况一样)。 进阶:实现一个popAt(int index)方法,根据指定的子栈,执行pop操作。

示例1:

输入:

[“StackOfPlates”, “push”, “push”, “popAt”, “pop”, “pop”]

[[1], [1], [2], [1], [], []]

输出:

[null, null, null, 2, 1, -1]

示例2:

输入:

[“StackOfPlates”, “push”, “push”, “push”, “popAt”, “popAt”, “popAt”]

[[2], [1], [2], [3], [0], [0], [0]]

输出:

[null, null, null, null, 2, 1, 3]

class StackOfPlates {

//存储多个栈的容器

private List<Stack> stackList;

//盘子高度的最大值

private int cup;

public StackOfPlates(int cap) {

//构造函数完成初始化的功能

this.cup = cap;

stackList = new ArrayList<>();

}

public void push(int val) {

if (cup <= 0) {

return;

}

//这两个逻辑或的条件一定不能反过来写,只有栈不为空时才能有size==cup的判断

if (stackList.isEmpty() || stackList.get(stackList.size() - 1).size() == cup) {

//新建一个栈存入容器

Stack stack = new Stack();

stack.push(val);

stackList.add(stack);

return;

}

//栈未达到最大值就从容器中最后一个栈的末尾入栈

stackList.get(stackList.size() - 1).push(val);

}

public int pop() {

//直接调用已定义好的方法,下标参数为容器中最后一个栈的下标

return popAt(stackList.size() - 1);

}

public int popAt(int index) {

//下标越界

if (index < 0 || index >= stackList.size()) {

return -1;

}

//得到容器中下标对应的栈

Stack stack = stackList.get(index);

//栈为空

if (stack.isEmpty()) {

return -1;

}

//出栈

int res = stack.pop();

//栈为空时要把这个空栈删除

if (stack.isEmpty()) {

stackList.remove(index);

}

//将出栈的元素返回

return res;

}

}

/**

  • Your StackOfPlates object will be instantiated and called as such:

  • StackOfPlates obj = new StackOfPlates(cap);

  • obj.push(val);

  • int param_2 = obj.pop();

  • int param_3 = obj.popAt(index);

*/

Q3.4 化栈为队

实现一个MyQueue类,该类用两个栈来实现一个队列。

示例:

MyQueue queue = new MyQueue();

queue.push(1);

queue.push(2);

queue.peek();  // 返回 1

queue.pop();   // 返回 1

queue.empty(); // 返回 false

我们知道:同一段序列,分别存进一个栈和一个队列,那么出栈序列T和出队序列S顺序刚好是相反的。

那么,假如我们有两个栈的话,一段序列list通过第一个栈后,再压入第二个栈,这时第二个栈的出栈序列应该和list直接压入队列后的出队序列是一样的。

既然如此,我们用两个栈就可以模拟队列,一个栈专门用来存入数据,记为StackWrite;一个栈专门用来读取数据,记为StackRead。基于上面的结论,我们每次入队时,就把数据压入StackWrite,每次读数据时,就把StackWrite中的数据再压入StackRead,这时StackRead中的栈顶元素就是我们所期望的队首元素

在出队的时候,要注意一点:

  • 如果StackRead中有数据,那么就直接弹出StackRead的栈顶元素;

  • 如果StackRead为空,先考虑把StackWrite中的元素压入StackRead,再弹出StackRead的栈顶元素。

class MyQueue {

Stack stackWrite; // 存数据

Stack stackRead; // 读数据

/** Initialize your data structure here. */

public MyQueue() {

stackWrite = new Stack<>();

stackRead = new Stack<>();

}

/** Push element x to the back of queue. */

public void push(int x) {

stackWrite.push(x);

}

/** Removes the element from in front of queue and returns that element. */

public int pop() {

peek();

return stackRead.pop();

}

/** Get the front element. */

public int peek() {

if (!stackRead.isEmpty()) {

return stackRead.peek();

}

while (!stackWrite.isEmpty()) {

stackRead.push(stackWrite.pop());

}

return stackRead.peek();

}

/** Returns whether the queue is empty. */

public boolean empty() {

return stackRead.isEmpty() && stackWrite.isEmpty();

}

}

/**

  • 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();

*/

Q3.5 栈排序

栈排序。 编写程序,对栈进行排序使最小元素位于栈顶。最多只能使用一个其他的临时栈存放数据,但不得将元素复制到别的数据结构(如数组)中。该栈支持如下操作:push、pop、peek 和 isEmpty。当栈为空时,peek 返回 -1。

示例1:

输入:

[“SortedStack”, “push”, “push”, “peek”, “pop”, “peek”]

[[], [1], [2], [], [], []]

输出:

[null,null,null,1,null,2]

示例2:

输入:

[“SortedStack”, “pop”, “pop”, “push”, “pop”, “isEmpty”]

[[], [], [], [1], [], []]

输出:

[null,null,null,null,null,true]

class SortedStack {

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-2fUljVQ2-1715682645264)]

[外链图片转存中…(img-VPugAGgz-1715682645266)]

[外链图片转存中…(img-WU5sw4oc-1715682645267)]

[外链图片转存中…(img-T4sEAtXV-1715682645268)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值