持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情
题目: 给定一个单链表的头节点head,节点的值类型是整型,再给定一个整数pivot,实现一个调整链表的函数,将链表调整为左部分都是值小于pivot的节点,中间部分都是值等于pivot的节点,右部分都是值大于pivot的节点。
进阶-在实现原问题功能的基础上增加如下的要求:
- 调整后所有小于pivot的节点之间的相对顺序和调整前一样
- 调整后所有等于pivot的节点之间的相对顺序和调整前一样
- 调整后所有大于pivot的节点之间的相对顺序和调整前一样
- 时间复杂度请达到O(N),额外空间复杂度请达到O(1)
法一:借助辅助空间
思路
把链表中的所有节点放入一个额外的数组中,然后统一调整位置的办法。
具体过程如下:
- 1、先遍历一遍链表,为了得到链表的长度,假设长度为N。
- 2、生成长度为N的Node类型的数组nodeArr,然后遍历一次链表,将节点依次放进nodeArr中。
- 3、在nodeArr中把小于pivot的节点放在左边,把相等的放中间,把大于的放在右边。也就是改进了快速排序中partition的调整过程。
- 即如下代码中的arrPartition方法。实现的具体解释请参看"数组类似partition的调整"问题,这里不再详述。
- 4、经过步骤3的调整后,nodeArr是满足题目要求的节点顺序,只要把nodeArr中的节点依次重连起来即可,整个过程结束。
复杂度
时间复杂度为O(N),额外空间复杂度为O(N)
法二: 不借助辅助空间,链表拆分成三个小链表
思路
将原链表拆分成小于,等于,大于区域的小链表,然后去遍历原列表,将大于,小于,等于数分别放到对应链表中。最后将三个链表连接起来就可以了。注意连接三个小链表时注意边界情况的处理。
eg:第一次找到第一个小于参考值的数。将它放进小于区域,这样就保证了在前面小于参考值的数先进入小于区域,然后整体就保证了相对位置不变。
举个例子
假设现在链表为[4,6,3,5,8,5,2],pivot为5。
- 1.小于pivot的区域的小链表的首尾分别用sH、sT来表示,等于pivot的区域的小链表的首尾分别用eH、eT来表示,大于pivot的区域的小链表的首尾分别用mH、mT来表示,遍历链表之前,sH、sT、eH、eT、mH、mT均为null
- 2.遍历到第一个节点时,sH、sT均指向4这个节点
- 3.遍历到第二个节点时,mH、mT均指向6这个节点
- 4.遍历到第三个节点时,sT尾部接上这个节点(也就是sT.next = cur),然后sT指向这个节点(也就是sT = cur)
- 5.遍历到第四个节点时,eH、eT均指向5这个节点
- 6.遍历到第五个节点时,mT尾部接上这个节点(也就是mT.next = cur),然后mT指向这个节点(也就是mT = cur)
- 7.遍历到第六个节点时,eT尾部接上这个节点(也就是eT.next = cur),然后eT指向这个节点(也就是eT = cur)
- 8.遍历到第七个节点时,sT尾部接上这个节点(也就是sT.next = cur),然后sT指向这个节点(也就是sT = cur)
- 9.连接
复杂度
时间复杂度O(N),额外空间复杂度O(1)
public static Node listPartition2(Node head, int pivot){
Node sH = null; // small head
Node sT = null; // small tail
Node eH = null; // equal head
Node eT = null; // equal tail
Node mH = null; // big head
Node mT = null; // big tail
Node next = null; // save next node
// every node distributed to three lists
while(head != null){
next = head.next;
head.next = null;
if(head.value < pivot){
if(sH == null){
sH = head;
sT = head;
}else{
sT.next = head;
sT = head;
}
}else if(head.value == pivot){
if(eH == null){
eH = head;
eT = head;
}else{
eT.next = head;
eT = head;
}
}else(head.value > pivot){
if(mH == null){
mH = head;
mT = head;
}else{
mT.next = head;
mT = head;
}
}
head = next;
}
// small and equal reconnect
if(sT != null){
sT.next = eH;
eT = eT == null ? sT : eT; // 下一步,谁去连大于区域的头,谁就变成eT
}
// 上面的if,不管跑了没有,et
// all reconnect
if(eT != null){ // 如果小于区域和等于区域,不是都没有
eT.next = mH;
}
return sH != null ? sH : (eH != null ? eH : mH);
}