复杂链表的复制java - 左神算法基础课04 - Kaiqisan

大家好,都吃晚饭了吗?我是Kaiqisan,是一个已经走出社恐的一般生徒,今天讲讲复杂链表的复制

一个链表在原来的基础上新增一个指针,随机指向任意一个节点(可能是null)
然后要求你复制链表

随机链表的生成

// 复杂链表
public class RandList extends LinkList {
    RandList rand = null; // 随机元素指针
    RandList next = null; // 下一个元素指针

    public RandList(int val) {
        super(val);
    }

	// 自己封装的方法,方便遍历链表
    public void readList() {
        RandList temp = this;
        while (temp != null) {
            System.out.print(temp.val);
            System.out.print(temp.next == null ? "" : "->");
            temp = temp.next;
        }

    }
}
		int[] arr = {3, 2, 4, 5, 6, 7, 2};
        RandList list = new RandList(arr[0]);
        RandList head = list;

        for (int i = 1; i < arr.length; i++) {
            list.next = new RandList(arr[i]);
            list = list.next;
        }

        RandList _head = head;
        RandList temp;
        for (int i = 0; i < arr.length; i++) {
            temp = head;
            int rand = (int) (Math.random() * arr.length);
            while (rand > 0) {
                rand--;
                temp = temp.next;
            }

            if (temp != _head) {
                _head.rand = temp;
            }
            _head = _head.next;
        }
        

思路

如果这是普通的链表,直接new一个新链表然后遍历,逐个链接,但如果是上述的复杂链表,还有额外的随机节点,所以如果还是使用前面的遍历复制的方法的话,在出现随机节点指向后面的节点的时候,就无法实现这个随机节点的复制。

所以要另寻出路

  • 方法1:使用map结构

使用HashMap,第一次遍历把当前的节点存入键(key),然后在当前的值(value)中存入和键中的元素值一样的节点(此时值中的节点没有next 和 rand指针)
然后第二次遍历给值(value)中的链表给定指针

static RandList doCopy(RandList preList) {
    HashMap<RandList, RandList> map = new HashMap<>();
    RandList _head = preList;
    while (_head != null) {
        map.put(_head, new RandList(_head.val));
        _head = _head.next;
    }
    _head = preList;

    while (_head != null) {
        map.get(_head).next = map.get(_head.next);
        map.get(_head).rand = map.get(_head.rand);
        _head = _head.next;
    }
    return map.get(preList);
}
  • 方法2:有丝分裂法(自己命名的)

先如图所示先复制链表的元素(为了方便,先不画rand指针了)

在这里插入图片描述
然后这个复制的节点的rand指针就是它前面的原配节点的rand指针的下一个节点(如图)

在这里插入图片描述
Node(1).rand = Node(3)
Node(1`).rand = Node(1).rand.next = Node(3).next

然后根据这个原理编排好所有的“被复制”节点的rand指针的信息,最后把这个新的链表重新从整个长链表中抽离出来

static RandList doCopy2(RandList preList) {
    RandList _head = preList;
    RandList temp;
    RandList temp2;
    // 元素复制
    while (_head != null) {
        temp = _head;
        _head = _head.next;
        temp2 = new RandList(temp.val);
        temp.next = temp2;
        temp2.next = _head;
    }

	// 重新赋值,开始赋值rand节点和抽离
    _head = preList;
    RandList res = preList.next;
    while (_head != null) {
        temp = _head;
        // 分割两个链表
        temp2 = _head.next;
        _head = _head.next.next;
        temp.next = temp2.next;
        temp2.rand = temp.rand == null ? null : temp.rand.next;
    }

    return res;
}

总结

没想到吧,就连最简单的复制操作都可以整出幺蛾子,这更加突出了掌握基础的重要性,没错,这些都是基础,面试中也是经常会出现,如果您被问到这个问题了,如果您没有往这些方向想的话,就已经输了一半了!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kaiqisan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值