LeetCode 热题 HOT 100:链表专题

2023-11-12

LeetCode 热题 HOT 100:https://leetcode.cn/problem-list/2cktkvj/



2. 两数相加

题目链接:https://leetcode.cn/problems/add-two-numbers/?envType=featured-list&envId=2cktkvj?envType=featured-list&envId=2cktkvj

实现步骤:

  • 将两个链表看成是相同长度的进行遍历,如果一个链表较短则在前面补 0,比如:987 + 23 = 987 + 023 = 1010。
  • 每一位计算的同时需要考虑上一位的进位问题,而当前位计算结束后同样需要更新进位值。
  • 如果两个链表全部遍历完毕后,进位值为 1,则在新链表最前方添加节点。
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode pre = new ListNode(0);
        ListNode p1 = l1, p2 = l2, q = pre;
        int sign = 0;
        while(p1 != null || p2 != null){
            int sum = 0;
            if(p1 == null){
                sum = p2.val + sign;
                p2 = p2.next;
            }else if(p2 == null){
                sum = p1.val + sign;
                p1 = p1.next;
            }else{
                sum = p1.val + p2.val + sign;
                p1 = p1.next;
                p2 = p2.next;
            }
            sign = sum >= 10 ? 1 : 0; // 修改标志位
            ListNode node = new ListNode(sum % 10);
            q.next = node;
            q = q.next;
        }
        if(sign == 1){
            ListNode node = new ListNode(1);
            q.next = node;
        }
        return pre.next;
    }
}

19. 删除链表的倒数第 N 个结点

题目链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/?envType=featured-list&envId=2cktkvj?envType=featured-list&envId=2cktkvj

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode pre = new ListNode(0); // 伪头部节点
        pre.next = head;
        ListNode p, q;
        p = q = pre;
        int co = 0;
        while(q.next != null){ // 先让q指针先走n步,然后p指针再继续走
            if(++co > n){
                p = p.next;
            }
            q = q.next;
        }// 结束循环时,p指针指向倒数第N+1位
        p.next = p.next.next;
        // 注意避坑点:return head; 是存在问题的:当链表中只有一个元素时,p指针会进行删除后,head 还是指向原来的那个结点。
        return pre.next; 
    }
}

21. 合并两个有序链表

题目链接:https://leetcode.cn/problems/merge-two-sorted-lists/?envType=featured-list&envId=2cktkvj?envType=featured-list&envId=2cktkvj

class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode res = new ListNode(0);
        ListNode p = res;
        while(list1 != null && list2 != null){
            if(list1.val < list2.val){
                p.next = list1;
                list1 = list1.next;
            }else{
                p.next = list2;
                list2 = list2.next;
            }
            p = p.next;
        }
        p.next = list1 == null ? list2 : list1;
        return res.next;
    }
}

23. 合并 K 个升序链表

题目链接:https://leetcode.cn/problems/merge-k-sorted-lists/?envType=featured-list&envId=2cktkvj?envType=featured-list&envId=2cktkvj

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        ListNode head = null;
        for(int i = 0; i < lists.length; i ++){
            head = mergeTwoLists(head, lists[i]);
        }
        return head;
    }

    public ListNode mergeTwoLists(ListNode a, ListNode b){
        ListNode res = new ListNode(0);
        ListNode p = res;
        while(a!=null && b!=null){
            if(a.val < b.val){
                p.next = a;
                a = a.next;
            }else{
                p.next = b;
                b = b.next;
            }
            p = p.next;
        }
        p.next = a != null ? a : b;
        return res.next;
    }
}

141. 环形链表

题目链接:https://leetcode.cn/problems/linked-list-cycle/description/?envType=study-plan-v2&envId=top-100-liked

哈希表做法(时间复杂度较高):

public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head == null){
            return false;
        }
        Set<ListNode> set = new HashSet(); // set 记录结点的地址
        while(head.next != null){
            if(set.contains(head)){
                return true;
            }
            set.add(head);
            head = head.next;
        }
        return false;
    }
}

快慢指针做法1:

public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head == null){
            return false;
        }
        ListNode slow, fast;
        slow = head;
        fast = head.next;
        // slow 每次向前走一步,fast 每次向前走两步(可以任意多步)
        // 当存在环时,fast 由于走得快,会发生扣圈的情况,且最终与 slow 相遇
        // 当不存在环时,fast 可能在某次循环后,发生当前位置为空,或下一位置为空的两种情况,当然由于走的快,最终会返回false。
        // 总之,循环的结束条件,要么出现环 slow == fast,要么 fast 先一步为空! 
        while(slow != fast && fast != null && fast.next != null){
            // 注意:fast != null 要先于fast.next != null 来判断,以防止控制帧异常
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow == fast;
    }
}

快慢指针做法2(思路同下方“环形链表2”):

public class Solution {
    public boolean hasCycle(ListNode head) {
        ListNode slow = head, fast = head;

        while(true){
            if(fast==null || fast.next==null){
                return false;
            }
            slow = slow.next;
            fast = fast.next.next;
            if(slow==fast){
                return true;
            }
        }
    }
}

142. 环形链表 II

题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/?envType=study-plan-v2&envId=top-100-liked

哈希表做法(时间复杂度较高):

public class Solution {
    public ListNode detectCycle(ListNode head) {
        Set<ListNode> set = new HashSet<>();
        ListNode p = head;
        while(p!=null){
            if(set.contains(p)){
                return p;
            }
            set.add(p);
            p = p.next;
        }
        return null;
    }
}

快慢指针,实现思路如下:

  • fast 每次走两个节点, slow 每次走一个节点。环外有 a 个结点,环内有 b 个结点。
  • 相遇时,fast 走了 f 步,slow 走了 s 步。
    f = 2s
    f = s + nb 表示 fs 多走了 n*b 步,即 n 圈。这样表示的原因在于扣圈。
    化简得:f = 2nb, s = nb
  • 设刚开始 slow 指针从开始到环的入口要走 k 步:k = a + nb (n = 0,1,2,…)
  • 由于 s = n*b,即已经走了 n*b 步了,那么此时只需要再走 a 步即可回到链表入环的起点。
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head, slow = head;
        while(true){
            if(fast == null || fast.next == null){
                return null;
            }
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow){
                break;
            }
        }
        fast = head; // fast回到链表起点,与 slow 一同遍历 a 步
        while(slow != fast){
            slow = slow.next;
            fast = fast.next;
        }
        return fast;
    }
}

148. 排序链表

题目链接:https://leetcode.cn/problems/sort-list/?envType=featured-list&envId=2cktkvj?envType=featured-list&envId=2cktkvj

使用优先队列模仿堆:

class Solution {
    public ListNode sortList(ListNode head) {
        PriorityQueue<ListNode> queue = new PriorityQueue<>((a, b) -> b.val-a.val); // 大顶堆
        while(head != null){
            queue.offer(head); // 从堆底插入
            head = head.next;
        }
        ListNode pre = new ListNode(0);
        while(!queue.isEmpty()){
            ListNode p = queue.poll(); // 出队列并调整堆
            p.next = pre.next; // 头插法倒序
            pre.next = p;
        }
        return pre.next;
    }
}

自顶向下归并排序1: 时间复杂度 O(nlogn),空间复杂度O(logn)

class Solution {
    public ListNode sortList(ListNode head) {
        return mergeSort(head, null);
    }

    // 归并排序
    // 将头指针和尾指针之前的元素进行排序,初始尾指针为null,即最后一个节点的下一个空节点
    public ListNode mergeSort(ListNode head, ListNode tail){
        if(head == tail){
            return head;
        }
        if(head.next == tail){ // 隔离出来单独结点
            head.next = null;
            return head;
        }
        ListNode slow, fast;
        slow = fast = head;
        while(fast != tail){
            slow = slow.next;
            fast = fast.next;
            if(fast != tail){
                fast = fast.next;
            }
        }
        ListNode mid = slow;
        ListNode l1 = mergeSort(head, mid); // 将 head 至 mid 之前的节点进行排序
        ListNode l2 = mergeSort(mid, tail); // 将 mid 至 tail 之前的节点进行排序
        return mergeList(l1, l2);
    }

    // 合并两个有序链表
    public ListNode mergeList(ListNode l1, ListNode l2){
        ListNode pre = new ListNode(0);
        ListNode p = pre;
        while(l1 != null && l2 != null){
            if(l1.val < l2.val){
                p.next = l1;
                l1 = l1.next;
            }else{
                p.next = l2;
                l2 = l2.next;
            }
            p = p.next;
        }
        p.next = l1 == null ? l2:l1;
        return pre.next;
    }
}

参考链接:https://leetcode.cn/problems/sort-list/solutions/492301/pai-xu-lian-biao-by-leetcode-solution/?envType=featured-list&envId=2cktkvj%3FenvType%3Dfeatured-list&envId=2cktkvj

自顶向下归并排序2:

class Solution {
    public ListNode sortList(ListNode head) {
        return mergeSort(head);
    }
    
	// 归并排序
    public ListNode mergeSort(ListNode head){
        if(head==null || head.next==null){
            return head;
        }
        ListNode slow = head; // 快慢指针
        ListNode fast = head.next;

        while(fast!=null && fast.next!=null){ // 查询中间节点
            slow = slow.next;
            fast = fast.next.next;
        }

        ListNode mid = slow.next; // 断链
        slow.next = null;

        ListNode l1 = mergeSort(head);
        ListNode l2 = mergeSort(mid);
        return mergeList(l1, l2);
    }

	// 合并两个有序链表
    public ListNode mergeList(ListNode l1, ListNode l2){
        ListNode pre = new ListNode(0);
        ListNode p = pre;
        while(l1 != null && l2 != null){
            if(l1.val < l2.val){
                p.next = l1;
                l1 = l1.next;
            }else{
                p.next = l2;
                l2 = l2.next;
            }
            p = p.next;
        }
        p.next = l1 == null ? l2:l1;
        return pre.next;
    }
}

自底向上排序: 时间复杂度 O(nlog),空间复杂度O(n)

class Solution {
    public ListNode sortList(ListNode head) {
        ListNode pre = new ListNode(0);
        pre.next = head;

        int len = getLength(head); // 获取长度
        for(int step = 1; step < len; step *=2){ //依次将链表分块的长度分为:1,2,4...
            ListNode curr = pre.next;
            ListNode p = pre;
            // p 用于链接每次分块的链表,如:第一次循环链接分块长度为1的链表,然后链接分块长度为2的链表
            while(curr != null){
                ListNode h1 = curr; // 第一块链表的头
                ListNode h2 = spilt(h1, step); // 第二块链表的头
                curr = spilt(h2, step); // 下次while循环的头,也是给到h1
                // 合并第一二块链表,下次while循环合并第三四块链表....
                ListNode res = mergeList(h1, h2);
                // 将合并后的链表链接起来,并将指针移到链表的最后一个节点,以链接下次的链表
                p.next = res;
                while(p.next!=null){
                    p = p.next;
                }
            }
        }
        return pre.next;
    }

    // 分割链表,并返回后半段的链头
    public ListNode spilt(ListNode head, int step){
        if(head == null){
            return null;
        }
        ListNode p = head;
        for(int i = 1; i < step && p.next!=null; i ++){
            p = p.next;
        }
        ListNode right = p.next;
        p.next = null; // 切断连接
        return right;
    }

    // 求链表长度
    public int getLength(ListNode head){
        int co = 0;
        while(head!=null){
            co++;
            head = head.next;
        }
        return co;
    }

    // 合并两个升序链表
    public ListNode mergeList(ListNode l1, ListNode l2){
        ListNode pre = new ListNode(0);
        ListNode p = pre;
        while(l1 != null && l2 != null){
            if(l1.val < l2.val){
                p.next = l1;
                l1 = l1.next;
            }else{
                p.next = l2;
                l2 = l2.next;
            }
            p = p.next;
        }
        p.next = l1 == null ? l2:l1;
        return pre.next;
    }
}

160. 相交链表

题目链接:https://leetcode.cn/problems/intersection-of-two-linked-lists/?envType=featured-list&envId=2cktkvj?envType=featured-list&envId=2cktkvj

实现步骤:

  • 设不是公共部分的节点数分别是 a、b,公共节点数为 n
  • 如果有公共节点,则当 p1 遍历完 a+n 个节点时,再在另一个链表的头部遍历 b 个节点时,必相交。原因在于此时 p2 遍历了 b+n+a 个结点。
  • 如果没有公共节点部分,那么 p1p2 经历了上文的步骤后,都会为 nullnull==nulltrue
    因此跳出循环,要么 null == null,要么都不为空找到了公共节点。
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode p1 = headA;
        ListNode p2 = headB;
        while(p1 != p2){
            p1 = p1 == null ? headB : p1.next;
            p2 = p2 == null ? headA : p2.next;
        }
        return p1;
    }
}

206. 反转链表

题目链接:https://leetcode.cn/problems/reverse-linked-list/?envType=featured-list&envId=2cktkvj?envType=featured-list&envId=2cktkvj

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode pre = new ListNode(0);
        ListNode p = head;
        while(p!=null){
            ListNode q = p.next;
            p.next = pre.next;
            pre.next = p;
            p = q;
        }
        return pre.next;
    }
}

234. 回文链表

题目链接:https://leetcode.cn/problems/palindrome-linked-list/?envType=featured-list&envId=2cktkvj?envType=featured-list&envId=2cktkvj

class Solution {
    public boolean isPalindrome(ListNode head) {
        Deque<ListNode> stack = new LinkedList<>();
        ListNode p = head;
        while(p!=null){
            stack.push(p);
            p = p.next;
        }
        while(head != null){
            p = stack.pop();
            if(p.val != head.val){
                return false;
            }
            head = head.next;
        }
        return true;
    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

LeetCode 热题 HOT 100:链表专题 的相关文章

随机推荐

  • 手动安装xapk

    xpak文件实际是一个压缩包 用解压软件可查看其内容 情况1 obb 多见于游戏 apk主包文件很小 用户能安装并启动 要解锁游戏全部内容 则需要下载obb文件 obb文件一般位于 sd卡的根目录下 路径大概是 sdcard Android
  • vue admin-template 添加动态路由

    store getters js const getters sidebar state gt state app sidebar device state gt state app device token state gt state
  • MATLAB实现最大类间方差算法

    Otsu算法 大律法或最大类间方差法 最大类间方差法是由日本学者大津 Nobuyuki Otsu 于1979年提出的 是一种自适应的阈值确定的方法 又叫大津法 简称OTSU 它是按图像的灰度特性 将图像分成背景和目标2部分 背景和目标之间的
  • Pycharm破解方法

    3 破解补丁激活 优点 到期时间为2099年 基本为永久啦 缺点 相对服务器激活麻烦些 但是一共只需要3个步骤 其实并不麻烦 下载 https pan baidu com s 1mcQM8CLUnweY02ahKEr4PQ 并将 Jetbr
  • win7设置右键+T 快捷键 快速新建文本文档

    1 win r 组合键呼出 运行 win就是键盘上和桌面 开始 有相同图标的按键 田 字 2 输入regedit 回车 出现 注册表编辑器 窗口 3 窗口下寻找这个位置 HKEY CLASSES ROOT Local Settings Mu
  • 【pygame学习_5】窗口设计

    1 引言 窗体是游戏的交互界面 一般我们会遇到窗口大小可调 窗口无边框 全屏显示 最小化设计 改名字 换图标等设计需求 屏幕绘制有如下重要函数 2 屏幕模式函数 pygame display set mode print pygame di
  • java解析蓝奏云直连(解析真正文件地址)

    使用htmlunit解析蓝奏云直连 前言 最近有个需求 客户端需要更新软件版本 我一直在用蓝奏云 觉得是个非常不错的网盘 可是如果用户自己打开连接选择下载方式很麻烦 用过蓝奏的朋友都知道 打开外链还要选择普通下载 电信下载 联通下载 很麻烦
  • 多系统UEFI启动项清理,windows、ubuntu,win10盘符隐藏

    文章目录 step1 推荐方法 step2 在window系统中启动cmd窗口 win10 隐藏不必要的盘符 如单机多系统情形 step1 推荐方法 参考 https blog csdn net mtllyb article details
  • sap服务器数据库配置文件,安装和配置 SAP 和数据库

    安装和配置 SAP 和数据库 使用本节中的过程可以执行以下任务 安装 SAP 和数据库 安装 SAP 和可缩放的应用程序服务器 使 SAP 能够在群集中运行 检验 SAP 和数据库安装是否适合于中央实例 检验 SAP 和数据库安装是否适合于
  • R语言排序函数sort(),rank(),order()

    转载地址 http blog sina com cn s blog 6caea8bf0100spe9 html 在R中 和排序相关的函数主要有三个 sort rank order sort x 是对向量x进行排序 返回值排序后的数值向量 r
  • c++智能指针

    C 智能指针详解 本文系转载 原文出处 诚然原博主总结的非常好 我只是加一些自己觉得需要补充的地方 并且在最后给出目前c 11在智能指针这方面的弥补 一 简介 由于 C 语言没有自动内存回收机制 程序员每次 new 出来的内存都要手动 de
  • 分布式系统实现幂等性的方式

    幂等性 接口的幂等性就是同样的数据 在实现方法的多次调用 得到的结果一致 对于查询接口 天然的保持幂等性 但是对于cud来说 如何保持幂等性 看法 从以下方式来看 要保证幂等性 必须要有一个标识 至始至终的保持不变的标识 只有这样 后来的操
  • 开源点云数据集整理汇总

    目录 一 ModelNet40 1 网址 2 模型 二 ShapeNet 1 网址 2 模型 三 S3DIS Dataset 1 网址 2 模型 四 ScanNet 1 网址 2 模型 五 RGB D Object Dataset 1 网址
  • 麻雀算法极限学习机SSA-ELM回归预测及其MATLAB代码实现

    作者简介 热爱科研的Matlab仿真开发者 修心和技术同步精进 matlab项目合作可私信 个人主页 Matlab科研工作室 个人信条 格物致知 更多Matlab仿真内容点击 智能优化算法 神经网络预测 雷达通信 无线传感器 信号处理 图像
  • 哈希 学习笔记

    Tips Hash 哈希 散列 Tips 哈希经常与哈希函数指一个意思 本文中哈希与哈希函数不做特殊区分 默认就是一个意思 什么是哈希 在记录的关键字与记录的存储地址之间建立的一种对应关系叫哈希函数 哈希函数就是一种映射 是从关键字到存储地
  • AI笔记(1)

    回归与分类 回归 在数学表示 数值是一个连续性的 要预测的一个值 回归分析是一种预测性的建模技术 它研究的是因变量和自变量之家的关系 这种技术通常用于预测分析 通过使用直线或曲线来拟合数据点 目标是使曲线到数据点的距离差异最小 分类 分类模
  • python重新加载某方法

    20221014 引言 我记得 在很久之前我就弄过这部分内容 当时也是在jupyter notebook中进行实验 然后在这个过程中 需要重新加载某个方法 因为在实验过程中 修改了这个py文件中的函数 整体的思路就是这样 这次也是遇到了这个
  • nginx+ftp实现图片的上传与访问

    1 Nginx的安装 在前面的博客讲到 具体见下面的网址 Nginx的安装 http blog csdn net zbw18297786698 article details 52556293 2 Linux安装ftp组件 2 1 安装vs
  • 随e行创建L2TP 809 错误【一键脚本】

    请下载下面的文件 809 repair zip 右键点击 809 repaire bat 文件 以管理员身份运行 选择 是 根据提示 输入对应字符 yes 以完成对注册表的修改 等待脚本完成对注册表和服务的更改 按任意键退出窗口 809错误
  • LeetCode 热题 HOT 100:链表专题

    LeetCode 热题 HOT 100 https leetcode cn problem list 2cktkvj 文章目录 2 两数相加 19 删除链表的倒数第 N 个结点 21 合并两个有序链表 23 合并 K 个升序链表 141 环