将单向链表按某值划分成左边小、中间相等、右边大的形式

本文涉及的产品
文本翻译,文本翻译 100万字符
图片翻译,图片翻译 100张
语种识别,语种识别 100万字符
简介: 将单向链表按某值划分成左边小、中间相等、右边大的形式

题目: 给定一个单链表的头节点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);
}



相关文章
|
6月前
【数据结构】单链表之--无头单向非循环链表
【数据结构】单链表之--无头单向非循环链表
|
1月前
|
存储
【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)(一)
【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)
|
1月前
|
算法 Java
数据结构与算法学习六:单向环形链表应用实例的约瑟夫环问题
这篇文章通过单向环形链表的应用实例,详细讲解了约瑟夫环问题的解决方案,并提供了Java代码实现。
19 0
|
1月前
|
存储 缓存
【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)(二)
【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)
|
6月前
|
存储
数据结构第二课 -----线性表之单向链表
数据结构第二课 -----线性表之单向链表
|
3月前
|
存储 JavaScript 前端开发
JavaScript实现单向链表
JavaScript实现单向链表
21 0
|
5月前
|
存储 算法
【单向链表】数据结构——单向链表的介绍与代码实现&笔记
【单向链表】数据结构——单向链表的介绍与代码实现&笔记
|
5月前
|
算法 C语言
数据结构——单向链表(C语言版)
数据结构——单向链表(C语言版)
45 2
|
5月前
|
Java
单向环形链表-约瑟夫问题(java)
单向环形链表-约瑟夫问题(java)