复杂链表的复制

题目:
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

这个题目分三步走

  1. 把新的节点插入旧链表对应节点的后面一个节点,即123456变成1(1)2(2)3(3)4(4)5(5)6(6)
  2. 遍历一遍新的链表,偶数位的random是前面奇数节点的random节点的next,即(2)节点的random节点是2节点的random节点(设为4)的next节点 (4),需要注意的是如果奇数的random节点是null,那偶数位的也是null
  3. 把链表1(1)2(2)3(3)4(4)5(5)6(6)拆成(1)(2)(3)(4)(5)(6)这样的链表,返回

看上面的步骤其实也不是很难理解,主要是看你想不想得到了。

class RandomListNode {
    int label;
    RandomListNode next = null;
    RandomListNode random = null;

    RandomListNode(int label) {
        this.label = label;
    }
}
public class Main1 {
	 public RandomListNode Clone(RandomListNode pHead)
	    {
		 if(pHead==null) {
			 return null;
		 }
		
		 RandomListNode rln0 = pHead; 
		 RandomListNode rln1 = null;
		 RandomListNode rln2 = null;
		 //第一步
		 while(rln0!=null) {
			rln1 = new RandomListNode(rln0.label);
			rln2 = rln0.next;
			rln0.next=rln1;
			rln1.next = rln2;
			rln0 = rln2;
			
		 }
		 //第二步
		 rln0 = pHead;
		 while(rln0.next.next!=null) {
			 if(rln0.random==null) {		//判断random为null的情况
				 rln0.next.random = null;
			 }else {
				 rln0.next.random = rln0.random.next;
			 }
			
			 rln0 = rln0.next.next;
		 }
		 //第三步
		rln0=pHead;
		rln1=pHead.next;
		while(rln0!=null) {
			rln2=rln0.next;
			rln0.next =rln2.next;
			if(rln2.next==null) {
				break;
			}
			rln2.next=rln2.next.next;
			rln0=rln0.next;
		}
				
			return rln1;
	        
	    }

}

第一二步只要看上面的思想肯定都会写,
我这说说第三步:
首先题目要求返回的链表不能有旧链表的节点的引用,所以这里脑袋里要好好想想
第一你返回的肯定是链表的头部,其实没拆之前链表的头部就可以确定了,就是第二个节点,直接用rln1=pHead.next指向头部节点,返回的也是rln1,那说明rln1只做头部节点的作用,拆表就和它无关了。

不知道大家关于拆链表成一个新链表是用一个节点搞定还是两个节点,我就不清楚了,我这是用两个节点进行拆链表

首先你每次到下一个节点存不存在肯定是确定1,2,3等这样的节点在不在,如果在,就说明(1)、(2)、(3)等这样的节点也在,所以while的判定条件就是这个。
while循环里面的就需要一步一步分析了
在这里插入图片描述
这个是初始图,在while循环里开始搞事情了
因为不能动rln1,所以rln2 是从rln0上得出来的,还有记住rln0,rln1,rln2都是一个链表上的,改一个就是都改了

关注点:注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空
这句话很关键,而且还很坑,

如果没有这句话,那我们在最后拆表的时候完全可以这么写

while(rln0!=null) {
			rln2=rln0.next;
			if(rln2.next==null) {	 
				break;
			}
			rln2.next=rln2.next.next;
			rln0=rln0.next;
		}

上面的逻辑没问题,但是测试的时候返回的是空,就是因为上面注意在这句话的原因。
你可以想一想,虽然我们返回的是rln1 是从pHead.next 开始的,但是rln1 不是一个完整的链表,即使我们用拆分拆掉了,但是pHead的第一个节点还在上面,我们根本没有把pHead的第一个节点拆掉,所以为什么会返回空了,其实这样也是为了让我们不要造成内存泄漏而已,
不能出现旧的节点引用,那怎么办?
就要加上这句话

rln0.next=rln2.next;

这句话是关键,加上这句话就成功,不加就返回空,
这就是拆表的方式不同造成了结果的不同。
填上这句话就成了下面这种方式
在这里插入图片描述
在这里插入图片描述
慢慢的循环就成了下面这个最终的图
在这里插入图片描述
这样rln1就是一个完整的单独的链表了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值