

在链表上实现 Partition 以及荷兰国旗问题 - Grey Zeng
source link: https://www.cnblogs.com/greyzeng/p/16923068.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在链表上实现 Partition 以及荷兰国旗问题
作者:Grey
原文地址:
CSDN:在链表上实现 Partition 以及荷兰国旗问题
题目描述#
给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。
你应当 保留 两个分区中每个节点的初始相对位置。
题目链接见:LeetCode 86. Partition List
主要思路#
本题可以借鉴数组的 Partition 操作,参考:荷兰国旗问题与快速排序算法
Partition 操作就是荷兰国旗的一种特殊情况而已。
我们可以把本题的难度稍微升级一下:如何在链表上实现荷兰国旗问题?
第一种解法就是将链表先转换成数组,然后在数组上实现荷兰国旗问题,最后将数组还原为链表并返回,该方法的时间复杂度是O(N)
,空间复杂度是O(N)
,不是最优解。
第二种解法是用有限几个变量来实现,在同样O(N)
的时间复杂度的情况下,空间复杂度可以做到O(1)
,设置如下几个变量
ListNode sH = null; // 小于区域的头结点
ListNode sT = null; // 小于区域的尾结点
ListNode eH = null; // 等于区域的头结点
ListNode eT = null; // 等于区域的尾结点
ListNode mH = null; // 大于区域的头结点
ListNode mT = null; // 大于区域的尾结点
ListNode next; // 记录遍历到的结点的下一个结点
接下来开始遍历链表,进行主流程处理,伪代码如下
while (head != null) {
next = head.next;
// 如果head.val < pivot,则通过sH,sT构造小于区域的链表
// 如果head.val == pivot,则通过eH,eT构造小于区域的链表
// 如果head.val > pivot,则通过mH,mT构造小于区域的链表
head = next;
}
// 把三个区域的链表串联起来即可。
构造每个区域的链表的时候,还要考虑链表是第一次被构造还是已经构造了,以小于区域的链表为例,如果是第一次构造,则sH == null
,此时需要把sH
和sT
同时初始化:
if (sH == null) {
sH = head;
sT = head;
}
如果不是第一次构造,则
sT.next = head;
sT = head;
开始区域的尾指针直接指向当前结点,然后把尾指针设置未当前结点即可。
其他两个区域的链表处理方式同理。
最后需要把三个区域的链表连接起来:
// 小于区域的尾巴,连等于区域的头,等于区域的尾巴连大于区域的头
if (sT != null) { // 如果有小于区域
sT.next = eH;
eT = eT == null ? sT : eT; // 下一步,谁去连大于区域的头,谁就变成eT
}
// all reconnect
if (eT != null) { // 如果小于区域和等于区域,不是都没有
eT.next = mH;
}
// 如果小于区域有,小于区域的头就是最终链表的头
// 如果小于区域没有,等于区域的头有,则等于区域的头就是最终链表的头
// 如果小于和等于区域都没有,则大于区域的头就是最终链表的头
return sH != null ? sH : (eH != null ? eH : mH);
完整代码见
public class Code_PartitionList {
public static class ListNode {
public int val;
public ListNode next;
public ListNode(int data) {
this.val = data;
}
}
public static ListNode listPartition2(ListNode head, int pivot) {
ListNode sH = null; // small head
ListNode sT = null; // small tail
ListNode eH = null; // equal head
ListNode eT = null; // equal tail
ListNode mH = null; // big head
ListNode mT = null; // big tail
ListNode next; // save next node
// every node distributed to three lists
while (head != null) {
next = head.next;
head.next = null;
if (head.val < pivot) {
if (sH == null) {
sH = head;
sT = head;
} else {
sT.next = head;
sT = head;
}
} else if (head.val == pivot) {
if (eH == null) {
eH = head;
eT = head;
} else {
eT.next = head;
eT = head;
}
} else {
if (mH == null) {
mH = head;
mT = head;
} else {
mT.next = head;
mT = head;
}
}
head = next;
}
// 小于区域的尾巴,连等于区域的头,等于区域的尾巴连大于区域的头
if (sT != null) { // 如果有小于区域
sT.next = eH;
eT = eT == null ? sT : eT; // 下一步,谁去连大于区域的头,谁就变成eT
}
// all reconnect
if (eT != null) { // 如果小于区域和等于区域,不是都没有
eT.next = mH;
}
// 如果小于区域有,小于区域的头就是最终链表的头
// 如果小于区域没有,等于区域的头有,则等于区域的头就是最终链表的头
// 如果小于和等于区域都没有,则大于区域的头就是最终链表的头
return sH != null ? sH : (eH != null ? eH : mH);
}
}
解决了链表的荷兰国旗问题,那么原题中的链表 Partition 问题,就迎刃而解了。
由于是 Partition,所以不存在等于区域,只需要考虑小于区域和大于区域,只需要设置如下几个变量即可。
ListNode sH = null; // 小于区域的头
ListNode sT = null; // 小于区域的尾
ListNode mH = null; // 大于区域的头
ListNode mT = null; // 大于区域的尾
ListNode cur = head; // 当前遍历到的结点
接下来开始遍历链表,进行主流程处理,伪代码如下
while (cur != null) {
// 如果head.val < pivot,则通过sH,sT构造小于区域的链表
// 如果head.val > pivot,则通过mH,mT构造小于区域的链表
cur = cur.next;
}
// 把两个区域的链表串联起来即可。
构造每个区域的链表的时候和上述荷兰国旗问题一样。
最后需要把两个区域的链表连接起来:
if (mT != null) {
// 大于区域的尾置空
mT.next = null;
}
if (sT != null) {
// 小于区域的尾置空
sT.next = null;
}
// 经过上述操作,两个链表断开连接
if (sH == null) {
// 小于区域的头为空,说明只有大于区域
return mH;
}
// 小于区域的头不为空,小于区域的尾一定也不为空,直接把小于区域的尾连上大于区域的头即可。
sT.next = mH;
return sH;
完整代码见
class Solution {
public static ListNode partition(ListNode head, int x) {
ListNode sH = null;
ListNode sT = null;
ListNode mH = null;
ListNode mT = null;
ListNode cur = head;
while (cur != null) {
if (cur.val < x) {
if (sH == null) {
sH = cur;
} else {
sT.next = cur;
}
sT = cur;
} else {
// cur.val >= x
// 都放到大于等于区域
if (mH == null) {
mH = cur;
} else {
mT.next = cur;
}
mT = cur;
}
cur = cur.next;
}
if (mT != null) {
mT.next = null;
}
if (sT != null) {
sT.next = null;
}
if (sH == null) {
return mH;
}
sT.next = mH;
return sH;
}
}
更多#
Recommend
-
43
请给我一个iPhone11@微信官方
-
18
-
11
在 React 里实现国旗下拉菜单漂洋过海来看你IT俱乐部-码出人生在 React 里实现国旗下拉菜单Dec 16, 2020re...
-
7
用 Python 画了几面国旗 发表于...
-
9
单个表上亿行数据的主键、索引设计,及分页查询 - ChenJacklondon的个人空间 - OSCHINA - 中文开源技术交流社区 一,概述 一般而言,我们对关系型数据库系统,进行表结构设计时,会按数据的种类,进行分类,一般有如下种类:
-
9
到国庆了,大家都急着给祖国母亲庆生。每年每到此时,微信朋友圈就会流行起给头像装饰上国旗,而今年又流行这款:emm,很不错。那么,将一张国旗图片与我们的头像,快速得到想要的头像,使用 CSS 如何简单实现呢?有人认为是改变其...
-
10
毕马威加拿大公司在其资产负债表上加入加密资产 作者:Brandy Betz | 编译者:Maya | 来源:CoinDesk时间:2022-2-8 14:15...
-
4
荷兰国旗问题与快速排序算法 作者:Grey 原文地址: 博客...
-
3
在一个项目中,客户要求对报表中的签名进行仿手写的签名处理,因此我们原先只是显示相关人员的姓名的地方,需要采用手写方式签名,我们的报表是利用FastReport处理的,在利用楷体处理的时候,开发展示倒是正常效果,不过实际上在服务器运行的时候,出来的确实正规的...
-
8
V2EX › WATCH 手表上指南针突然有了经纬度 ...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK