Leetcode 148. 排序链表

前引

综合性比较强的一道题,要求时间复杂度必须O(logn)才能通过,最适合链表的排序算法就是归并。

这里采用自顶向下的方法

步骤:

  1. 找到链表中点(双指针)
  2. 对两个子链表排序(递归,直到只有一个结点,记得将子链表最后指向nullptr)
  3. 归并(引入dummy结点)

题目

在这里插入图片描述
Leetcode 148. 排序链表

代码(首刷看题解)

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        return sortList(head, nullptr);
    }
    ListNode* sortList(ListNode* head, ListNode* tail) {
        if(!head)   // 为空
            return head;
        if(head->next == tail) {    // 两个结点
            head->next = nullptr;
            return head;
        }
        auto mid = middleNode(head, tail);
        return merge(sortList(head, mid), sortList(mid, tail));
    }
	
	// 中间结点
    ListNode* middleNode(ListNode* head, ListNode* tail) {
        auto fast = head;
        auto slow = head;
        while (fast != tail && fast->next != tail) {
            slow = slow->next;
            fast = fast->next->next;
        }
        return slow;
    }
    // 归并
    ListNode* merge(ListNode* head1, ListNode* head2) {
        auto dummy = new ListNode(0);
        auto tmp = dummy;
        ListNode* tmp1 = head1, *tmp2 = head2;
        while(tmp1 && tmp2) {
            if(tmp1->val < tmp2->val) {
                tmp->next = tmp1;
                tmp1 = tmp1->next;
            } else {
                tmp->next = tmp2;
                tmp2 = tmp2->next;
            }
            tmp = tmp->next;
        }
        while(tmp1) {  // 其实只需要执行一次,因为左右两边链表数只相差一
            tmp->next = tmp1;
            tmp = tmp->next;
            tmp1 = tmp1->next;
        }
        while(tmp2) {
            tmp->next = tmp2;
            tmp = tmp->next;
            tmp2 = tmp2->next;
        }
        return dummy->next;
    }
};

代码(8.9 二刷部分看解析)

用到的是归并排序

class Solution {
public:
    ListNode* sortInList(ListNode* head) {
        return mergeSort(head, nullptr);
    }
    ListNode* middleNode(ListNode* head, ListNode* tail) {
        auto fast = head, slow = head;
        while(fast != tail && fast->next != tail) {
            slow = slow->next;
            fast = fast->next->next;
        }
        return slow;
    }
    ListNode* mergeSort(ListNode* p1, ListNode* p2) {   // p2代表末尾
        if(p1 ->next == p2) {
            p1->next = nullptr;
            return p1;
        }
        auto middle = middleNode(p1, p2);
        auto q1 = mergeSort(p1, middle);
        auto q2 = mergeSort(middle, p2);
        return merge(q1, q2);

    }
    ListNode* merge(ListNode* p1, ListNode* p2) {
        auto dummy = new ListNode(-1);
        auto p = dummy;
        while(p1 && p2) {
            if(p1->val < p2->val) {
                p->next = p1;
                p1 = p1->next;
            } else {
                p->next = p2;
                p2 = p2->next;
            }
            p = p->next;
        }
        while(p1) {
            p->next = p1;
            p1 = p1->next;
            p = p->next;
        }
        while(p2) {
            p->next = p2;
            p2 = p2->next;
            p = p->next;
        }
        return dummy->next;
    }
};

GO

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func sortList(head *ListNode) *ListNode {
    return mergeSort(head, nil)
}
func middleNode(head, tail *ListNode) *ListNode {
    fast, slow := head, head
    for fast != tail && fast.Next != tail {
        fast = fast.Next.Next
        slow = slow.Next
    }
    return slow
}
func mergeSort(head, tail *ListNode) *ListNode {
    if head == nil {
        return head
    }
    if head.Next == tail {
        head.Next = nil
        return head
    }
    mid := middleNode(head, tail)
    p1 := mergeSort(head, mid)
    p2 := mergeSort(mid, tail)
    return merge(p1, p2)

}
func merge(head, tail *ListNode) *ListNode {
    dummy := &ListNode{}
    p := dummy
    for head != nil && tail != nil {
        if head.Val <= tail.Val {
            p.Next = head
            head = head.Next
        } else {
            p.Next = tail
            tail = tail.Next
        }
        p = p.Next
    }
    for head != nil {
        p.Next = head
        head = head.Next
        p = p.Next
    }
    for tail != nil {
        p.Next = tail
        tail = tail.Next
        p = p.Next
    }
    return dummy.Next
}

代码(9.15 三刷部分看解析)

细节问题:如果head->next = tail,需要将head->next置为nullptr,方便后面在归并的时候有边界条件

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(!head)
            return head;
        return mergeSort(head, nullptr);
    }
    ListNode* midddle(ListNode* head, ListNode* tail) {
        auto fast = head, slow = head;
        while(fast != tail && fast->next != tail) {
            fast = fast->next->next;
            slow = slow->next;
        }
        return slow;
    }
    ListNode* mergeSort(ListNode* head, ListNode* tail) {
        if(!head)
            return head;
        if(head->next == tail) {
            head->next = nullptr;
            return head;
        }
        auto mid = midddle(head, tail);
        auto p1 = mergeSort(head, mid);
        auto p2 = mergeSort(mid, tail);
        auto dummy = new ListNode();
        auto p = dummy;
        while(p1 && p2) {
            if(p1->val < p2->val) {
                p->next = p1;
                p1 = p1->next;
            } else {
                p->next = p2;
                p2 = p2->next;
            }
            p = p->next;
        }
        while(p1) {
            p->next = p1;
            p = p->next;
            p1 = p1->next;
        } 
        while(p2) {
            p->next = p2;
            p = p->next;
            p2 = p2->next;
        }
        return dummy->next;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值