• 数据结构刷题


    空间复杂度:临时开辟的空间、空间是可以重复利用的

    递归为O(n)

    时间复杂度:程序执行次数

    消失的数字

    力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

    思路1:利用连续的特点求等差和然后减去所有元素得到的就是消失的数字

    时间复杂度:O(n)     空间复杂度:O(1)

    思路2:将给定数组的元素和连续的元素进行异或(异或与顺序无关),相同元素异或结果为0。会得到有一个落单的数字与0异或就是这个数字。

    时间复杂度:O(n)     空间复杂度:O(1)

    第一种方法大家自行实现,我们可以实现一下不常见的第二种方法:

    1. int missingNumber(int* nums, int numsSize){
    2. int x = 0;//0与任何数异或为该数
    3. for(int i = 0;i
    4. {
    5. x ^= nums[i];
    6. }
    7. for(int i = 0;i<=numsSize;i++)
    8. {
    9. x ^= i;
    10. }
    11. return x;
    12. }

    轮转数组

    力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

    c语言阶段曾实现了两种方法,一种是依次移动,移动M次。一种是局部逆置和整体逆置。前者时间复杂度为O(N*M),后者为O(N)

    空间换时间:创建一个临时数组,前面放需要旋转的数据,后面放没有旋转的数据即可。 

    不完整代码: 

    1. void rotate(int* nums, int numsSize, int k){
    2. int tmp[numsSize];
    3. k %= numsSize;//循环次数不必多于元素个数
    4. int i = 0;
    5. int j = 0;
    6. for(i=numsSize-k;i
    7. {
    8. tmp[j] = nums[i];
    9. j++;
    10. }
    11. for(i = 0;i
    12. {
    13. tmp[j] = nums[i];
    14. }
    15. for//打印
    16. }

    有效的括号

    力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

    思路:让左括号依次入栈,与右括号匹配。

    匹配前:判断栈是否为空,为空说明无左括号。返回false。

    匹配中:匹配涉及多次如 " () {} (())",记录指针位置与栈顶比较,然后出栈,不匹配返回false。

    匹配结束栈空为匹配成功,否则匹配失败。

    注意返回前都需进行销毁操作。

    1. #include
    2. #include
    3. #include
    4. typedef char STDatatype;
    5. typedef struct Stack
    6. {
    7. STDatatype* a;
    8. int capacity;
    9. int top;
    10. }ST;
    11. void check_capacity(ST* ps)
    12. {
    13. if(ps->capacity == ps->top)
    14. {
    15. int newCapacity = 0 ? 4:ps->capacity*2;
    16. char* tmp;
    17. tmp = (STDatatype*)realloc(ps->a,sizeof(STDatatype) * newCapacity);
    18. if (tmp == NULL)
    19. {
    20. perror("malloc");
    21. exit(-1);
    22. }
    23. ps->a = tmp;
    24. ps->capacity = newCapacity;
    25. }
    26. }
    27. bool StackEmpty(ST* ps)//判空
    28. {
    29. assert(ps);
    30. return ps->top == 0;
    31. }
    32. STDatatype StackTop(ST* ps)
    33. {
    34. assert(ps);
    35. assert(!StackEmpty(ps));
    36. return ps->a[ps->top-1];//top为最后一个元素的下一个
    37. }
    38. void StackDestroy(ST* ps)
    39. {
    40. assert(ps);
    41. free(ps->a);
    42. ps->a = NULL;
    43. ps->top = ps->capacity = 0;
    44. }
    45. void StackInit(ST* ps)
    46. {
    47. /*ps->a = NULL;
    48. ps->top = 0;
    49. ps->capacity = 0;*/
    50. //初始化空间
    51. ps->a = (STDatatype*)malloc(sizeof(STDatatype) * 4);
    52. if (ps->a == NULL)
    53. {
    54. perror("malloc");
    55. exit(-1);
    56. }
    57. ps->top = 0;
    58. ps->capacity = 4;
    59. }
    60. void StackPop(ST* ps)//出栈
    61. {
    62. assert(ps);
    63. //if(ps->top>0)
    64. assert(!StackEmpty(ps));
    65. ps->top--;
    66. }
    67. void StackPush(ST* ps, STDatatype x)
    68. {
    69. assert(ps);
    70. check_capacity(ps);
    71. ps->a[ps->top] = x;
    72. ps->top++;//指向下一个
    73. }
    74. bool isValid(char* s) {
    75. ST ps;
    76. StackInit(&ps);
    77. while(*s)
    78. {
    79. if(*s == '(' || *s == '[' ||*s == '{' )
    80. {
    81. StackPush(&ps,*s);
    82. s++;
    83. }
    84. else
    85. {
    86. if(StackEmpty(&ps))//如果没有左括号,栈顶没有元素
    87. {
    88. StackDestroy(&ps);//注意返回前都要手动释放空间
    89. return false;
    90. }
    91. char top = StackTop(&ps);
    92. if((*s == ')' && top != '(') || (*s == ']' && top != '[') ||
    93. (*s == '}' && top != '{'))//
    94. {
    95. StackDestroy(&ps);
    96. return false;
    97. }
    98. else
    99. {
    100. StackPop(&ps);
    101. s++;
    102. }
    103. }
    104. }
    105. bool ret = StackEmpty(&ps);
    106. StackDestroy(&ps);
    107. return ret;
    108. }

    用队列实现栈

    力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

    先导入我们实现过的队列:

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #include
    6. typedef int QDataType;
    7. typedef struct QueueNode
    8. {
    9. QDataType data;
    10. struct QueueNode* next;
    11. }QNode;
    12. struct Queue
    13. {
    14. QNode* head;
    15. QNode* tail;
    16. int size;
    17. };
    18. void QueueInit(Queue* pq);
    19. void QueueDestroy(Queue* pq);
    20. void QueuePush(Queue* pq, QDataType x);
    21. void QueuePop(Queue* pq);
    22. QDataType QueueFront(Queue* pq);
    23. QDataType QueueBack(Queue* pq);
    24. bool QueueEmpty(Queue* pq);
    25. int QueueSize(Queue* pq);
    26. void QueueDestroy(Queue* pq)
    27. {
    28. assert(pq);
    29. QNode* cur = pq->head;
    30. while (cur)
    31. {
    32. QNode* Next =cur->next;
    33. free(cur);
    34. cur = Next;
    35. }
    36. pq->head = pq->tail = NULL;//避免野指针
    37. pq->size = 0;
    38. }
    39. void QueuePush(Queue* pq, QDataType x)
    40. {
    41. assert(pq);
    42. QNode* newnode = (QNode*)malloc(sizeof(QNode));
    43. if (newnode == NULL)
    44. {
    45. perror("malloc fail");
    46. exit(-1);
    47. }
    48. newnode->data = x;
    49. newnode->next = NULL;
    50. pq->size++;
    51. if (pq->head == NULL)
    52. {
    53. pq->head = pq->tail = newnode;
    54. }
    55. else
    56. {
    57. pq->tail->next = newnode;
    58. pq->tail = newnode;
    59. }
    60. }
    61. void QueuePop(Queue* pq)
    62. {
    63. //出队头删
    64. assert(pq);
    65. assert(pq->head);
    66. QNode* del = pq->head;
    67. pq->head = pq->head->next;
    68. free(del);
    69. if (pq->head == NULL)
    70. pq->tail = NULL;
    71. pq->size--;
    72. }
    73. void QueueInit(Queue* pq)
    74. {
    75. assert(pq);
    76. pq->head = NULL;
    77. pq->tail = NULL;
    78. pq->size = 0;
    79. }
    80. bool QueueEmpty(Queue* pq)
    81. {
    82. assert(pq);
    83. return pq->head == NULL && pq->tail == NULL;
    84. }
    85. int QueueSize(Queue* pq)
    86. {
    87. assert(pq);
    88. return pq->size;
    89. }
    90. QDataType QueueFront(Queue* pq)
    91. {
    92. assert(pq);
    93. assert(!QueueEmpty(pq));
    94. return pq->head->data;
    95. }
    96. QDataType QueueBack(Queue* pq)
    97. {
    98. assert(pq);
    99. assert(!QueueEmpty(pq));
    100. return pq->tail->data;
    101. }

     两个队列

    将两个队列封装在一个结构体中。

    1. typedef struct Queue
    2. {
    3. QNode* head;
    4. QNode* tail;
    5. int size;
    6. }Queue;//简写

    创建并初始化链表(栈)

    注意要想保证我们创建的结构体生命周期能够贯彻整个工程,必须在上申请空间。

    1. MyStack* myStackCreate() {//创建并初始化链表
    2. MyStack* obj = (MyStack*)malloc(sizeof(MyStack));//堆区
    3. QueueInit(&obj->q1);
    4. QueueInit(&obj->q2);
    5. return obj;
    6. }

    模拟入栈

    选择非空队列插入即可。

    1. void myStackPush(MyStack* obj, int x) {
    2. if(!QueueEmpty(&obj->q1))//非空队列插入
    3. {
    4. QueuePush(&obj->q1,x);
    5. }
    6. else
    7. QueuePush(&obj->q2,x);
    8. }

    模拟出栈

    出栈是在队尾进行出(后进先出),我们将非空队列进行出队只剩下最后一个元素即是栈顶的元素,然后将其保存后出栈避免造成内存泄露,然后返回。

    1. nt myStackPop(MyStack* obj) {
    2. //假定一方不为空
    3. Queue* empty = &obj->q1;
    4. Queue* nonempty = &obj->q2;
    5. if(!QueueEmpty(empty))
    6. {
    7. empty = &obj->q2;
    8. nonempty = &obj->q1;
    9. }
    10. while(QueueSize(nonempty) > 1)//O(1)导入空来链表
    11. {
    12. QueuePush(empty,QueueFront(nonempty));//非空取队头插入空
    13. QueuePop(nonempty);
    14. }
    15. //保证原链表返回为空
    16. int top = QueueFront(nonempty);
    17. QueuePop(nonempty);//出栈
    18. return top;
    19. }

    模拟栈顶

    直接返回队尾元素即可。

    1. int myStackTop(MyStack* obj) {
    2. //返回队尾
    3. if(!QueueEmpty(&obj->q1))
    4. {
    5. return QueueBack(&obj->q1);
    6. }
    7. else
    8. return QueueBack(&obj->q2);
    9. }

    模拟栈判空

    1. bool myStackEmpty(MyStack* obj) {
    2. return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
    3. }

    模拟栈销毁

    除了释放队列指针组合的结构体外,还要将每个队列里的元素释放。

    1. void myStackFree(MyStack* obj) {
    2. QueueDestroy(&obj->q1);
    3. QueueDestroy(&obj->q2);
    4. free(obj);
    5. }

    用栈实现队列

    思路:两个栈,一个负责push数据,一个负责pop数据,在pop数据时,判断pop栈中是否有数据,没有则将push栈的数据全部导入,此时数据顺序反过来后再pop栈里出栈就可以实现先进先出这一特性了。

    导入实现好的栈:

    1. #include
    2. #include
    3. #include
    4. #include
    5. typedef int STDatatype;
    6. typedef struct Stack
    7. {
    8. STDatatype* a;
    9. int capacity;
    10. int top;
    11. }ST;
    12. void StackInit(ST* ps);
    13. void StackDestroy(ST* ps);
    14. void StackPush(ST* ps, STDatatype x);
    15. void StackPop(ST* ps);//出栈
    16. STDatatype StackTop(ST* ps);
    17. bool StackEmpty(ST* ps);
    18. int StackSize(ST* ps);
    19. void StackInit(ST* ps)
    20. {
    21. /*ps->a = NULL;
    22. ps->top = 0;
    23. ps->capacity = 0;*/
    24. //初始化空间
    25. ps->a = (STDatatype*)malloc(sizeof(STDatatype) * 4);
    26. if (ps->a == NULL)
    27. {
    28. perror("malloc");
    29. exit(-1);
    30. }
    31. ps->top = 0;
    32. ps->capacity = 4;
    33. }
    34. static void check_capacity(ST* ps)
    35. {
    36. if (ps->top == ps->capacity)
    37. {
    38. int newCapacity = ps->capacity * 2;
    39. STDatatype* tmp = (STDatatype*)realloc(ps->a, newCapacity *sizeof(STDatatype));
    40. if (tmp == NULL)
    41. {
    42. perror("realloc");
    43. exit(-1);
    44. }
    45. else
    46. {
    47. ps->a = tmp;
    48. ps->capacity == newCapacity;
    49. }
    50. }
    51. }
    52. void StackPush(ST* ps, STDatatype x)
    53. {
    54. assert(ps);
    55. check_capacity(ps);
    56. ps->a[ps->top] = x;
    57. ps->top++;//指向下一个
    58. }
    59. void StackPop(ST* ps)//出栈
    60. {
    61. assert(ps);
    62. //if(ps->top>0)
    63. assert(!StackEmpty(ps));
    64. ps->top--;
    65. }
    66. STDatatype StackTop(ST* ps)
    67. {
    68. assert(ps);
    69. assert(!StackEmpty(ps));
    70. return ps->a[ps->top-1];//top为最后一个元素的下一个
    71. }
    72. void StackDestroy(ST* ps)
    73. {
    74. assert(ps);
    75. free(ps->a);
    76. ps->a = NULL;
    77. ps->top = ps->capacity = 0;
    78. }
    79. bool StackEmpty(ST* ps)//判空
    80. {
    81. assert(ps);
    82. return ps->top == 0;
    83. }
    84. int StackSize(ST* ps)
    85. {
    86. assert(ps);
    87. return ps->top;
    88. }

    两个栈

    1. typedef struct {
    2. ST pushst;//入队
    3. ST popst;//出队
    4. } MyQueue;

    Create

    1. MyQueue* myQueueCreate() {
    2. //初始化+开空间
    3. MyQueue* st = (MyQueue*)malloc(sizeof(MyQueue));
    4. StackInit(&st->pushst);
    5. StackInit(&st->popst);
    6. return st;
    7. }

    Push

    1. void myQueuePush(MyQueue* obj, int x) {
    2. assert(obj);
    3. StackPush(&obj->pushst,x);
    4. }

    判空 

    1. bool myQueueEmpty(MyQueue* obj) {
    2. assert(obj);
    3. return StackEmpty(&obj->pushst) && StackEmpty(&obj->popst);
    4. }

    查看队头

    由于popst的栈顶为队头,如果该栈为,需要导入pushst的数据。

    1. int myQueuePeek(MyQueue* obj) {
    2. assert(obj);
    3. assert(!myQueueEmpty(obj)); //双栈判空
    4. if(StackEmpty(&obj->popst))
    5. {
    6. while(!StackEmpty(&obj->pushst))//导数据
    7. {
    8. StackPush(&obj->popst,StackTop(&obj->pushst));
    9. StackPop(&obj->pushst);
    10. }
    11. }
    12. return StackTop(&obj->popst);
    13. }

    Pop

    同样涉及判空和调用队头元素,通过调用peek函数判断并完成对数据的导入并接收其返回值,

    1. int myQueuePop(MyQueue* obj) {
    2. int qhead = myQueuePeek(obj);
    3. StackPop(&obj->popst);//出队
    4. return qhead;
    5. }

    释放

    1. void myQueueFree(MyQueue* obj) {
    2. assert(obj);
    3. StackDestroy(&obj->pushst);
    4. StackDestroy(&obj->popst);
    5. free(obj);
    6. }

  • 相关阅读:
    MySQL--创建,删除,查找,案例
    发展之路是怎么样? 防爆机器人的未来发展之路是怎么样
    数字孪生产业园开发公司,VR钢铁效果怎么样?强荐广州华锐互动
    Shell常用的几个正则表达式:[:alnum:], [:alpha:], [:upper:], [:lower:], [:digit:] 认知
    代码随想录笔记_动态规划_139单词拆分
    字符串首尾空格去除问题
    redis
    JMeter 逻辑控制之IF条件控制器
    CLIP 论文逐段精读【论文精读】
    计算机组成原理 | 输入输出系统
  • 原文地址:https://blog.csdn.net/dwededewde/article/details/134082802