148.Sort List---链表排序(冒泡、归并)
题目大意:对链表进行排序,要求时间复杂度是o(nlgn)。
法一:冒泡,不交换结点,而交换结点中的数值。超时了。代码如下:
1 public ListNode sortList(ListNode head) { 2 if(head == null || head.next == null) { 3 return head; 4 } 5 ListNode cur = null, tail = null; 6 cur = head; 7 while(cur.next != tail) { 8 while(cur.next != tail) { 9 //其实这里交换的是两个相邻结点的值,并没有交换两个结点指针 10 if(cur.val > cur.next.val) { 11 int tmp = cur.val; 12 cur.val = cur.next.val; 13 cur.next.val = tmp; 14 } 15 cur = cur.next; 16 } 17 //每一趟排序都会把一个相对最大的数排到最后一个,所以这里要将tail置为cur,而不是一直是null 18 tail = cur;//下一次遍历的尾结点是当前结点 19 //每一趟都再次从头开始遍历 20 cur = head;//遍历起始结点重置为头结点 21 } 22 return head; 23 }
法二:归并,交换结点,利用尾插,谁小谁放在前面。代码如下(耗时7ms):
1 public ListNode sortList(ListNode head) { 2 if(head == null || head.next == null) { 3 return head; 4 } 5 //划分成两个链表,由快慢指针得到。 6 //最终slow会指向第二个链表的起始位置,fast会指向第二个链表的末尾,pre会指向第一个链表的末尾 7 ListNode pre = null, slow = head, fast = head; 8 while(fast != null && fast.next != null) { 9 pre = slow; 10 slow = slow.next; 11 fast = fast.next.next; 12 } 13 //第一个链表的终结 14 pre.next = null; 15 //分别对两个链表进行排序 16 //head是第一个链表的头,slow是第二个链表的头 17 ListNode l1 = sortList(head); 18 ListNode l2 = sortList(slow); 19 //归并l1和l2 20 return merge(l1, l2); 21 } 22 private static ListNode merge(ListNode l1, ListNode l2) { 23 //l头节点初始化为0,返回的时候返回l.next即可,即不带头结点的指针 24 ListNode l = new ListNode(0), p = l; 25 while(l1 != null && l2 != null) { 26 //尾插 27 if(l1.val < l2.val) { 28 p.next = l1; 29 l1 = l1.next; 30 } 31 else { 32 p.next = l2; 33 l2 = l2.next; 34 } 35 p = p.next; 36 } 37 //如果还有结点,则直接放在其后即可 38 if(l1 != null) { 39 p.next = l1; 40 } 41 if(l2 != null) { 42 p.next = l2; 43 } 44 return l.next; 45 }