8.<tag-链表和哈希表, >lc-138. 复制带随机指针的链表

lc-138. 复制带随机指针的链表

[案例需求]
在这里插入图片描述

[思路分析一, HashMap 存储法]
本题其实解题方法有挺多的, 以后再补吧, 先把这个学费!

  • 前面曾经提到过, 对于链表结点, 因为链式存储的原因, 我们无法通过索引随机访问而只能遍历访问, 相比于数组, 链表的遍历可真是太让人难受了
  • 所以有些题目, 我们经常会使用各种特性的集合来存储链表结点, 在一定程度上提高链表访问的遍历性. 比如前面写过的题解": 7.<tag-链表和反转, 求中间结点, 合并有序链表>lt.143-重排链表, 就利用了list可以随机访问的特性, 通过一次链表遍历, 把结点放到list中, 然后通过list 的索引访问(list.get(index))来进行下一步的前半部分和后半部分的合并工作;
  • 对于本题: 其实重点就在于如何对原有的链表进行深拷贝. 同时也把原有链表每个节点的next域, 和radom域拷贝到新结点中;
  • 我们可以这么做:
    • 把原有链表的每个节点存储到HashMap中, 为什么是Map呢? 目的就是让旧结点和新节点一一对应, 所以键值对为: <旧结点, 新结点>
    • 第一次我们先遍历原来的链表, 把遇到的结点作为map的key, 同时以这个旧结点的val为参数新建一个新节点作为key的value, 即<旧结点, new Node(旧结点.val); 这样的话每个旧结点都有一个新节点与之对应;
    • 第二次再去遍历旧结点, 这一次我们要把新节点的next域和random域组合起来,
      • 新节点.next = map.get(旧结点.next)
      • 新节点.random = map.get(旧结点.random)
      • 注意噢, 新节点 = map.get(旧结点)

[代码实现]

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/

class Solution {
    public Node copyRandomList(Node head) {
        //
        //遍历原有链表, 每遍历一个结点都新建一个相同val 的结点, 然后使用Hashmap存放于<原链表结点, 新链表结点>
        // 再一次遍历链表, 通过hashMap, 建立起新链表的之间的next, random关系
        Map<Node, Node> map = new HashMap<>();

        Node temp = head;
        while(true){
            if(temp == null)break;

            map.put( temp, new Node(temp.val));
            temp = temp.next;
        }


        //再一次遍历
        temp = head;
        while(true){
            if(temp == null)break;

            map.get(temp).next = map.get(temp.next);
            map.get(temp).random = map.get(temp.random);

            temp = temp.next;
        }

        return map.get(head);
    }
}
posted @ 2022-05-26 20:29  青松城  阅读(27)  评论(0)    收藏  举报