当前位置:   article > 正文

链表OJ题

链表OJ题

移除链表元素

给定一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val==val 的节点,并返回 新的头节点 。OJ链接

 

方法一:【三指针--无哨兵位】

时间复杂度:O(N)

思想:

三个指针,cur负责对比val,tmp负责存储删除元素的下一个元素地址,prve负责存储删除元素的上一个元素地址。

易错:

  • 记住prve是cur的前一个元素,那么它从NULL开始
  • 循环条件
  • 记得处理头节点和尾节点
  • 造成野指针的错误❌

  1. struct ListNode* removeElements(struct ListNode* head, int val)
  2. {
  3. struct ListNode*cur=head;
  4. struct ListNode*prve=NULL;
  5. while(cur)
  6. {
  7. if(cur->val == val)
  8. {
  9. struct ListNode*tmp=cur->next;
  10. free(cur);
  11. if(prve)
  12. {
  13. prve->next=tmp;
  14. }
  15. else
  16. {
  17. head=tmp;
  18. }
  19. cur=tmp;
  20. }
  21. else
  22. {
  23. prve=cur;
  24. cur=cur->next;
  25. }
  26. }
  27. return head;
  28. }

方法二:【双指针---无哨兵位】

  1. struct ListNode* removeElements(struct ListNode* head, int val)
  2. {
  3. struct ListNode*newhead=NULL;
  4. struct ListNode*tail=NULL;
  5. struct ListNode*cur=head;
  6. while(cur)
  7. {
  8. //不是val的节点取下来尾插。
  9. if(cur->val != val)
  10. {
  11. //尾插
  12. if(tail == NULL)
  13. {
  14. newhead=tail=cur;
  15. }
  16. else
  17. {
  18. tail->next=cur;
  19. tail=tail->next;
  20. }
  21. cur=cur->next;
  22. }
  23. else
  24. {
  25. struct ListNode*tmp=cur->next;
  26. free(cur);
  27. cur=tmp;
  28. }
  29. if(tail)
  30. {
  31. tail->next=NULL;
  32. }
  33. }
  34. return newhead;
  35. }

方法三:【双指针---有哨兵位】

不带哨兵位:plist指向NULL

带哨兵位:plist指向头节点。这个节点不存储有效数据。

 

哨兵位的优势:如果有哨兵位就不需要二级指针了。带哨兵位的更简单。但在实践中和OJ中一般都是不带哨兵位的。 

不需要再判断链表是否为空了

  1. struct ListNode* removeElements(struct ListNode* head, int val)
  2. {
  3. struct ListNode* cur=head;
  4. struct ListNode* newhead=(struct ListNode*)malloc(sizeof(struct ListNode));
  5. struct ListNode* tail=newhead;
  6. //tail不为空。
  7. while(cur)
  8. {
  9. if(cur->val != val)
  10. {
  11. //这里不需要判断链表是否为空了,因为tail不可能为空。
  12. tail->next=cur;
  13. tail=tail->next;
  14. cur=cur->next;
  15. }
  16. else
  17. {
  18. struct ListNode* tmp=cur->next;
  19. free(cur);
  20. cur=tmp;
  21. }
  22. }
  23. //处理尾
  24. if(tail)
  25. {
  26. tail->next=NULL;
  27. }
  28. //这里要记得释放newhead
  29. struct ListNode*tmp=newhead;
  30. newhead=newhead->next;
  31. free(tmp);
  32. tmp=NULL;
  33. return newhead;
  34. }

分割链表

编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前。OJ链接

这道题我们不建议使用不带哨兵位的方法,因为不带哨兵位的话我们就需要在两个链表连接的时候,判断两个链表是否为空的情况,比较麻烦。 

【易错点】

以上测试用例我们可以看到,9是链表中的最后一个数字,9指向NULL,所以代码最后写成

  1. tail->next = list2->next;
  2. free(list1);
  3. free(list2);
  4. return PHead;

这样是没错的,但是如果用例如下, 9的next指向1,形成了一个闭环,那么这样就会出错。所以我们要把tail2->next = NULL;

 

  1. /*
  2. struct ListNode {
  3. int val;
  4. struct ListNode *next;
  5. ListNode(int x) : val(x), next(NULL) {}
  6. };*/
  7. //用不带头节点来写,两个链表都可能为NULL,都要判断非常麻烦
  8. //所以我们用带头节点来写
  9. class Partition {
  10. public:
  11. ListNode* partition(ListNode* pHead, int x) {
  12. ListNode* list1=(ListNode*)malloc(sizeof(ListNode));
  13. ListNode* list2=(ListNode*)malloc(sizeof(ListNode));
  14. ListNode* tail1=list1;
  15. ListNode* tail2=list2;
  16. ListNode* cur=pHead;
  17. while(cur)
  18. {
  19. if(cur->val < x)
  20. {
  21. tail1->next=cur;
  22. tail1=tail1->next;
  23. }
  24. else//cur->val >= x
  25. {
  26. tail2->next=cur;
  27. tail2=tail2->next;
  28. }
  29. cur=cur->next;
  30. }
  31. //尾巴处理
  32. tail1->next=list2->next;
  33. tail2->next=NULL;//易错
  34. PHead = list1->next;
  35. free(list1);
  36. free(list2);
  37. return PHead;
  38. //return list1->next;
  39. }
  40. };

 反转链表

  给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。OJ链接

法一:【三指针】

  1. struct ListNode* reverseList(struct ListNode* head)
  2. {
  3. if(head == NULL)
  4. {
  5. return NULL;
  6. }
  7. struct ListNode*n1=NULL;
  8. struct ListNode*n2=head;
  9. struct ListNode*n3=head->next;
  10. while(n2)//易错
  11. {
  12. n2->next=n1;
  13. n1=n2;
  14. n2=n3;
  15. if(n3)
  16. n3=n3->next;
  17. }
  18. return n1;//易错
  19. }

 要注意结束条件是n3==NULL!!

法二:【头插】

  1. struct ListNode* reverseList(struct ListNode* head) {
  2. struct ListNode* cur = head;
  3. struct ListNode* newhead = NULL;
  4. while (cur)
  5. {
  6. struct ListNode* next = cur->next;
  7. //头插
  8. cur->next = newhead;
  9. newhead = cur;
  10. cur = next;
  11. }
  12. return newhead;
  13. }

链表中倒数第k个结点

输入一个链表,输出该链表中倒数第k个结点 OJ链接

示例1:输入:1,{1,2,3,4,5}

返回值:{5}

示例2:输入:6,{1,2,3,4,5}

返回值:{}


思路:这个题我们可以通过控制fast和slow的间隔,来输出倒数第k个值。如果fast先走k步,然后两个再一起走,那么等到fast==NULL的时候,slow的值就是倒数第k个值。 如果fast先走k-1步,然后两个再一起走,那么等到fast->next==NULL的时候,slow的值就是倒数第k个值。

 k步 

  1. struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
  2. struct ListNode*fast=pListHead;
  3. struct ListNode*slow=pListHead;
  4. while(k--)//走k
  5. {
  6. if(fast == NULL)
  7. {
  8. return NULL;
  9. }
  10. fast=fast->next;
  11. }
  12. while(fast)
  13. {
  14. fast=fast->next;
  15. slow=slow->next;
  16. }
  17. return slow;
  18. }

k-1步

  1. struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
  2. struct ListNode*fast=pListHead;
  3. struct ListNode*slow=pListHead;
  4. while(--k)//走k-1
  5. {
  6. if(fast == NULL)
  7. {
  8. return NULL;
  9. }
  10. fast=fast->next;
  11. }
  12. while(fast->next)
  13. {
  14. fast=fast->next;
  15. slow=slow->next;
  16. }
  17. return slow;
  18. }

 

合并链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。OJ链接

 

  • 取小尾插
  1. struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
  2. struct ListNode* tail=NULL,*head = NULL;
  3. if(list1 == NULL)
  4. return list2;
  5. if(list2 == NULL)
  6. return list1;
  7. while(list1 && list2)
  8. {
  9. if(list1->val < list2->val)
  10. {
  11. if(tail == NULL)
  12. {
  13. head=tail=list1;//易错
  14. }
  15. else
  16. {
  17. tail->next=list1;//已经放进去//易错
  18. tail=tail->next;//tail是尾节点,可以往后移动了
  19. }
  20. list1=list1->next;
  21. }
  22. else
  23. {
  24. if(tail == NULL)
  25. {
  26. head=tail=list2;//易错
  27. }
  28. else
  29. {
  30. tail->next=list2;//已经放进去//易错
  31. tail=tail->next;//tail是尾节点,可以往后移动了
  32. }
  33. list2=list2->next;
  34. }
  35. }
  36. if(list1)
  37. {
  38. tail->next=list1;
  39. }
  40. else
  41. {
  42. tail->next=list2;//已经不用在往后走了
  43. }
  44. return head;
  45. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/644976
推荐阅读
相关标签
  

闽ICP备14008679号