题目:
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
这个题目分三步走
- 把新的节点插入旧链表对应节点的后面一个节点,即123456变成1(1)2(2)3(3)4(4)5(5)6(6)
- 遍历一遍新的链表,偶数位的random是前面奇数节点的random节点的next,即(2)节点的random节点是2节点的random节点(设为4)的next节点 (4),需要注意的是如果奇数的random节点是null,那偶数位的也是null
- 把链表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就是一个完整的单独的链表了