方法一 选择排序 时间复杂度O(N^2)空间复杂度O(1) 超时。。。
class Solution {
public:
ListNode* sortList(ListNode* head) {
ListNode* tail = NULL;
ListNode* cur = head;
ListNode* smallPre = NULL;
ListNode* small = NULL;
while (cur != NULL) {
small = cur;
smallPre = getSmallestPreNode(cur);
if (smallPre != NULL) {
small = smallPre->next;
smallPre->next = small->next;
}
cur = cur == small ? cur->next : cur;
if (tail != NULL) {
tail->next = small;
}
else {
head = small;
}
tail = small;
}
return head;
}
ListNode* getSmallestPreNode(ListNode* head) {
ListNode* cur = head->next;
ListNode* pre = head;
ListNode* small = head;
ListNode* smallPre = NULL;
while (cur != NULL) {
if (cur->val < small->val) {
small = cur;
smallPre = pre;
}
cur = cur->next;
pre = pre->next;
}
return smallPre;
}
};
虽然没有跑通,但是还有很多值得学习和思考的点
因为需要从链表中找到最小的值,那么就需要将最小节点取出以后,再将原链表连接起来。那么就需要找到最小点的前驱,来负责完成连接操作。那么此时又出现一直可能发生的情况,那就是未排序链表的第一个节点就是最小的,那么他的前驱就是NULL 所以我们在程序中应该把这种情况当做是初始条件,如果在寻找最小节点的过程中找到了最小节点和他的前驱,那么就可以更新最小值和前驱。如果没有找到,则前驱就是NULL,此时最小点就是当前节点cur,那么需要将未排序的链表部分的头节点修改为当前头节点也就是最小节点的后继。
方法二 归并排序 时间复杂度O(NlogN)空间复杂度O(N)
class Solution {
public:
ListNode* sortList(ListNode* head) {
if (head==NULL || head->next==NULL) return head;
ListNode* fast = head;
ListNode* slow = head;
while (fast->next!=NULL&&fast->next->next!=NULL)
{
slow = slow->next;
fast = fast->next->next;
}
fast = slow->next;
slow->next = NULL;
return merge(sortList(head), sortList(fast));
}
ListNode* merge(ListNode* head1,ListNode* head2) {
ListNode dummyhead(0);
ListNode* p = &dummyhead;
while (head1 && head2) {
if (head1->val < head2->val) {
p->next = head1;
p = head1;
head1 = head1->next;
}
else {
p->next = head2;
p = head2;
head2 = head2->next;
}
}
p->next = head1 ? head1 : head2;
return dummyhead.next;
}
};
需要注意点就是使用的是递归的方法不断切分,那么就需要有递归基就是开始的当head或head的后继为空时,就可以返回。切链操作可以使链表不需要记录最后一个节点,将最后的节点置为空。
merge操作主要是使用了dummyhead节点,然后将两部分合并起来。当一个链表为空后,判断某个链表是否为空,将没有遍历完的链表接在后面,最后返回dummyhead的后继即可