题解 | #复杂链表的复制#

复杂链表的复制

https://www.nowcoder.com/practice/f836b2c43afc4b35ad6adc41ec941dba

难点:random的深拷贝

  • 此题难点在于要深拷贝,新链表中每一个结点都应该指向自己链表中的结点,而不能单纯保存旧表中结点的地址。
  • next指向下一个新结点很容易,但random是随机访问,拷贝时就要找到旧random指向的旧结点,对应的新结点是哪个,然后让新结点的random指向这个新结点。
  • 新结点在创建时可能指向的random结点还没有被创建,因此这也是不能直接赋值random的原因,链表先链接好再去找random,也得找到新旧结点的对应关系才行。

    方法一:哈希表建立新旧结点间的映射

    public RandomListNode Clone(RandomListNode pHead) {
          if(pHead==null)return pHead;
          Map<RandomListNode,RandomListNode> map = new HashMap<>();
          RandomListNode newHead = new RandomListNode(0);
          RandomListNode cur = pHead,newcur = newHead;
          while(cur!=null){
              RandomListNode clone = new RandomListNode(cur.label);
              //clone.next = cur.next;
              //不能同时拷贝next和random,clone的random还是指向旧表了!
              //clone.random = cur.random;
              //映射,可以通过旧表的radom访问到新表的random
              map.put(cur,clone);//哈希表记录对应新旧节点的映射关系
              //利用newcur把新建的clone连起来
              //clone的next已经ok,只需要填充random
              newcur.next = clone;
              newcur = newcur.next;
              //继续遍历旧链表
              cur = cur.next;
          }
          //哈希表键值对的遍历(key:cur;value:clone)
          for(HashMap.Entry<RandomListNode,RandomListNode> entry:map.entrySet()){
              //entry.getValue().random:新结点clone的random
              //entry.getKey().random:与新结点对应的旧结点cur的random
              //map.get():获取旧结点random指向的那个新结点!!!
              entry.getValue().random = map.get(entry.getKey().random);
              //等号右侧就阐释了为什么要用哈希表建立映射才能拷贝random!
          }
          return newHead.next;
      }

    方法二:双指针插入旧结点

  • 难点:循环停止条件的判断,两链表连接之后,每次指针走两步,最后一个元素必为新结点,所以只有old可能为null,这是循环停止条件(或new.next!=null)
    public RandomListNode Clone(RandomListNode pHead) {
          if(pHead==null)return pHead;
          RandomListNode cur = pHead;
          while(cur!=null){
              RandomListNode clone = new RandomListNode(cur.label);
              clone.next = cur.next;
              cur.next = clone;
              cur = clone.next;
          }
          RandomListNode pre = pHead;
          cur = pHead.next;
          while(pre!=null){
              //循环结束时,应该为:pre=null,cur.next=null
              //因为最后一个元素必为cur,所以cur无法为空,pre可以
              if(pre.random==null)
              {
                  cur.random=null;
              }else{
              //若pre的random为空,那么根本访问不到next,会出越界错误
                  cur.random = pre.random.next;
              }
              //pre后面还有clone,所以pre.next必定非空
              pre = pre.next.next;
              if(cur.next!=null)
                  cur = cur.next.next;
          }
          pre = pHead;
          cur = pHead.next;
          RandomListNode res = cur;
          while(pre != null){
              pre.next = pre.next.next;
              pre = pre.next;
              //若cur的next为空,也意味着pre目前为null
              //这是最后一次循环
              if(cur.next!=null)
                  cur.next = cur.next.next;
              cur = cur.next;          
          }
       return res;   
      }
全部评论

相关推荐

2025-12-28 16:32
重庆邮电大学 Java
程序员花海:1.技能放最后,来面试默认你都会,技能没啥用 2.实习写的看起来没啥含金量,多读读部门文档,包装下 接LLM这个没含金量 也不要用重构这种 不会给实习生做的 3.抽奖这个还是Demo项目,实际在公司里面要考虑策略,满减,触发点,触发规则 库存 之类的,不是这个项目这么简单 4.教育背景提前,格式为 教育背景 实习 项目 技能 自我评价
简历被挂麻了,求建议
点赞 评论 收藏
分享
2025-12-18 18:23
深圳大学 前端工程师
程序员花海:实习和校招简历正确格式应该是教育背景+实习+项目经历+个人评价 其中项目经历注意要体现业务 实习经历里面的业务更是要自圆其说 简历模板尽可能保持干净整洁 不要太花哨的
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务