• 代码随想录第七章 栈与队列


    1、leecode232 用栈实现队列

    使用栈模拟队列的行为,仅使用一个栈是不行的,所以需要两个栈,一个是输入栈,一个是输出栈。

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. class MyQueue {
    8. private:
    9. stack<int> stack_in;
    10. stack<int> stack_out;
    11. public:
    12. void push(int value) {
    13. stack_in.push(value);
    14. }
    15. int pop() {
    16. if (stack_out.empty()) {
    17. while (!stack_in.empty()) {
    18. stack_out.push(stack_in.top());
    19. stack_in.pop();
    20. }
    21. }
    22. int result = stack_out.top();
    23. stack_out.pop();
    24. return result;
    25. }
    26. int top() {
    27. if (stack_out.empty()) {
    28. while (!stack_in.empty()) {
    29. stack_out.push(stack_in.top());
    30. stack_in.pop();
    31. }
    32. }
    33. int result = stack_out.top();
    34. return result;
    35. }
    36. bool empty() {
    37. return stack_in.empty() && stack_out.empty();
    38. }
    39. };
    40. void main() {
    41. MyQueue queue;
    42. queue.push(1);
    43. queue.push(2);
    44. queue.push(3);
    45. cout << "the first value: " << queue.pop() << endl;
    46. cout << "the next value: " << queue.pop() << endl;
    47. cout << "the next value: " << queue.pop() << endl;
    48. cout << "hello world" << endl;
    49. }

    2、用队列实现栈。 leetcode225

    队列的规则是先进先出,把一个队列中的数据导入另一个队列,数据的顺序并没有变。所以用栈实现队列和用队列实现栈的思路是不一样的,取决于这两个数据结构的性质。如果用两个对列实现栈,那么两个队列就没有输入队列和输出队列的关系,另一个队列完全是用来备份的。

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. class MyStack {
    8. private:
    9. queue<int> queue_fir;
    10. queue<int> queue_sec;
    11. public:
    12. void push(int val) {
    13. queue_fir.push(val);
    14. }
    15. int pop() {
    16. int size = queue_fir.size();
    17. size--;
    18. while (size--) {
    19. queue_sec.push(queue_fir.front());
    20. queue_fir.pop();
    21. }
    22. int result = queue_fir.front();
    23. queue_fir.pop();
    24. queue_fir = queue_sec;
    25. while (!queue_sec.empty()) {
    26. queue_sec.pop();
    27. }
    28. return result;
    29. }
    30. int top() {
    31. return queue_fir.back();
    32. }
    33. bool empty() {
    34. return queue_fir.empty();
    35. }
    36. };
    37. void main() {
    38. MyStack stack;
    39. stack.push(1);
    40. stack.push(2);
    41. stack.push(3);
    42. cout << stack.pop() << endl;
    43. cout << stack.pop() << endl;
    44. cout << stack.pop() << endl;
    45. cout << "hello world" << endl;
    46. }

    3、匹配括号 leetcode20

    这里有三种不匹配的情况

    (1)、第一种情况,字符串中左方向的括号多余了,所以不匹配。

    第一种情况:已经遍历了字符串,但是栈不为空,说明有相应的左括号,但没有右括号,所以返回错误。

    (2)、第二种情况,括号没有多余,但是括号的类型不匹配。

    遍历字符串的过程中,发现栈中没有要匹配的字符,返回错误。

    (3)、第三种情况,字符串中右方向的括号多余了,所以不匹配。

    在遍历字符串的过程中栈已经为空,没有匹配的字符了,说明右括号没有找到对应的左括号,返回错误。

    那么什么时候说明左括号和右括号全部匹配了呢?如果遍历字符串之后,栈是空的,则说明全都匹配了。

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. class Solution {
    8. private:
    9. stack<int> st;
    10. public:
    11. bool IsValid(string& s) {
    12. for (int i = 0; i < s.size(); i++) {
    13. if (s[i] == '(') {
    14. st.push(')');
    15. }
    16. else if (s[i] == '{') {
    17. st.push('}');
    18. }
    19. else if (s[i] == '[') {
    20. st.push(']');
    21. }
    22. else if (st.empty() || st.top() != s[i]) {
    23. return false;
    24. }
    25. else {
    26. st.pop();
    27. }
    28. }
    29. return st.empty();
    30. }
    31. };
    32. void main() {
    33. string s = "(){}[]{[]}";
    34. Solution slo;
    35. slo.IsValid(s);
    36. cout << "hello world" << endl;
    37. }

    4、滑动窗口最大值 leetcode239

    一个大小为k的滑动窗口,从前向后在数组nums上移动,返回滑动窗口每移动一次时窗口中的最大值。

    (1)、设计单调对列,设计的时候,pop和push操作保持如下规则:

    pop():如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不进行任何操作。

    push():如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于或等于队列入口元素的数值。

    基于以上规则,每次窗口移动的时候,只要调用que.front()就可以返回当前窗口的最大值。

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. using namespace std;
    8. //单调队列,从大到小
    9. class MyQueue {
    10. private:
    11. deque<int> que;
    12. //使用deque实现单调队列
    13. public:
    14. //每次弹出元素时,比较当前要弹出元素的数值是否等于队列出口元素的数值,如果相等则弹出。
    15. //弹出元素之前,需要判断队列当前是否为空
    16. void pop(int value) {
    17. if (!que.empty() && value == que.front()) {
    18. que.pop_front();
    19. }
    20. }
    21. //如果要push的数组大于入口元素的数值,那么就将队列入口元素弹出,知道push的数值小于或等于对列入口元素的数值。
    22. //这样就保持了队列中的数值是从大到小的单调递减了。
    23. void push(int value) {
    24. while (!que.empty() && value > que.back()) {
    25. que.pop_back();
    26. }
    27. que.push_back(value);
    28. }
    29. int front() {
    30. return que.front();
    31. }
    32. };
    33. void main() {
    34. cout << "hello world" << endl;
    35. }

    这样就用deque实现了一个单调队列,接下来解决求滑动窗口最大值的问题就简单了。

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. using namespace std;
    8. class Slotuion {
    9. private:
    10. //单调队列,从大到小
    11. class MyQueue {
    12. private:
    13. deque<int> que;
    14. //使用deque实现单调队列
    15. public:
    16. //每次弹出元素时,比较当前要弹出元素的数值是否等于队列出口元素的数值,如果相等则弹出。
    17. //弹出元素之前,需要判断队列当前是否为空
    18. void pop(int value) {
    19. if (!que.empty() && value == que.front()) {
    20. que.pop_front();
    21. }
    22. }
    23. //如果要push的数组大于入口元素的数值,那么就将队列入口元素弹出,知道push的数值小于或等于对列入口元素的数值。
    24. //这样就保持了队列中的数值是从大到小的单调递减了。
    25. void push(int value) {
    26. while (!que.empty() && value > que.back()) {
    27. que.pop_back();
    28. }
    29. que.push_back(value);
    30. }
    31. int front() {
    32. return que.front();
    33. }
    34. };
    35. private:
    36. MyQueue que;
    37. public:
    38. vector<int> MaxSlidingWindow(vector<int> &input,int k) {
    39. vector<int> result;
    40. for (int i = 0; i < k; i++) {
    41. que.push(input[i]);
    42. }
    43. result.push_back(que.front());
    44. for (int i = k; i < input.size(); i++) {
    45. que.push(input[i]);
    46. que.pop(input[i - k]);
    47. result.push_back(que.front());
    48. }
    49. return result;
    50. }
    51. };
    52. void main() {
    53. vector<int> input = { 2,4,-2,-4,3,1,5 };
    54. int k = 4;
    55. Slotuion slo;
    56. slo.MaxSlidingWindow(input, k);
    57. cout << "hello world" << endl;
    58. }

    5、前K个高频元素 leetcode347

    在一个数组中找到出现频率前k高的元素。

    这道题目主要涉及如下三个部分:

    (1)、统计元素出现的次数;

    (2)、对次数进行排序;

    (3)、找出前k个高频元素。

    首先统计元素出现的次数,可以使用map进行统计。然后对次数进行排序,这里可以使用一种容器适配器即优先级对列。

    优先级队列是一个拥有权值的queue,其内部元素按照元素的权值排列。权值较高者排在最前优先出队。其中缺省情况下系统是通过一个max-heap以堆实现完成排序特性,表现为一个vector表现的完全二叉树。

    1、优先级队列介绍

    这是一个queue,所以只允许在底端加入元素,并从顶端取出元素。
    但是优先级队列中的元素并非依照被推入队列的顺序排列。而是自动依照元素的权值排列。权值最高者排在最前面。
    缺省的情况下维护的是一个大堆,即权值以从高到低排列。

    其中Type代表数据类型,Container代表容器类型,缺省状态为vector; Functional是比较方式,默认采用的是大顶堆(less<>)。

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. class Solution {
    8. public:
    9. class MyCompare {
    10. public:
    11. bool operator()(const pair<int,int>& lhs, const pair<int, int>& rhs) {
    12. return lhs.second > rhs.second;
    13. }
    14. };
    15. vector<int> TopKFrequent(vector<int>& input, int k) {
    16. unordered_map<int, int> map;
    17. for (int i = 0; i < input.size(); i++) {
    18. map[input[i]]++;
    19. }
    20. priority_queueint,int>,vectorint,int>>, MyCompare> pri_que;
    21. for (auto iter = map.begin(); iter != map.end(); iter++) {
    22. pri_que.push(*iter);
    23. if (pri_que.size() > k) {
    24. pri_que.pop();
    25. }
    26. }
    27. vector<int>result(k);
    28. for (int i = k - 1; i >= 0; i--) {
    29. result[i] = pri_que.top().first;
    30. pri_que.pop();
    31. }
    32. return result;
    33. }
    34. };
    35. void main() {
    36. vector<int> input = { 2,2,2,2,2,3,3,3,1 };
    37. int k = 2;
    38. Solution slo;
    39. slo.TopKFrequent(input, k);
    40. cout << "hello world" << endl;
    41. }

    5、接雨水 leetcode42

    给出一排宽度为1,高度为n的柱子,求可以接到雨水的面积。

    输入:height=[1,0,2,1,3,1,0,1,2,0,1]。输出为7.

    (1)、双指针解法

    从头遍历所有的列,注意第一个柱子和最后一个柱子不接雨水,整体代码如下。

    1. #include
    2. #include
    3. using namespace std;
    4. //双指针算法
    5. class Solution {
    6. public:
    7. int Trap(vector<int>& height) {
    8. int sum = 0;
    9. for (int i = 0; i < height.size(); i++) {
    10. if (i == 0 || i == height.size() - 1) {
    11. continue;
    12. }
    13. int rheight = height[i];
    14. int lheight = height[i];
    15. // 找到右边那个最大的柱子
    16. for (int r = i + 1; r < height.size(); r++) {
    17. if (height[r] > rheight) {
    18. rheight = height[r];
    19. }
    20. }
    21. //找到左边最大的柱子
    22. for (int l = i - 1; l >= 0; l--) {
    23. if (height[l] > lheight) {
    24. lheight = height[l];
    25. }
    26. }
    27. int h = min(rheight, lheight) - height[i];
    28. if (h > 0) {
    29. sum = sum + h;
    30. }
    31. }
    32. return sum;
    33. }
    34. };
    35. void main() {
    36. vector<int> height = { 1,0,2,1,3,1,0,1,2,0,1 };
    37. Solution slo;
    38. slo.Trap(height);
    39. cout << "hello world" << endl;
    40. }

  • 相关阅读:
    Android RecyclerView使用ListAdapter高效刷新数据
    【C++】运算符重载
    1 分钟 Serverless 搭建你的首个个人网站(完成就送猫超卡)
    什么是网络编程?
    Django后端开发——中间件
    EMI改善
    使用Testconainers来进行JAVA测试
    可视化学习:如何生成简单动画让图形动起来
    ChatGPT充值,银行卡被拒绝
    【考试】常见考点知悉
  • 原文地址:https://blog.csdn.net/qq_32565805/article/details/133247062