• 栈和队列的练习题


    ​1. 用两个栈实现队列

    用两个栈来实现一个队列,使用n个元素来完成 n 次在队列尾部插入整数(push)和n次在队列头部删除整数(pop)的功能。 队列中的元素为int类型。保证操作合法,即保证pop操作时队列内已有元素。

    数据范围:n≤1000

    要求:存储n个元素的空间复杂度为 O(n) ,插入与删除的时间复杂度都是 O(1)

    解题思路:

    借助栈的先进后出规则模拟实现队列的先进先出。想用用栈实现队列,需要把一个栈中的元素挨个pop 出来,然后再 push 进另一个栈中。题中的 push 方法中就直接将元素插入 stack1 中。pop 方法中,当 stack2 不为空时,弹出 stack2 的栈顶元素;如果 stack2 为空时,将 stack1 中的元素先pop 出去,然后再 push 到 stack2 中。

    代码实现:

    1. import java.util.*;
    2. import java.util.Stack;
    3. public class Solution {
    4. Stack stack1 = new Stack();
    5. Stack stack2 = new Stack();
    6. public void push(int node) {
    7. stack1.push(node);
    8. }
    9. public int pop() {
    10. // 如果 stack2 为空,先让 stack1 pop出栈顶元素
    11. if(stack2.size() <= 0) {
    12. while(stack1.size() != 0) {
    13. stack2.push(stack1.pop());
    14. }
    15. }
    16. // 如果 stack2 不为空,直接弹出栈顶元素
    17. return stack2.pop();
    18. }
    19. }

    2. 包含min函数的栈 

    定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的 min 函数,输入操作时保证 pop、top 和 min 函数操作时,栈中一定有元素。

    此栈包含的方法有:

    push(value):将value压入栈中

    pop():弹出栈顶元素

    top():获取栈顶元素

    min():获取栈中最小元素

    数据范围:操作数量满足 0≤n≤300  ,输入的元素满足 ∣val∣≤10000 
    进阶:栈的各个操作的时间复杂度是 O(1)  ,空间复杂度是 O(n)

    解题思路:

    使用双栈,一个栈中正常 push 元素进行 pop、top 操作,另一个栈记录每次 push 的最小值。第一个栈 push 元素时,当另一个栈中没有元素时将当前插入的元素 push 进去,然后每一次插入元素时两个栈中的栈顶元素进行比较。如果当前插入的元素小于第二个栈的栈顶元素,就将当前元素 push 到第二个栈中,否则就将第二个栈中的栈顶元素重新入栈。这样第二个栈顶元素仍然是最小值。

    画图理解:

    代码实现:

    1. import java.util.*;
    2. import java.util.Stack;
    3. public class Solution {
    4. Stack stack1 = new Stack<>();
    5. // stack2 中存放最小值
    6. Stack stack2 = new Stack<>();
    7. public void push(int node) {
    8. stack1.push(node);
    9. // 如果 stack2 为空,stack2的栈顶元素大于当前插入的值
    10. if(stack2.isEmpty() || stack2.peek() > node) {
    11. // 就将当前插入的元素入栈
    12. stack2.push(node);
    13. } else {
    14. // 如果 stack2 不为空,且当前栈顶元素小于当前插入的值
    15. // 就将 stack2 当前栈顶元素重新入栈
    16. stack2.push(stack2.peek());
    17. }
    18. }
    19. public void pop() {
    20. stack1.pop();
    21. stack2.pop();
    22. }
    23. public int top() {
    24. return stack1.peek();
    25. }
    26. public int min() {
    27. return stack2.peek();
    28. }
    29. }

    3. 有效括号序列 

    给出一个仅包含字符'(',')','{','}','['和']',的字符串,判断给出的字符串是否是合法的括号序列
    括号必须以正确的顺序关闭,"()"和"()[]{}"都是合法的括号序列,但"(]"和"([)]"不合法。

    解题思路:

    括号的有效是指 "( )[ ]{ }"或者这种“( [ ] )”,也就是符合先进后出的原理,最左出现的括号对应的括号一定在最右。所以就可以使用栈来完成,遇到左括号就将相应匹配的右括号加入栈中,后续如果是合法的,右括号的顺序就是栈中弹出的顺序。

    1. public class Solution {
    2. /**
    3. *
    4. * @param s string字符串
    5. * @return bool布尔型
    6. */
    7. public boolean isValid (String s) {
    8. // write code here
    9. Stack stack = new Stack<>();
    10. for(char c : s.toCharArray()) {
    11. if(c == '(') {
    12. stack.push(')');
    13. } else if(c == '{') {
    14. stack.push('}');
    15. } else if(c == '[') {
    16. stack.push(']');
    17. } else if(stack.isEmpty() || c != stack.pop()) {
    18. return false;
    19. }
    20. }
    21. return stack.isEmpty();
    22. }
    23. }

    4. 表达式求值 

    请写一个整数计算器,支持加减乘三种运算和括号。

    数据范围:1000≤∣s∣≤100,保证计算结果始终在整型范围内

    要求:空间复杂度: O(n),时间复杂度 O(n)

    解题思路:

    使用双栈存放数字和运算符,其中需要考虑的是运算符优先级和括号的处理问题。对于优先级问题,乘法优先,加减法最后。当遇到乘法时,把前一个数和后一个数相乘,遇到加减法,把这些数字都暂存起来,最后再相加。处理括号问题,就是将括号中的部分看成一个整体,每次遇到左括号,将括号放入栈中,直到遇到右括号,再计算括号中的部分。

    代码实现:

    1. public class Solution {
    2. /**
    3. * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
    4. * 返回表达式的值
    5. * @param s string字符串 待计算的表达式
    6. * @return int整型
    7. */
    8. public int solve (String s) {
    9. // write code here
    10. // 存放所有的运算符
    11. Stack ops = new Stack<>();
    12. // 存放所有的数字
    13. Stack nums = new Stack<>();
    14. if(s.length() < 2) {
    15. return (int)s.charAt(0);
    16. }
    17. // 由于第一个数可能是负数,为了减少边界判断,第一个数放0
    18. nums.push(0);
    19. for(int i = 0; i < s.length();) {
    20. // 如果是左括号,将左括号放入到 ops 栈中
    21. if(s.charAt(i) == '(') {
    22. ops.push(s.charAt(i++));
    23. } else if(s.charAt(i) == ')') {
    24. while(ops.peek() != '(') {
    25. // 计算括号中的数
    26. nums.push(calculate(ops.pop(), nums.pop(), nums.pop()));
    27. }
    28. // 弹出右括号
    29. ops.pop();
    30. i++;
    31. } else if(s.charAt(i) == '*') {
    32. ops.push('*');
    33. i++;
    34. } else if(s.charAt(i) == '+' || s.charAt(i) == '-') {
    35. if(ops.isEmpty()) {
    36. ops.push(s.charAt(i++));
    37. } else if(ops.peek() == '*' || ops.peek() == '-' || ops.peek() == '+') {
    38. nums.push(calculate(ops.pop(), nums.pop(), nums.pop()));
    39. } else ops.push(s.charAt(i++));
    40. } else {
    41. // 如果不是运算符,判断是否是数字,将连续的数字字符转化为数字
    42. int num = 0;
    43. while(i < s.length() && isNum(s.charAt(i))) {
    44. num = 10 * num + s.charAt(i++) - '0';
    45. }
    46. nums.push(num);
    47. }
    48. }
    49. int res = 0;
    50. // 如果运算符不为空,将所有的中间值计算
    51. while(!ops.isEmpty()) {
    52. res = res + nums.push(calculate(ops.pop(), nums.pop(), nums.pop()));
    53. }
    54. return res;
    55. }
    56. // 加减乘除计算
    57. public int calculate(char op, int b, int a) {
    58. if(op == '+') {
    59. return a + b;
    60. }
    61. if(op == '-') {
    62. return a - b;
    63. }
    64. if(op == '*') {
    65. return a * b;
    66. }
    67. return 0;
    68. }
    69. // 判断是否是数字
    70. public boolean isNum(char num) {
    71. if('0' <= num && num <= '9') {
    72. return true;
    73. } else {
    74. return false;
    75. }
    76. }
    77. }

    5. 两个队列实现栈

    请你仅使用两个队列实现一个后入先出的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty),输入数据保证 pop、top函数操作时,栈中一定有元素。

    void push(int element) 将元素 element 压入栈顶。

    int pop() 移除并返回栈顶元素。

    int top() 返回栈顶元素。

    bool empty() 如果栈是空的,返回 true ;否则,返回 false 。

    解题思路:

    根据栈和队列各自的特性,栈是先进后出,队列是先进先出,用队列模拟实现栈,这里需要两个队列,q1 是主栈,q2 是辅助栈,当需要插入元素时,总是将新元素插入到空的队列中,然后再将另一个有数据的队列中的数据,取出插入到存放新元素的队列中,即可完成栈的功能。

     画图理解:

    插入元素时,如果 q1 为空,就直接插入元素。

     如果 q1 不为空,将 q1 中的元素加入到 q2 中,然后在 q1 中插入新元素,再将 q2 中的元素插入到 q1 中,这样就符合栈的弹出顺序。

    弹出元素时,直接弹出。

    代码实现:

    1. import java.util.*;
    2. public class Solution {
    3. Queue queue1 = new LinkedList();
    4. Queue queue2 = new LinkedList();
    5. public void push(int element) {
    6. while(!queue1.isEmpty()) {
    7. queue2.add(queue1.poll());
    8. }
    9. queue1.add(element);
    10. while(!queue2.isEmpty()) {
    11. queue1.add(queue2.poll());
    12. }
    13. }
    14. public int pop() {
    15. return queue1.poll();
    16. }
    17. public int top() {
    18. return queue1.peek();
    19. }
    20. public boolean empty() {
    21. return queue1.isEmpty();
    22. }
    23. }

    活动地址:CSDN21天学习挑战赛

  • 相关阅读:
    paddledetection在window使用cpu快速上手 & 在cpu端训练自己的VOC类型数据集
    [附源码]计算机毕业设计JAVAjsp远程学习系统
    git从入门到会用
    Linux网络:网络层IP协议 链路层MAC协议
    Linux系统上2个非常有意思也最特殊的目录/run和/proc的作用以及监测项
    运维理想和现实,你是?
    网页大作业代码自取
    使用 C# 读取 zip 压缩包解压文件的方法及注意事项
    C++语言实现网络爬虫详细代码
    美新科技过会:收入依赖美国、产能利用率低,林东亮等均为香港籍
  • 原文地址:https://blog.csdn.net/AlinaQ05/article/details/126155221