《程序员代码面试指南》按照左右半区的方式重新组合单链表

题目:
给定一个单链表的头部节点 head,链表长度为 N,如果 N 为偶数,那么前 N/2 个节点算作左半区,后 N/2 的节点算作右半区;如果 N 为奇数,那么前 N/2 个节点算作左半区,后 N/2 + 1 个节点算作右半区。左半区从左到右依次记为 L1->L2->...,右半区从左到右依次记做 R1->R2->..., 请将链表调整成为 L1->R1->L2->R2->...的形式。

 

例如:

1->null,调整为 1->null。

1->2->null,调整为 1->2null。

1->2->3->null,调整为 1->2->3->null。

1->2->3->4->null,调整为 1->3->2->4->null。

1->2->3->4->5->null,调整为 1->3->2->4->5->null。

1->2->3->4->5->6->null,调整为 1->4->2->5->3->6->null。

 

解答:
假如链表的长度为 , 直接给出时间复杂度为 O(N)、额外空间复杂度为 O(1)的方法。

具体过程如下:
1.如果链表为空或长度为 1 不用调整,过程直接结束。

2.链表长度大于 1 时,遍历一遍找到左半区的 最后一个节点,记为 mid。

例如:1->2, mid 为 1 ;1->2->3 mid 为 1;1->2->3->4 mid 为 2;1->2->3->4->5 mid 为 2;1->2->3->4->5->6 mid 为 3;也就是说当链表长度为 2 后,长度每增加 2 ,mid 加一。

3.遍历一遍找到 mid 后,将左半区和右半区分为两个链表(mid.next = nulll),分别记为 left(head) 和 right(原来的 mid.next)。

4.将两个链表按照题目要求合并起来。

具体过程请参看如下代码中的 relocate 方法,其中 mergeLR 方法为步骤 4 的合并过程。

 

    

public class Demo {

	public class Node{
		public int value;
		public Node next;
		
		public Node(int value){
			this.value = value;
		}
	}
	
	public void relocate(Node head){
		if(head == null || head.next == null){
			return;
		}
		Node mid = head;
		Node right = head.next;
		while(right.next != null && right.next.next != null){
			mid = mid.next;
			right = right.next.next;		
		}
		right = mid.next;
		mid.next = null;
	}
	public void mergeLR(Node left, Node right){
		Node next =null;
		while(left.next != null){
			next = left.next;//保留left.next作为第二轮的right
			right.next = left.next;//两条链表建立关联
			left.next = right;//两条链表建立关联
			left = right.next;//第二轮的left头结点
			right = next;//第二轮的right头结点
		}
	}
}

参考资料:《程序员代码面试指南》左程云 著

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值