帮助橘妈学算法:分隔链表

84 阅读2分钟

86. 分隔链表

一、题目描述

给你一个链表的头结点 head和一个特定的值 x,请你对链表进行分隔,使得所有 小于x的节点都出现在 大于等于x的节点之前。

你应当 保留 两个分区中每个节点的初始相对位置。

大白话解释

对链表进行一次遍历操作,小于x的移动到 分隔节点 的左侧,大于等于x节点的移动到 分隔节点的右侧(包含分隔节点),注意:不要改变每个节点的初始相对位置。其中 分隔节点第一个大于等于 x的节点。

示例说明

题目给定 x = 3,则 分隔节点 = 4(链表中第一个大于等于 3 的节点)

二、算法实现

实现思路

  1. 定义一个新的节点 monitor,其中 monitor.next指向给定链表的头结点
  2. 定义 ListNode curr指向给定链表的头结点
  3. 定义 ListNode currLeft指向 monitor节点,表示 curr节点的前驱节点
  4. 定义 ListNode seprateNode = null 用于表示分隔节点
  5. 定义 ListNode seprateNodeLeft = monitor 表示 分隔节点的前驱节点
  6. 判断 curr != null
    • 如果 curr.val < x
      • 如果seprateNode = null,表示 curr节点之前的节点都是 小于x的,只需要移动currcurrLeftseprateNodeLeft指向下一个节点即可
      • 如果 seperateNode != null,表示已经找到了分隔节点,需要将当前节点移动到 分隔节点 的左侧
    • 如果 curr.val >= x
      • 如果 seprateNode = null 则表示当前节点是 分隔节点,此时 seprateLeft 无需移动了,只需要将 currcurrLeft 移动到下一个节点即可
      • 如果 seprateNode != null,则表示curr节点已经位于分隔节点的右半区,无需节点交换,只需要将currcurrLeft 移动到下一个节点即可
  7. 重复步骤6,直到 curr = null结束遍历链表

算法实现

public ListNode partition(ListNode head,int x){
	if(null == head){
        return null;
    }
    //# 定义新节点,指向head
    ListNode monitor = new ListNode(-1,head);

    //# 定义当前节点
    ListNode curr = head;
    //# 定义当前节点前驱节点
    ListNode currLeft = monitor;
    //# 定义分隔节点
    ListNode seprateNode = null;
    //# 定义分隔节点的前驱节点
    ListNode seprateLeft = monitor;

    while(null != curr) {
        //# 分隔节点不为空,且当前节点小于x
        if(curr.val < x && null != seprateNode) {
            currLeft.next = curr.next;
            curr.next = seprateNode;
            seprateLeft.next = curr;

            curr = currLeft.next;
            seprateLeft = seprateLeft.next;
            continue;
        }
        //# 找到分隔节点
        if(null == seprateNode && curr.val >= x){
            seprateNode = curr;
        }
        //# 移动到下一个节点
        curr = curr.next;
        currLeft = currLeft.next;
        //# 如果分隔节点为空,则一直移动分隔节点的前驱节点,直达找到分隔节点后就不再移动
        if(null == seprateNode) {
            seprateLeft = seprateLeft.next;   
        }
    }
    return monitor.next;
}