LeetCode 排序链表(归并排序)

在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
示例 1:

输入: 4->2->1->3
输出: 1->2->3->4

示例 2:

输入: -1->5->3->4->0
输出: -1->0->3->4->5

思路分析:由于题目特意要求 O(n log n) 时间复杂度和常数级空间复杂度 所以不能使用冒泡、计数排序啥的,比较符合要求的就是归并排序。
归并排序:排序一段序列分为排序前部分、后部分,再合并两个已经排序好的部分。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
	ListNode* sortList(ListNode* head) {
		if (head == NULL || head->next == NULL) {
			return head;
		}
		ListNode *end = head;//定位到链表的尾部
		while (end != NULL && end->next != NULL) {
			end = end->next;
		}
		return mergeSort(head, end);
	}
	//归并排序
	ListNode* mergeSort(ListNode* head, ListNode *end) {
		if (head == end) {//这段链表只有一个节点
			return head;
		}
		if (head->next == end) {//只有两个节点
			if (head->val > end->val) {
				int tempVaule = head->val;
				head->val = end->val;
				end->val = tempVaule;
			}
			return head;
		}
        //快慢指针,定位链表中间
		ListNode *slowPtr = head, *fastPtr = head;
		while (fastPtr != end) {
			slowPtr = slowPtr->next;//慢指针走一步
			fastPtr = fastPtr->next;//快指针走两步
			if (fastPtr != end) {
				fastPtr = fastPtr->next;//快指针走两步
			}
		}
        
		//第一步  递归,排序右半
		ListNode * rightList = mergeSort(slowPtr->next, end);
		slowPtr->next = NULL;//将左右两部分切开
		//第二步 递归,排序左半
		ListNode * leftList = mergeSort(head, slowPtr);
        
		//第三步 合并
		ListNode *pHead = NULL, *pEnd = NULL;//合并链表的头、尾
		if (rightList == NULL) {
			return leftList;
		}
		//初始化头结点、尾节点
		if (rightList->val > leftList->val) {
			pEnd = pHead = leftList;
			leftList = leftList->next;
		}
		else {
			pEnd = pHead = rightList;
			rightList = rightList->next;
		}
		//合并,每次将较小值放入新链表
		while (rightList && leftList) {
			if (rightList->val > leftList->val) {
				pEnd->next = leftList;
				pEnd = pEnd->next;
				leftList = leftList->next;
			}
			else {
				pEnd->next = rightList;
				pEnd = pEnd->next;
				rightList = rightList->next;
			}
		}
		//可能某个链表有剩余
		if (rightList == NULL) {
			pEnd->next = leftList;
		}
		else {
			pEnd->next = rightList;
		}
		return pHead;
	}
};

在这里插入图片描述
下面对代码做出优化,去掉链表end的确定。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
	ListNode* sortList(ListNode* head) {
		if (head == NULL || head->next == NULL) {
			return head;
		}
		return mergeSort(head);//去掉链表尾端的寻找
	}
	ListNode* mergeSort(ListNode* head) {
		if (head == NULL || head ->next == NULL) {//这段链表只有一个节点
			return head;
		}
        //快慢指针,定位链表中间
		ListNode *slowPtr = head, *fastPtr = head->next;
		while (fastPtr != NULL && fastPtr->next != NULL) {
			slowPtr = slowPtr->next;//慢指针走一步
			fastPtr = fastPtr->next;//快指针走两步
			if (fastPtr != NULL && fastPtr->next != NULL) {
				fastPtr = fastPtr->next;//快指针走两步
			}
		}
        
		//第一步  递归,排序右半
		ListNode * rightList = mergeSort(slowPtr->next);
		slowPtr->next = NULL;//将左右两部分切开
		//第二步 递归,排序左半
		ListNode * leftList = mergeSort(head);
        
		//第三步 合并
		ListNode *pHead = NULL, *pEnd = NULL;//合并链表的头、尾
		if (rightList == NULL) {
			return leftList;
		}
		//初始化头结点、尾节点
		if (rightList->val > leftList->val) {
			pEnd = pHead = leftList;
			leftList = leftList->next;
		}
		else {
			pEnd = pHead = rightList;
			rightList = rightList->next;
		}
		//合并,每次将较小值放入新链表
		while (rightList && leftList) {
			if (rightList->val > leftList->val) {
				pEnd->next = leftList;
				pEnd = pEnd->next;
				leftList = leftList->next;
			}
			else {
				pEnd->next = rightList;
				pEnd = pEnd->next;
				rightList = rightList->next;
			}
		}
		//可能某个链表有剩余
		if (rightList == NULL) {
			pEnd->next = leftList;
		}
		else {
			pEnd->next = rightList;
		}
		return pHead;
	}
};

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41855420/article/details/87901524
今日推荐