当前位置:   article > 正文

【栈和队列】算法题 ---- 力扣

【栈和队列】算法题 ---- 力扣

        通过前面栈和队列的学习,现在来看这些算法题目

一、有效的括号

        本题让判断括号是否有效

第一眼看可能没一点思路,但仔细分析一下;

        我们学习过栈数据结构,知道栈先进后出的原则,那我们就可以使用啊;把题目的左括号存储起来,让右括号跟左括号一一比较。

思路:

        遍历字符串,遇到左括号就括号入栈,遇到右括号就与栈顶数据进行对比,如果配对就继续;如果不配对,就返回false

画图分析:

  现在有这样的括号字符串

        遍历字符串,第一个是  {  左括号,就入栈

        ps接着遍历, [  依然是左括号,入栈

        ps接着遍历,  (  还是左括号,入栈

        ps接着遍历,  )  是右括号,与栈顶数据进行比较,括号匹配,出栈

        ps接着遍历,  ]  是右括号,与栈顶数据比较,括号匹配,出栈

        ps接着遍历,  }  是右括号,与栈顶数据进行比较,括号匹配,出栈

        ps遍历完字符串,再判断栈是否为空?如果为空,就代表所以括号都匹配了;如果栈不为空,括号就不匹配。

        此外,再遍历过程中,有依次括号不匹配就要直接返回false

力扣题代码如下:

  1. typedef char SType;
  2. typedef struct Stack {
  3. SType* arr;
  4. int size; // 栈顶
  5. int num; // 空间大小
  6. } Stack;
  7. // 初始化
  8. void STInit(Stack* ps) {
  9. assert(ps);
  10. ps->arr = NULL;
  11. ps->size = ps->num = 0;
  12. }
  13. // 判断栈是否为空
  14. bool STEmpty(Stack* ps) {
  15. assert(ps);
  16. return ps->size == 0;
  17. }
  18. // 入栈
  19. void STPush(Stack* ps, SType x) {
  20. assert(ps);
  21. // 判断空间大小是否足够
  22. if (ps->num <= ps->size) {
  23. int newnum = (ps->num == 0) ? 4 : 2 * ps->num;
  24. SType* tmp = (SType*)realloc(ps->arr, newnum * sizeof(Stack));
  25. if (tmp == NULL) {
  26. perror("realloc filed");
  27. exit(1);
  28. }
  29. ps->arr = tmp;
  30. ps->num = newnum;
  31. }
  32. ps->arr[ps->size++] = x;
  33. }
  34. // 出栈
  35. void STPop(Stack* ps) {
  36. assert(ps); // 不能传NULL
  37. assert(!STEmpty(ps)); // 栈不能为空
  38. ps->size--;
  39. }
  40. // 取栈顶数据
  41. SType STtop(Stack* ps) {
  42. assert(ps); // 不能传NULL
  43. assert(!STEmpty(ps)); // 栈不能为空
  44. return ps->arr[ps->size - 1];
  45. }
  46. // 获取栈中数据个数
  47. int STSize(Stack* ps) {
  48. assert(ps);
  49. return ps->size;
  50. }
  51. // 栈的销毁
  52. void STDesTroy(Stack* ps) {
  53. assert(ps);
  54. if (ps->arr)
  55. free(ps->arr);
  56. ps->arr = NULL;
  57. ps->size = ps->num = 0;
  58. }
  59. bool isValid(char* s) {
  60. Stack arr;
  61. // 初始化
  62. STInit(&arr);
  63. char* ps = s;
  64. while (*ps != '\0') {
  65. if (*ps == '(' || *ps == '[' || *ps == '{') {
  66. // 入栈
  67. STPush(&arr, *ps);
  68. } else {
  69. // 取栈顶数据
  70. if (STEmpty(&arr)) {
  71. return false;
  72. }
  73. char ch = STtop(&arr);
  74. if ((ch == '(' && *ps == ')') || (ch == '[' && *ps == ']') ||
  75. (ch == '{' && *ps == '}')) {
  76. STPop(&arr);
  77. } else {
  78. return false;
  79. }
  80. }
  81. ps++;
  82. }
  83. if (STEmpty(&arr)) // 栈为空
  84. {
  85. return true;
  86. }
  87. return false;
  88. }

二、用队列实现栈

        使用队列来实现栈,我们直到,队列是先进先出,而栈是先进后出。这里我们需要用两个队列来实现栈的相关操作

思路:

        保证两个队列中有一个为空,再两个队列之间来回导入导出数据。

        入栈:往不为空的队列里面插入数据

        出栈:找到不为空的队列,将size-1个数据导入到另一个队列,最后剩余的一个数据,就是要出栈的数据

        取栈顶元素:找到不为空的队列,取队尾元素即可

假设依次插入了1,2,3三个数据,现在要出栈

        将q1中数据size-1(2个)导入到q2中。

        现在q1当中剩余的数据就是要出栈的数据(即栈顶)。这样就满足了栈先进先出的特点。

力扣题代码如下:

  1. typedef int QType;
  2. typedef struct QueueNode // 队列节结构
  3. {
  4. QType data;
  5. struct QueueNode* next;
  6. } QueueNode;
  7. typedef struct Queue // 队列结构
  8. {
  9. int size; // 队列中的数据个数
  10. QueueNode* phead; // 队头
  11. QueueNode* ptial; // 队尾
  12. } Queue;
  13. // 初始化
  14. void QueueInit(Queue* pq) {
  15. assert(pq);
  16. pq->phead = pq->ptial = NULL;
  17. pq->size = 0;
  18. }
  19. // 判断队列是否为空
  20. bool QueueEmpty(Queue* pq) {
  21. assert(pq);
  22. return pq->size == 0;
  23. }
  24. // 入队列--从队尾插入数据
  25. void QueuePush(Queue* pq, QType x) {
  26. assert(pq);
  27. QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
  28. newnode->data = x;
  29. newnode->next = NULL;
  30. if (QueueEmpty(pq)) // 队列为空
  31. {
  32. pq->phead = pq->ptial = newnode;
  33. } else { // 队列不为空
  34. pq->ptial->next = newnode;
  35. pq->ptial = newnode;
  36. }
  37. pq->size++;
  38. }
  39. // 出队列--从对头删除数据
  40. void QueuePop(Queue* pq) {
  41. assert(pq); // 不能传NULL
  42. //assert(!QueueEmpty(pq)); // 队列不能为空
  43. QueueNode* del = pq->phead;
  44. pq->phead = pq->phead->next;
  45. if (pq->size == 1) // 队列只有一个节点
  46. {
  47. pq->ptial = NULL;
  48. }
  49. pq->size--;
  50. free(del);
  51. del = NULL;
  52. }
  53. // 取队头数据
  54. QType QueueFront(Queue* pq) {
  55. assert(pq); // 不能传NULL
  56. //assert(!QueueEmpty(pq)); // 队列不能为空
  57. return pq->phead->data;
  58. }
  59. // 取队尾数据
  60. QType QueueBack(Queue* pq) {
  61. assert(pq); // 不能传NULL
  62. //assert(!QueueEmpty(pq)); // 队列不能为空
  63. return pq->ptial->data;
  64. }
  65. // 获取队列数据个数
  66. int QueueSize(Queue* pq) {
  67. assert(pq); // 不能传NULL
  68. return pq->size;
  69. }
  70. // 销毁队列
  71. void QueueDesTroy(Queue* pq) {
  72. assert(pq); // 不能传NULL
  73. //assert(!QueueEmpty(pq)); // 队列不能为空
  74. QueueNode* pcur = pq->phead;
  75. while (pcur) {
  76. QueueNode* del = pcur;
  77. pcur = pcur->next;
  78. free(del);
  79. del = NULL;
  80. }
  81. pq->phead = pq->ptial = NULL;
  82. pq->size = 0;
  83. }
  84. typedef struct {
  85. Queue q1;
  86. Queue q2;
  87. } MyStack;
  88. MyStack* myStackCreate() {
  89. MyStack* Qst = (MyStack*)malloc(sizeof(MyStack));
  90. QueueInit(&Qst->q1);
  91. QueueInit(&Qst->q2);
  92. return Qst;
  93. }
  94. void myStackPush(MyStack* obj, int x) {
  95. // 往不为空的队列中插入数据
  96. if (QueueEmpty(&obj->q1)) {
  97. QueuePush(&obj->q2, x);
  98. } else {
  99. QueuePush(&obj->q1, x);
  100. }
  101. }
  102. int myStackPop(MyStack* obj) {
  103. // 先找到不为空的队列
  104. Queue* empq = &obj->q1;
  105. Queue* noneq = &obj->q2;
  106. if (!(QueueEmpty(&obj->q1))) // 如果q1不为空
  107. {
  108. empq = &obj->q2;
  109. noneq = &obj->q1;
  110. }
  111. //empq -- 空队列
  112. //noneq -- 非空队列
  113. while(QueueSize(noneq) > 1) {
  114. // 将noneq队列的数据导入到empq中去
  115. QueuePush(empq, QueueFront(noneq));
  116. QueuePop(noneq);
  117. }
  118. int ret = QueueFront(noneq);
  119. QueuePop(noneq);
  120. return ret;
  121. }
  122. int myStackTop(MyStack* obj) {
  123. if(QueueEmpty(&obj->q1))
  124. {
  125. return QueueBack(&obj->q2);
  126. }else{
  127. return QueueBack(&obj->q1);
  128. }
  129. }
  130. bool myStackEmpty(MyStack* obj) {
  131. return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
  132. }
  133. void myStackFree(MyStack* obj) {
  134. free(obj);
  135. obj = NULL;
  136. }

三、用栈实现队列

        上一个题让我们用队列来实现栈,这个用两个栈来实现队列。

定义两个栈

思路:

        往PushST中插入数据,再将数据导入到PopST中,出栈即可;

        入队列:往PushST中插入数据

        出队列:判断栈PopST是否为空?如果PopST栈为空,就将栈PushST中数据导入到栈PopST中去,再让栈PopST出栈操作;如果不为空,直接让栈PopST出栈操作即可。

        取队头数据:和出队列操作一样,只是不需要出栈操作,只取数据

分析:

        假设依次插入了1,2,3三个数据,现在出栈一次,再插入一个数据4,最后取队头数据,依次出栈。

        出栈一次,PopST为空,就将PushST中数据导入到PopST中去。

依次导入

        出栈;

再插入数据4

取队头数据:

最后依次出队列

现在,PopST栈为空,就要先将PushST中数据先导入到PopST中。

再出队列

力扣题代码如下:

  1. typedef int SType;
  2. typedef struct Stack
  3. {
  4. SType* arr;
  5. int size; //栈顶
  6. int num; //空间大小
  7. }Stack;
  8. //初始化
  9. void STInit(Stack* ps)
  10. {
  11. assert(ps);
  12. ps->arr = NULL;
  13. ps->size = ps->num = 0;
  14. }
  15. //判断栈是否为空
  16. bool STEmpty(Stack* ps)
  17. {
  18. assert(ps);
  19. return ps->size == 0;
  20. }
  21. //入栈
  22. void STPush(Stack* ps, SType x)
  23. {
  24. assert(ps);
  25. //判断空间大小是否足够
  26. if (ps->num <= ps->size)
  27. {
  28. int newnum = (ps->num == 0) ? 4 : ps->num * 2;
  29. SType* tmp = (SType*)realloc(ps->arr, newnum * sizeof(Stack));
  30. if (tmp == NULL)
  31. {
  32. perror("realloc filed");
  33. exit(1);
  34. }
  35. ps->arr = tmp;
  36. ps->num = newnum;
  37. }
  38. ps->arr[ps->size++] = x;
  39. }
  40. //出栈
  41. void STPop(Stack* ps)
  42. {
  43. assert(ps); //不能传NULL
  44. assert(!STEmpty(ps)); //栈不能为空
  45. ps->size--;
  46. }
  47. //取栈顶数据
  48. SType STtop(Stack* ps)
  49. {
  50. return ps->arr[ps->size - 1];
  51. }
  52. //获取栈中数据个数
  53. int STSize(Stack* ps)
  54. {
  55. assert(ps);
  56. return ps->size;
  57. }
  58. //栈的销毁
  59. void STDesTroy(Stack* ps)
  60. {
  61. assert(ps);
  62. if (ps->arr)
  63. free(ps->arr);
  64. ps->arr = NULL;
  65. ps->size = ps->num = 0;
  66. }
  67. typedef struct {
  68. Stack s1;
  69. Stack s2;
  70. } MyQueue;
  71. //初始化
  72. MyQueue* myQueueCreate() {
  73. MyQueue* Queue=(MyQueue*)malloc(sizeof(MyQueue));
  74. STInit(&Queue->s1);
  75. STInit(&Queue->s2);
  76. return Queue;
  77. }
  78. //插入数据
  79. void myQueuePush(MyQueue* obj, int x) {
  80. assert(obj);
  81. STPush(&obj->s1, x);
  82. }
  83. int myQueuePop(MyQueue* obj) {
  84. assert(obj);
  85. if(STEmpty(&obj->s2))
  86. {
  87. //把s1中数据导入到s2
  88. while(!STEmpty(&obj->s1))
  89. {
  90. STPush(&obj->s2,STtop(&obj->s1));
  91. STPop(&obj->s1);
  92. }
  93. }
  94. int ret=STtop(&obj->s2);
  95. STPop(&obj->s2);
  96. return ret;
  97. }
  98. int myQueuePeek(MyQueue* obj) {
  99. if(STEmpty(&obj->s2))
  100. {
  101. //把s1中数据导入到s2
  102. while(!STEmpty(&obj->s1))
  103. {
  104. STPush(&obj->s2,STtop(&obj->s1));
  105. STPop(&obj->s1);
  106. }
  107. }
  108. return STtop(&obj->s2);
  109. }
  110. bool myQueueEmpty(MyQueue* obj) {
  111. return (STEmpty(&obj->s1)) && (STEmpty(&obj->s2));
  112. }
  113. void myQueueFree(MyQueue* obj) {
  114. if(obj)
  115. free(obj);
  116. obj=NULL;
  117. }

四、设计循环队列

        设计循环队列,这里使用数组来设计

这里会设计到的一些问题:

        插入数据,如何判断空间是否满了?       

这里多申请一个空间,便于判断空间是否满了

        删除数据,如何去删?

这里,删除front指向的数据,就是队头数据

详细代码如下:

  1. typedef struct {
  2. int* arr;
  3. int front;
  4. int rear;
  5. int num;
  6. } MyCircularQueue;
  7. MyCircularQueue* myCircularQueueCreate(int k) {
  8. MyCircularQueue* pq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
  9. pq->arr = malloc((k + 1) * sizeof(int));
  10. pq->front = pq->rear = 0;
  11. pq->num = k;
  12. return pq;
  13. }
  14. bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
  15. return (obj->rear == obj->front);
  16. }
  17. bool myCircularQueueIsFull(MyCircularQueue* obj) {
  18. return (obj->rear + 1) % (obj->num + 1) == obj->front;
  19. }
  20. bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
  21. if (myCircularQueueIsFull(obj)) // 队列满了
  22. {
  23. return false;
  24. }
  25. // 插入数据
  26. obj->arr[obj->rear++] = value;
  27. obj->rear %= (obj->num + 1);
  28. return true;
  29. }
  30. bool myCircularQueueDeQueue(MyCircularQueue* obj) {
  31. if (myCircularQueueIsEmpty(obj)) {
  32. return false;
  33. }
  34. obj->front++;
  35. obj->front %= (obj->num + 1);
  36. return true;
  37. }
  38. int myCircularQueueFront(MyCircularQueue* obj) {
  39. if (myCircularQueueIsEmpty(obj))
  40. return -1;
  41. return obj->arr[obj->front];
  42. }
  43. int myCircularQueueRear(MyCircularQueue* obj) {
  44. if (myCircularQueueIsEmpty(obj))
  45. return -1;
  46. int ret=obj->rear-1;
  47. if(obj->rear==0)
  48. {
  49. ret=obj->num;
  50. }
  51. return obj->arr[ret];
  52. }
  53. void myCircularQueueFree(MyCircularQueue* obj) {
  54. free(obj->arr);
  55. free(obj);
  56. obj = NULL;
  57. }

感谢各位大佬支持并指出问题,

                        如果本篇内容对你有帮助,可以一键三连支持以下,感谢支持!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/918843
推荐阅读
相关标签
  

闽ICP备14008679号