链表OJ(四)链表排序合集

目录

合并两个排序的链表

合并k个已排序的链表

单链表的排序

链表的奇偶重排

链表的奇偶重排扩展


合并两个排序的链表

描述

输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。

数据范围: 0≤n≤10000≤n≤1000,−1000≤节点值≤1000−1000≤节点值≤1000
要求:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)

如输入{1,3,5},{2,4,6}时,合并后的链表为{1,2,3,4,5,6},所以对应的输出为{1,2,3,4,5,6},转换过程如下图所示:

或输入{-1,2,4},{1,3,4}时,合并后的链表为{-1,1,2,3,4,4},所以对应的输出为{-1,1,2,3,4,4},转换过程如下图所示:

示例1

class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
		ListNode* newhead = new ListNode(0);
		ListNode* p = newhead;
		ListNode* l1 = pHead1, *l2 = pHead2;
		while(l1 && l2)
		{
			if(l1->val <= l2->val)    // 创建一个头结点,让头结点依次按序接入各个结点
			{
				p->next = l1;
				l1 = l1->next;
			}
			else
			{
				p->next = l2;
				l2 = l2->next;
			}
		 	p = p->next;
		}
		p->next = l1 ? l1 : l2;    // 记得循环跳出后对剩余结点的接入
		return newhead->next;
    }
};

合并k个已排序的链表

描述

合并 k 个升序的链表并将结果作为一个升序的链表返回其头节点。

数据范围:节点总数 0≤n≤50000≤n≤5000,每个节点的val满足 ∣val∣<=1000∣val∣<=1000

要求:时间复杂度 O(nlogn)O(nlogn)

使用优先级队列,存储依次存储各个链表,然后根据链表首部元素的大小进行建堆,

每次从堆中取出堆顶链表,将堆顶链表pop取出,得到头结点数据后,链表后移重新入队

class Com
{
public:
    bool operator()(ListNode* left, ListNode* right)
    {
        return left->val > right->val;
    }
};

class Solution {
public:
    ListNode *mergeKLists(vector<ListNode*> &lists) {
        if(lists.empty())return nullptr;
        priority_queue<ListNode*, vector<ListNode*>, Com> q;    // 创建一个优先级队列,按照大于的比较方式存储
        for(auto &e : lists)
        {
            if(e!=nullptr)      // 对每个不空的结点进行入队列
                q.push(e);
        }
        ListNode* newhead = new ListNode(0);
        newhead->next = nullptr;
        ListNode* pre = newhead;
        while(!q.empty())
        {
            ListNode* cur = q.top();    // cur标记当前堆顶结点
            q.pop();
            pre->next = cur;      // 将它插入返回链表中
            cur = cur->next;    // 当前结点后移一步
            if(cur) 
                q.push(cur);    // 如果不为空就重新入队列
            pre = pre->next;
        }
        return newhead->next;
    }
};

单链表的排序

描述

给定一个节点数为n的无序单链表,对其按升序排序。

数据范围:0<n≤1000000<n≤100000,保证节点权值在[−109,109][−109,109]之内。

要求:空间复杂度 O(n)O(n),时间复杂度 O(nlogn)O(nlogn)

使用优先级队列,存储结点

class Com
{
public:
    bool operator()(const ListNode* left, const ListNode* right)
    {
        return left->val > right->val;
    }
};
class Solution {
public:
    ListNode* sortInList(ListNode* head) {
        // write code here
        priority_queue<ListNode*, vector<ListNode*>, Com> q;
        while(head)
        {
            q.push(head);        // 将每一个结点入队列
            head = head->next;
        }
        ListNode* newhead = new ListNode(0);
        ListNode* p = newhead;
        while(!q.empty())
        {
            ListNode* cur = q.top();    // 将堆顶结点依次取出置入新头结点后面
            q.pop();
            p->next = cur;
            p = p->next;
        }
        p->next = nullptr;
        return newhead->next;
    }
};

下面是使用按值存储并还原,这是因为上面的办法使用时我没有最后将p的next指向nullptr,导致p的屁股后面跟了一长串,这一长串都是一堆数据。

而上面的k个链表合并,他们每一个链表最终都走到了末尾空的位置。

class Com
{
public:
    bool operator()(const long long left, const long long right)
    {
        return left > right;
    }
};
class Solution {
public:
    ListNode* sortInList(ListNode* head) {
        // write code here            // 使用long long类型
        priority_queue<long long, vector<long long>, Com> q;
        while(head)
        {
            q.push(head->val);    // 存储值的优先级队列
            head = head->next;
        }
        ListNode* newhead = new ListNode(0);
        ListNode* p = newhead;
        while(!q.empty())
        {
            ListNode* cur = new ListNode(q.top());    // 用值将链表结点还原
            q.pop();
            p->next = cur;        // 插入newhead后面即可
            p = p->next;
        }
        return newhead->next;
    }
};

链表的奇偶重排

描述

给定一个单链表,请设定一个函数,将链表的奇数位节点和偶数位节点分别放在一起,重排后输出。

注意是节点的编号而非节点的数值。

class Solution {
public:
    ListNode* oddEvenList(ListNode* head) {
        // write code here
        if(head==nullptr)return nullptr;
        ListNode* slow = head, *fast = head->next;
        ListNode* link = fast;
        while(fast && fast->next)    // 注意这里fast 与 fast->next的判空
        {
            slow->next = fast->next;
            slow = slow->next;
            fast->next = slow->next;
            fast = fast->next;
            
            /*    俩种写法都可以
            slow->next = slow->next->next;
            fast->next = fast->next->next;
            slow = slow->next;
            fast = fast->next;
            */
        }
        slow->next = link;
        return head;
    }
};

链表的奇偶重排扩展

class Com
{
public:
    bool operator()(const ListNode* left, const ListNode* right)
    {
        return left->val > right->val;
    }
};
class Solution {
public:
    ListNode* oddEvenList(ListNode* head) {
        // write code here
        priority_queue<ListNode*, vector<ListNode*>, Com> q1;
        priority_queue<ListNode*, vector<ListNode*>, Com> q2;
        for(int i = 0; head; i++)
        {
            ListNode* newNode = new ListNode(head->val);
            if(i%2==0)
                q1.push(newNode);
            else
                q2.push(newNode);
            head = head->next;
        }
        ListNode* newhead1 = new ListNode(0);
        ListNode* p1 = newhead1;
        ListNode* newhead2 = new ListNode(0);
        ListNode* p2 = newhead2;
        while(!q1.empty())
        {
            p1->next = q1.top();
            q1.pop();
            p1 = p1->next;
        }
        while(!q2.empty())
        {
            p2->next = q2.top();
            q2.pop();
            p2 = p2->next;
        }
        p1->next = newhead2->next;
        p2->next = nullptr;
        return newhead1->next;
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值