🚩传送门:牛客题目

题目

将给定的单链表🚩[NC]2. 重排链表 - 图1
重新排序为: 🚩[NC]2. 重排链表 - 图2
要求使用原地算法,不能只改变节点内部的值,需要对实际的节点进行交换。

要求:空间复杂度 🚩[NC]2. 重排链表 - 图3 并在链表上进行操作而不新建链表,时间复杂度 🚩[NC]2. 重排链表 - 图4
进阶:空间复杂度 🚩[NC]2. 重排链表 - 图5 , 时间复杂度 🚩[NC]2. 重排链表 - 图6

解题思路:模拟

  1. 找到中间结点,利用快慢指针

    快指针速度是慢指针两倍,故快指针跑到链表尾巴,慢指针跑一半

  2. 反转链表 [mid+1,last]

  3. 将两个链表二路归并

image.png

复杂度分析

时间复杂度: 🚩[NC]2. 重排链表 - 图8 ,每个结点都需要遍历

空间复杂度:🚩[NC]2. 重排链表 - 图9,没有使用额外空间

我的代码

  1. public class Solution {
  2. public static ListNode reverseList(ListNode head){
  3. if(head==null||head.next==null)return head;
  4. ListNode pre=head;
  5. ListNode cur=head.next;
  6. head.next=null;
  7. ListNode next=null;
  8. while(cur!=null){
  9. next=cur.next;
  10. cur.next=pre;
  11. pre=cur;
  12. cur=next;
  13. }
  14. return pre;
  15. }
  16. public ListNode getMid(ListNode head){
  17. //快慢指针
  18. //切割[1,2,3,4]=[1->2][4->3] [1,2,3,4,5]=[1->2][5->4->3]
  19. ListNode fast=head;
  20. ListNode slow=head;
  21. while(fast.next!=null&&fast.next.next!=null){
  22. fast=fast.next.next;
  23. slow=slow.next;
  24. }
  25. return slow;
  26. }
  27. public void reorderList(ListNode head) {
  28. //0.除去特殊情况 0、1、2 个结点
  29. if(head==null||head.next==null||head.next.next==null)return;
  30. //1.找到中间结点 mid , mid 将区间切分[left,mid,right]
  31. ListNode mid=getMid(head);
  32. //2.反转区间[mid+1,last]
  33. ListNode head2=reverseList(mid.next);
  34. mid.next=null;
  35. ListNode head1=head;
  36. //3.给个头节点方便操作
  37. ListNode pcur=new ListNode(-1);
  38. //4.归并
  39. while(head1!=null||head2!=null){
  40. if(head1!=null){
  41. pcur.next=head1;
  42. pcur=pcur.next;
  43. head1=head1.next;
  44. }
  45. if(head2!=null){
  46. pcur.next=head2;
  47. pcur=pcur.next;
  48. head2=head2.next;
  49. }
  50. }
  51. return ;
  52. }
  53. }