对于链表相关问题,有如下几类:

  • 排序(归并(B2U,U2B))
  • 判环,环起点,环长度(快慢指针)

对于链表O(1)的算法,有如下:

  • Floyd判圈算法(快慢指针)

排序链表(自顶向下、自底向上)

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

进阶: 你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?

算法(归并排序,自顶向下)

  • 分解:待排序的区间为[l,r],令m=l+((r-l)>>1),将区间分为[l,m],[m+1,r],链表可用快慢指针寻终点
  • 解决:使用归并排序递归地排序两个子序列(即当前节点数为1或0时,直接返回)
  • 合并:把两个已经排好序的子序列[l,m][m+1,r]合并起来

实现

  1. /* Merge */
  2. ListNode* merge(ListNode* lhs,ListNode* rhs){
  3. /* merge two sorted list*/
  4. ListNode* dummyHead=new ListNode(0);
  5. auto tmp=dummyHead,tmp1=lhs,tmp2=rhs;
  6. while(tmp1!=nullptr && tmp2!=nullptr){
  7. if(tmp1->val<=tmp2->val){
  8. tmp->next=tmp1;
  9. tmp1=tmp1->next;
  10. }else{
  11. tmp->next=tmp2;
  12. tmp2=tmp2->next;
  13. }
  14. tmp=tmp->next;
  15. }
  16. if(tmp1){
  17. tmp->next=tmp1;
  18. }else{
  19. tmp->next=tmp2;
  20. }
  21. return dummyHead->next;
  22. }
  23. /* divide and solve */
  24. ListNode* sortList(ListNode* head){
  25. if(head==nullptr ||head->next==nullptr)
  26. return head;
  27. auto slow=head,fast=head;
  28. while(fast!=nullptr){
  29. fast=fast->next;
  30. if(fast!=nullptr){
  31. fast=fast->next;
  32. }
  33. if(fast==nullptr) break; /* important !*/
  34. slow=slow->next;
  35. }
  36. auto next_head=slow->next;
  37. slow->next=nullptr;
  38. return merge(sortList(head),sortList(next_head));
  39. }

复杂度分析

  • 时间复杂度:链表(复杂算法) - 图1
  • 空间复杂度:链表(复杂算法) - 图2,即递归栈的长度

    算法(归并排序,自低向顶,主动分解)

  • 分解:将待排序的区间主动分解,按sublen逐渐以2指数递增

  • 解决:使用归并排序递归地排序两个子序列(即当前节点数为1或0时,直接返回)
  • 合并:把两个已经排好序的子序列[l,m][m+1,r]合并起来

    实现

    1. ListNode* sortListBottom2Up(ListNode* head) {
    2. int len=0;
    3. auto tmp=head;
    4. while(tmp!=nullptr){
    5. tmp=tmp->next;
    6. len++;
    7. }
    8. auto assi_node=new ListNode(0,head);
    9. for(int sublen=1;sublen<len;sublen<<=1){
    10. auto head_tmp=assi_node->next,assi_node_tmp=assi_node;
    11. while(head_tmp!=nullptr){
    12. /* get first head of first segment, len = sublen */
    13. auto first=head_tmp,tmp1=first;
    14. for(int i=1;i<sublen && tmp1->next!=nullptr;i++){
    15. tmp1=tmp1->next;
    16. }
    17. /* get second head of second segment, len = sublen*/
    18. auto second=tmp1->next,tmp2=second;
    19. tmp1->next=nullptr; /* need to cut first's relation from all*/
    20. for(int i=1;i<sublen && tmp2!=nullptr && tmp2->next!=nullptr;i++){
    21. tmp2=tmp2->next;
    22. }
    23. /* ready to get next part(next first and next second)*/
    24. if(tmp2!=nullptr){
    25. head_tmp=tmp2->next;
    26. tmp2->next=nullptr;
    27. }else{
    28. /* important! */
    29. head_tmp=nullptr;
    30. }
    31. /* merge first and second segment */
    32. auto newhead=merge(first,second);
    33. /* IMPORTANT! head insert way!*/
    34. assi_node_tmp->next=newhead;
    35. while(assi_node_tmp->next!=nullptr){
    36. assi_node_tmp=assi_node_tmp->next;
    37. }
    38. }
    39. }
    40. return assi_node->next;
    41. }

    复杂度分析

  • 时间复杂度:链表(复杂算法) - 图3

  • 空间复杂度:链表(复杂算法) - 图4

**

判环

Floyd判圈算法(Floyd Cycle Detection Algorithm),又称龟兔赛跑算法(Tortoise and Hare Algorithm),是一个可以在有限状态机、迭代函数或者链表上判断是否存在环,求出该环的起点与长度的算法

我们定义两个指针,一快一慢,慢指针每次走一步,快指针每次走两步;当两个指针从链表的同一节点开始移动时,若链表中无环,则快指针一直在慢指针前;否则,快指针会先于慢指针入环,且会在慢指针跑满环中一圈之前,追上快指针!。

  1. slow=head,fast=head;
  2. while(fast!=nullptr){
  3. if(fast->next==nullptr)
  4. return false;
  5. fast=fast->next->next;
  6. slow=slow->next;
  7. if(fast==slow)
  8. return true;
  9. }
  10. return false;

求环的起点与长度

算法

链表(复杂算法) - 图5
基于Floyd判圈算法, 设置快慢指针fast和slow,假设fast和slow在P点相遇,且fast已跑n圈,可得出如下结论

链表(复杂算法) - 图6
联立后,可得出链表(复杂算法) - 图7
即环外距离等于【相遇点与环起点距离c】和【多圈环长度】之和
故当快慢指针相遇时,设置新ptr指针指向头结点。并令ptr和slow指针同步运动,直到两指针相遇时,便为环的起点。

实现

  1. {
  2. auto slow=head,fast=head;
  3. while(fast!=nullptr){
  4. if(fast->next==nullptr)
  5. return nullptr;
  6. fast=fast->next->next;
  7. slow=slow->next;
  8. if(fast==slow){
  9. auto ptr=head;
  10. while(ptr!=slow){
  11. slow=slow->next;
  12. ptr=ptr->next;
  13. }
  14. return ptr;
  15. }
  16. }
  17. return nullptr;
  18. }

复杂度分析

  • 时间复杂度:链表(复杂算法) - 图8
  • 空间复杂度:链表(复杂算法) - 图9