[算法] - 将单向链表按某值划分成左边小、 中间相等、 右边大的形式 ( 额外空间复杂度请达到O(1) )

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


【 题目】 给定一个单链表的头节点head, 节点的值类型是整型, 再给定一个整
数pivot。 实现一个调整链表的函数, 将链表调整为左部分都是值小于pivot的
节点, 中间部分都是值等于pivot的节点, 右部分都是值大于pivot的节点。
【 进阶】 在实现原问题功能的基础上增加如下的要求
【 要求】 调整后所有小于pivot的节点之间的相对顺序和调整前一样
【 要求】 调整后所有等于pivot的节点之间的相对顺序和调整前一样
【 要求】 调整后所有大于pivot的节点之间的相对顺序和调整前一样
【 要求】 时间复杂度请达到O(N), 额外空间复杂度请达到O(1)。

笔试用:变成数组,数组上partition,然后再返回链表

public static Node listPartition1(Node head, int pivot) {
		if (head == null) {
			return head;
		}
        //变成数组
		Node cur = head;
		int i = 0;
		while (cur != null) {
			i++;
			cur = cur.next;
		}
		Node[] nodeArr = new Node[i];
		i = 0;
		cur = head;
		for (i = 0; i != nodeArr.length; i++) {
			nodeArr[i] = cur;
			cur = cur.next;
		}
        //arrPartition数组Partition
		arrPartition(nodeArr, pivot);
        //变成链表
		for (i = 1; i != nodeArr.length; i++) {
			nodeArr[i - 1].next = nodeArr[i];
		}
		nodeArr[i - 1].next = null;
		return nodeArr[0];//返回链表的head
	}

	public static void arrPartition(Node[] nodeArr, int pivot) {
		int small = -1;
		int big = nodeArr.length;
		int index = 0;
		while (index != big) {
			if (nodeArr[index].value < pivot) {//如果小于p,
				swap(nodeArr, ++small, index++);//首先交换small和index的位置,然后各自+1,表示
			} else if (nodeArr[index].value == pivot) {
				index++;
			} else {
				swap(nodeArr, --big, index);
			}
		}
	}

	public static void swap(Node[] nodeArr, int a, int b) {
		Node tmp = nodeArr[a];
		nodeArr[a] = nodeArr[b];
		nodeArr[b] = tmp;
	}

面试:

6个指针 Head tail equal,依次遍历原链表,注意边界连接问题

链表if的时候很多是为了next不出错,

if (sT != null) {//如果有小于区域
            sT.next = eH;不用管eH是什么,就算是null这句话也是对的。

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 bH = null; // big head
		Node bT = null; // big tail
		Node next = null; // save next node 遍历用一个节点~ ~ ~ 
		// every node distributed to three lists
		while (head != null) {
            //链表的遍历 就是这样
			next = head.next;//先记录原先的下一个的环境
			head.next = null;//因为涉及到链表的重连,原先的next结构要在新的里面初始化成null,所以需要先null
            
			if (head.value < pivot) {
				if (sH == null) {
					sH = head;
					sT = head;
				} else {
					sT.next = head;//老的 st的next的指针连向你head
					sT = head;//你变成你的尾部
				}
			} else if (head.value == pivot) {
				if (eH == null) {
					eH = head;
					eT = head;
				} else {
					eT.next = head;
					eT = head;
				}
			} else {
				if (bH == null) {
					bH = head;
					bT = head;
				} else {
					bT.next = head;
					bT = head;
				}
			}
			head = next;//遍历
		}
		// small and equal reconnect
       //边界问题出错,就是next调用的时候出错,所以这里就是先做了if
		if (sT != null) {//如果有小于区域
			sT.next = eH;//如果有等于区域eT=eT,如果没有等于区域但是有小于区域eT=sT
			eT = eT == null ? sT : eT;//下一步,谁去连eh,谁就变成eT
		}//上面的eT很巧妙~ ~ ~如果没有小于区域也没有等于区域,也就是上下if都没有跑,此时的eT就是eT,没变。
   
		// all reconnect 
		if (eT != null) {//就是如果有小于或等于的区域
			eT.next = bH;
		}
    
    //如果sh存在就是sh,如果不存在但是存在eh就选eh,否则就选bh返回
		return sH != null ? sH : eH != null ? eH : bH;
	}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值