首页 > 其他分享 >【Leetcode】 剑指offer:链表(简单)--Day02

【Leetcode】 剑指offer:链表(简单)--Day02

时间:2022-11-08 16:01:58浏览次数:38  
标签:Node head offer -- random next 链表 ori null

剑指Offer 06. 从尾到头打印链表

可借助栈。

或先遍历列表得到元素数,开辟数组空间倒序填入。

剑指 Offer 24. 反转链表

可借助栈:

class Solution {
    public ListNode reverseList(ListNode head) {
        if(head == null) return null;
        Deque<ListNode> d = new LinkedList<>();
        ListNode cur = head;
        while(cur != null) {
            d.addLast(cur);
            cur = cur.next;
        }
        ListNode nhead = d.pollLast();
        cur = nhead;
        while(!d.isEmpty()) {
            cur.next = d.pollLast();
            cur = cur.next;
        }
        cur.next = null;
        return nhead;
    }
}

双指针

双指针所定位的两个结点的指向关系要反过来,这会导致后方指针原本所指的结点丢失。因此每次双指针的移动要借助第三个指针解决结点丢失问题,使得双指针能够进行位置更新。

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode p1 = null, p2 = head;
        while(p2 != null) {
            ListNode tmp = p2.next;
            p2.next = p1;
            p1 = p2;
            p2 = tmp;
        }
        return p1;
    }
}

剑指 Offer 35. 复杂链表的复制

在复杂链表中,每个节点除了有一个next指针指向下一个节点,还有一个random指针指向链表中的任意节点或者null

复杂链表的复制难点在于,复制到某一结点时,该random指针所指结点可能还未被创建。所以大致有两种思路:

  • 既创建next所指结点,又创建random所指结点。
  • next所指顺序依次创建结点,全部结点创建后再开始random指针的赋值。
方法一:next结点与random结点同时递归生成

利用一Map记录结点的创建情况,若已创建则直接返回,否则创建后更新Map。由于next指针连接了所有节点,故所有节点都会被复制。

class Solution {
    Map<Node, Node> createdNode = new HashMap<>();
    public Node copyRandomList(Node head) {
        if(head == null) return null;
        Node neuu = createdNode.get(head);
        if(neuu == null) {
            neuu = new Node(head.val);
            createdNode.put(head, neuu);
            neuu.next = copyRandomList(head.next);
            neuu.random = copyRandomList(head.random);
        }
        return neuu;
    }
}
方法二:先next,后random(Map映射新旧节点)

同样采用Map记录新旧节点的对应情况。整个过程由两次针对原链表的循环组成。

第一次循环的过程除进行常规链表的复制以外,添加Map键值对,建立由原节点到新节点的映射。

第二次循环通过Map建立新节点之间的random指向关系。

class Solution {
    public Node copyRandomList(Node head) {
        if(head == null) return null;
        Map<Node, Node> m = new HashMap<>();
        Node ori = head, last = null;
        while(ori != null) {
            m.put(ori, new Node(ori.val));
            if(ori != head) {
                m.get(last).next = m.get(ori);
            }
            last = ori;
            ori = ori.next;
        }
        m.get(last).next = null;

        ori = head;
        while(ori != null) {
            if(ori.random != null) {
                m.get(ori).random = m.get(ori.random);
            }
            else {
                m.get(ori).random = null;
            }
            ori = ori.next;
        }
        return m.get(head);
    }
}
方法三:先next,后random(新节点暂时插入原节点后)

方法二与方法三并无本质区别,对random指针赋值的基础都是新旧相应结点的映射。

方法二主要由三次链表的遍历组成:

第一次遍历,按照原链表next顺序依次创建新节点,并将新节点插入原链表对应旧结点后,使原链表的长度翻倍。这样做的意义是实现了通过旧结点的next指针访问对应新结点,且原列表的next顺序也没有丢失。

第二次遍历,复制random关系。这一遍历的循环变量仍然会依次被赋值为原链表的各节点,假设某一时刻循环变量指向结点A。则A.next指向新节点,A.random指向原节点的random目标,A.random.next指向新节点random指针待指向的节点。

第三次遍历,将新旧链表分离。

class Solution {
    public Node copyRandomList(Node head) {
        if(head == null) return null;
        for(Node ori = head; ori != null; ori = ori.next.next) {
            Node neuu = new Node(ori.val);
            neuu.next = ori.next;
            ori.next = neuu;
        }
        for(Node ori = head; ori != null; ori = ori.next.next) {
            Node neuu = ori.next;
            neuu.random = (ori.random == null)?null:(ori.random.next);
        }
        Node nhead = head.next;
        for(Node ori = head; ori != null; ori = ori.next) {
            Node neuu = ori.next;
            ori.next = neuu.next;
            if(neuu.next != null) neuu.next = neuu.next.next;
        }
        return nhead;
    }
}

标签:Node,head,offer,--,random,next,链表,ori,null
From: https://www.cnblogs.com/hsjia/p/16869790.html

相关文章

  • vue.js3:div上添加右键菜单([email protected])
    一,js代码:<template><div><divstyle="width:800px;margin:auto;display:flex;flex-direction:column;"><div>请选择上传图片:<inputtype="......
  • 13个常用的​JavaScript代码片段
    JavaScript可以做很多好玩的事,从复杂的框架到处理API,有太多的东西需要学习。但是,它也能让我们只用一行就能做一些了不起的事情。1、获得一个随机的布尔值(true/false)该函数......
  • 转型和instanceof关键字
    向上转型向下转型instanceof关键字向下转型向下转型和继承和覆写构成了多态,多态的出现使得父类成为一个接口,屏蔽了不同子类的差异性,为统一的变成成为了可能没有用......
  • 从图灵机到量子计算机,计算机可以解决所有问题吗?
    本文已收录到 GitHub·AndroidFamily,有Android进阶知识体系,欢迎Star。技术和职场问题,请关注公众号[彭旭锐]进Android面试交流群。前言大家好,我是小彭。今......
  • 01 向量与坐标 | 解析几何
    1.向量的概念与运算1.向量向量:既有大小又有方向的量叫做向量,或称矢量标量:只有大小(可用一个数值表示)向量的几何表示:有向线段\(\overrightarrow{P_1P_2}\)或者\(\vec......
  • 【前端面试题】—26道HTTP和HTTPS的面试题(附答案)
    Web前端就是当用户在浏览器地址栏中输入一行字母看到的页面结果。然而,从输入字母到看到页面中都发生了什么,数据是怎么得到的?这些都离不开HTTP/HTTPS。然而,这部分内容通常被......
  • lz 日记的使用
     实际上,在API中使用时,可以使用$db_name与当前数据库匹配......
  • 你需要知道的 10 个 JavaScript 技巧和窍门
    英文|https://javascript.plainenglish.io/top-10-javascript-tips-and-tricks-you-need-to-know-27896d2a313f翻译|杨小二JavaScript非常了不起,许多程序员都在使用它......
  • 逆向递归,给一个完整的树,找对应的部门树
    递归找到树找到部门树构建一棵树很简单,只要有parentId,很简单递归就能构建好这棵树,今天来讲怎么样递归从树中找到这个对应id的树,比如传入部门id找到这个部门......
  • 当Sass和新CSS功能发生冲突时的解决方案
    英文| https://css-tricks.com/when-sass-and-new-css-features-collide/翻译|web前端开发我们都知道,CSS添加了许多新的很酷的功能,例如,自定义属性的新功能,css的一些基础......