版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/macanv/article/details/78981800
链表克隆,今天看面经的时候,发现很多公司都考了这个题目,也有很多童鞋挂在这个题目上,废话不多说,直接说解决办法。
1. 克隆链表
最简单的,从直接克隆简单链表开始吧,链表结构定义如下:
class RandomListNode {
int label;
RandomListNode next, random;
RandomListNode(int x) { this.label = x; }
};
使用递归或遍历链表进行求解
1, 使用遍历的方法
public RandomListNode copyRandomList(RandomListNode head) {
if(head == null){
return head;
}
RandomListNode t = head;
RandomListNode res = new RandomListNode(0);
RandomListNode p = res;;
while(t != null){
RandomListNode t = new RandomListNode(head.label);
p.next = t;
p = p.next;
t = t.next;
}
return res.next;
}
2,使用递归的方法
public RandomListNode copyRandomList(RandomListNode head) {
if(head == null){
return head;
}else{
RandomListNode p = new RandomListNode(head.label);
p.next = copyRandomList(head.next);
return p;
}
}
2. 克隆带有两个next指针的链表
除了指向next的指针,还多了一个random指针,这个random可以指向链表中的任意元素或者为null,链表结构定义如下:
class RandomListNode {
int label;
RandomListNode next, random;
RandomListNode(int x) { this.label = x; }
};
解决方法如下:
public RandomListNode copyRandomList(RandomListNode head) {
if(head == null){
return head;
}
RandomListNode p = head;
while(p != null){
//new 新节点
RandomListNode newNode = new RandomListNode(p.label);
newNode.random = p.random;
//将新节点插到当前节点之后
newNode.next = p.next;
p.next = newNode;
//当前节点后移
p = newNode.next;
}
//调整random节点 指向新的copy节点
p = head.next;
while(p != null){
if(p.random != null){
p.random = p.random.next;
}
if(p.next == null){
break;
}
p = p.next.next;
}
RandomListNode result = new RandomListNode(0);
RandomListNode t = head;
p = result;
//拆分链表,偶数节点都是新链表中的节点,其余的是原始链表中的节点
while(t != null){
p.next = t.next;
p = p.next;
//断开原始链表连接到新节点的next指针
t.next = p.next;
t = p.next;
}
return result.next;
}
这个题目来自leetcode,还有一种解法,挺直观的,但是需要用到Map这种数据结构,不知道在面试的时候,是不是可以用,解法如下:
public RandomListNode copyRandomList(RandomListNode head) {
RandomListNode result = new RandomListNode(0);
Map<RandomListNode, RandomLsitNode> randomLinks = new HashMap<>();
RandomListNode p = result;
RandomListNode t1 = head;
while(t1.next != null){
//new新的节点
RandomListNode newNode = new RandomListNode(t1.label);
// 设置新链表的random 指向原来链表的random
newNode.random = t1.random;
// add node 到新链表上
p.next = newNode;
p = p.next;
//记录原始链表和新链表的对应关系
randomLinks.put(t1, newNode);
t1 = t1.next;
}
//将新链表中的原始random更改指向新链表中的节点(原来的random 是指向的原始链表中的节点的。)
t1 = result.next;
while(t1 != null){
if (t1.random != null){
t1.random = randomLinks.get(t1.random);
}
t1 = t1.next;
}
return result.next;
}
3. 克隆带有三个next指针的链表
哈哈,要是在多一个random2 指针 怎么搞? 数据结构定义如下:
class RandomListNode {
int label;
RandomListNode next, random, random2;
RandomListNode(int x) { this.label = x; }
};
区别在25-27行
好吧,原谅我在扯淡,这个解法和二中的解法一样,没啥区别,代码如下:
public RandomListNode copyRandomList(RandomListNode head) {
if(head == null){
return head;
}
RandomListNode p = head;
while(p != null){
//new 新节点
RandomListNode newNode = new RandomListNode(p.label);
newNode.random = p.random;
//将新节点插到当前节点之后
newNode.next = p.next;
p.next = newNode;
//当前节点后移
p = newNode.next;
}
//调整random节点 指向新的copy节点
p = head.next;
while(p != null){
if(p.random != null){
p.random = p.random.next;
}
if(p.random2 != null){
p.random2 = p.random2.next;
}
if(p.next == null){
break;
}
p = p.next.next;
}
RandomListNode result = new RandomListNode(0);
RandomListNode t = head;
p = result;
//拆分链表,偶数节点都是新链表中的节点,其余的是原始链表中的节点
while(t != null){
p.next = t.next;
p = p.next;
//断开原始链表连接到新节点的next指针
t.next = p.next;
t = p.next;
}
return result.next;
}
当有n个next的时候,我就不继续扯淡了,解法可以类比克隆三个next的时候,多做几次调整random就好了。