• 《剑指Offer》栈&队列全题——妙解思路,难度由浅入深


    目录

    JZ9 用两个栈实现队列

    JZ30 包含min函数的栈

    JZ31 栈的压入、弹出序列

    JZ73 翻转单词序列

    JZ59 滑动窗口的最大值


    JZ9 用两个栈实现队列

    思路(蓄水池):创建两个栈,入栈时先入栈一,出栈时,先检测栈二是否为空,若为空,将栈一所有元素全部弹出并压入栈二,若不为空,则直接将栈二元素弹出即可。

            以下链接是博主早已整理出画图理解,包括两个栈如何实现队列?两个队列如何实现栈?快来看看吧!

    http://t.csdn.cn/vyc3o

    1. Stack stack1 = new Stack();
    2. Stack stack2 = new Stack();
    3. public void push(int node) {
    4. if(stack2.isEmpty()){
    5. stack1.push(node);
    6. }else{
    7. while(!stack2.isEmpty()){
    8. stack1.push(stack2.pop());
    9. }
    10. stack1.push(node);
    11. }
    12. }
    13. public int pop() {
    14. int ret = 0;
    15. if(!stack2.isEmpty()){
    16. ret = stack2.pop();
    17. }else{
    18. while(!stack1.isEmpty()){
    19. stack2.push(stack1.pop());
    20. }
    21. ret = stack2.pop();
    22. }
    23. return ret;
    24. }

    JZ30 包含min函数的栈

    思路(此题是头条的笔试题):建立两个栈,一个是主栈,一个是最小栈,每次压栈主栈都会进行压栈,而最小栈只有为空或是压栈元素小于最小栈栈顶元素即可;出栈时主栈每次必须出栈并在出栈时检测是否与最小栈栈顶元素相等,若相等则一起弹出,若不相等,则不用弹出~

    1. Stack stack = new Stack<>();
    2. Stack minStack = new Stack<>();
    3. public void push(int node) {
    4. //最小栈为空直接放数据
    5. if(minStack.isEmpty()){
    6. minStack.push(node);
    7. }else if(minStack.peek() >= node){//小于等于最小栈栈顶元素都要放入
    8. minStack.push(node);
    9. }
    10. //主栈必须放
    11. stack.push(node);
    12. }
    13. public void pop() {
    14. //检测主栈元素是否等于最小栈栈顶元素,若等于也需要pop
    15. //这里要注意pop和peek操作返回的都是泛型类,没有整数比较时需要强制类型转化
    16. if((int)stack.pop() == (int)minStack.peek()){
    17. minStack.pop();
    18. }
    19. }
    20. public int top() {
    21. return stack.peek();
    22. }
    23. public int min() {
    24. return minStack.peek();
    25. }

    JZ31 栈的压入、弹出序列

    思路:创建一个栈,将所给入栈序列一个一个入栈,同时将每个入栈元素与弹出序列的元素进行比较,若相等就弹出,不相等则继续压栈,往复操作,直到遍历完为止

    1. public boolean IsPopOrder(int [] pushA,int [] popA) {
    2. Stack stack = new Stack<>();
    3. int count = 0;//计数:与压栈数据匹配则加一
    4. for(int i = 0; i < pushA.length; i++){
    5. if(pushA[i] == popA[count]){
    6. //先压栈,再判断
    7. stack.push(pushA[i]);
    8. while(stack.peek() == popA[count]){
    9. stack.pop();
    10. count++;
    11. //popA遍历完说明正确
    12. if(count == pushA.length){
    13. return true;
    14. }
    15. /**
    16. *弹出栈后,可能一个元素也不剩,这时再到while里判断,
    17. *有可能能造成对空指针的解引用操作
    18. */
    19. if(stack.empty()){
    20. break;
    21. }
    22. }
    23. }
    24. else{
    25. stack.push(pushA[i]);
    26. }
    27. }
    28. return false;
    29. }

    JZ73 翻转单词序列

    此题给出了进阶要求:空间复杂度 O(n) ,时间复杂度 O(n) ,栈解决依然符合要求

    思路:先将所给字符串分割放入数组中,创建一个栈,直接压栈出栈即可得到反转单词(注意空格),是不是很妙~

    1. public String ReverseSentence(String str) {
    2. Stack stack = new Stack<>();
    3. //每个单词用空格分开
    4. String[] strArr = str.split(" ");
    5. StringBuilder ret = new StringBuilder();
    6. //压栈
    7. for(int i = 0; i < strArr.length; i++){
    8. //注意空格隔开
    9. if(i != 0){
    10. stack.push(" ");
    11. }
    12. stack.push(strArr[i]);
    13. }
    14. //出栈
    15. while(!stack.isEmpty()){
    16. ret.append(stack.pop());
    17. }
    18. return ret.toString();
    19. }

    JZ59 滑动窗口的最大值

    解法一(双指针法,若不考虑时间复杂度,则可以通过):通过双指针来维护滑动窗口,并且每次遍历小的滑动窗口,比较出最大值后放入顺序表,往复操作即可~

    1. public ArrayList maxInWindows(int [] num, int size) {
    2. ArrayList array = new ArrayList<>();
    3. //假定最大值
    4. for(int i = 0; i < num.length - size + 1; i++){
    5. int left = i;
    6. int right = left + size - 1;
    7. //求最大值
    8. int max = num[left];//假定最大值
    9. for(int j = left; j <= right; j++){
    10. if(num[j] > max){
    11. max = num[j];
    12. }
    13. }
    14. array.add(max);
    15. }
    16. return array;
    17. }

    解法二(双端队列):创建一个双端队列,保持对头存放数组最大值下标,窗口滑动每滑动一次,就要判断当前最大值是否还是真的最大值,同时新增元素从队尾开始比较,比他小的全部出队,往复操作即可~

    1. public static ArrayList maxInWindows(int [] num, int size){
    2. ArrayList array = new ArrayList<>();
    3. //长度为零直接返回空表
    4. if(size == 0) {
    5. return array;
    6. }
    7. int begin = 0;
    8. //双端队列用来存放下标
    9. Deque deque = new LinkedList<>();
    10. for(int i = 0; i < num.length; i++){
    11. //制造虚拟滑动窗口起点
    12. begin = i - size + 1;
    13. //若为空,先放入元素假定为最大值
    14. if(deque.isEmpty()){
    15. deque.add(i);
    16. }
    17. else if(begin > deque.peekFirst()){
    18. deque.pollFirst();
    19. }
    20. //队尾开始比较,把比他小的都出队
    21. while((!deque.isEmpty()) && num[deque.peekLast()] <= num[i]){
    22. deque.pollLast();
    23. }
    24. deque.add(i);
    25. if(begin >= 0){
    26. array.add(num[deque.peekFirst()]);
    27. }
    28. }
    29. return array;
    30. }

     

  • 相关阅读:
    人工神经网络的基本模型,神经网络解剖学模型图
    智能合约平台开发指南
    云南民族文化旅游网页设计制作 简单静态HTML网页作品 我的家乡网页作业成品 学生旅游网站模板
    古代汉语复习资料与练习题(适合王力版教材)
    HTTP之常见问答
    MATLAB R2023b安装包下载链接及软件安装教程
    C#在并发编程使用Frozen来确保线程安全性
    中国微信生态行业投资价值分析及发展趋势预测报告
    变压器分析
    解锁新技能《SkyWalking-aop服务搭建》
  • 原文地址:https://blog.csdn.net/CYK_byte/article/details/126443474