LeetCode-----第148题-----排序链表

排序链表

难度:中等

在 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),那么在我们熟悉的排序中只有快排和归并排序,再者要求空间复杂度为常数空间复杂度。那么我们知道在排序数组的时候,快排的空间复杂度为O(longn),归并排序的时间复杂度为O(n)。在这里我们显然考虑使用归并排序,因为一个是快排的话需要前后指针,那么必然需要O(n)的空间,放在vector中进行排序,那不符合要求;二个的话,在不考虑辅助空间的情况下,归并排序的空间复杂度可以为O(1)。具体实现看代码

 

参考代码:

/**
 * 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* pre = head->next;
		ListNode* post = head;
		while (pre && pre->next)
		{
			pre = pre->next->next;
			post = post->next;
		}
        //记录中间节点,和下一个节点
		ListNode* mid = post;
		mid = mid->next;
		post->next = NULL;
        //这里把sortList函数直接传入node_merge函数,这样才不会丢失节点,
        //否则排序的过程中会丢失节点。因为当递归返回到上一层是,比如是3,4,mid指向的是4,
        //那么返回后还是4,这样就会丢失节点,应该指向3节点
		return node_merge(sortList(head), sortList(mid));
	}

	ListNode* node_merge(ListNode* head, ListNode* mid)
	{
        //如果两个节点相等时,说明是一个节点,不需要排序
		if (head == mid)
			return head;

        //建立两个指针,分别从两个链表的头结点开始移动
		ListNode* left = head;
		ListNode* right = mid;

        //这里需要建立一个临时头结点来进行连接,因为你不知道上面两个链表哪个是头结点,
        //所以建立一个临时头结点,后面两个链表再比大小,将小的先连接上去,以此类推
		ListNode* temp_head = new ListNode(INT_MIN);
		ListNode* res = temp_head;

		while (left && right)
		{
			if (left->val < right->val)
			{
				temp_head->next = left;
				temp_head = temp_head->next;
				left = left->next;
			}
			else{
				temp_head->next = right;
				temp_head = temp_head->next;
				right = right->next;
			}
		}

		while (left)
		{
			temp_head->next = left;
			temp_head = temp_head->next;
			left = left->next;
		}

		while (right)
		{
			temp_head->next = right;
			temp_head = temp_head->next;
			right = right->next;
		}

		return res->next;
	}
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值