必须要掌握的单链表操作大全

2023-05-16

前言

号外号外,笔者最近在系统整理一些 Java 后台方面的面试题和参考解答,有找工作需求的童鞋,欢迎关注我的 Github 仓库,如果觉得不错可以点个 star 关注 :

  • 1、awesome-java-interview
  • 2、awesome-java-notes

链表相关的各种常用操作实现方法

经常刷 leetcode 的童鞋一定对单链表的各种骚操作不陌生,单链表可以玩出各种各样的骚操作,掌握单链表的各种常规操作一方面对于锻炼我们的编程思维和编程能力很有帮助,另一方面,面试的时候面试官也会经常问一些单链表相关的题目,可以让自己提前预热吧,对此感到不陌生。

总之,帮助很大就是了。废话不多说,以下主要根据自己平时刷题总结了一些高频的、常规的单链表操作题目,后续有时间还会不断补上,目前大体思路主要写在注释中,后续有时间再单独将思路整理出来。

1)单链表反转
2)链表中环的检测
3)返回链表中环的入口节点
4)两个有序链表的合并
5)链表中倒数第 n 个节点
6)求链表的中间节点
7)删除有序链表中的重复节点,只保留其中一个节点
8)删除有序链表中的所有重复节点 9)在 O(1)
时间内删除链表的节点
10)从尾到头打印链表
11)两个链表的第一个公共节点

package com.offers.leetcode.linkedlist;

import java.util.ArrayList;
import java.util.LinkedList;

/**
 * 1)单链表反转
 * 2)链表中环的检测
 * 3)返回链表中环的入口节点
 * 4)两个有序链表的合并
 * 5)链表中倒数第 n 个节点
 * 6)求链表的中间节点
 * 7)删除有序链表中的重复节点,只保留其中一个节点
 * 8)删除有序链表中的所有重复节点
 * 9)在 O(1) 时间内删除链表的节点
 * 10)从尾到头打印链表
 * 11)两个链表的第一个公共节点
 *
 *
 * @author Rotor
 * @since 2019/10/23 22:49
 */
public class LinkedListAlgo {

    // 1)单链表反转
    public static Node reverse(Node list) {
        Node curr = list, pre = null;
        while (curr != null) {
            Node next = curr.next;
            curr.next = pre;
            pre = curr;
            curr = next;
        }
        return pre; // 此时前驱结点pre为反转后的头结点
    }

    /**
     * 2)检测链表是否有环
     *
     * 采用两个指针的方式可以判断链表是否有环。设置快慢两个指针,快指针一次走两步,慢指针一次走
     * 一步,如果链表有环,那么最终快慢指针会在环中的某个节点相遇(类比于在操场中跑步,跑得快的
     * 童鞋最终会追上跑得慢的童鞋,在跑道的某处相遇)。
     *
     * 时间复杂度:O(n)
     * 空间复杂度:O(1) 只需要临时存储快慢指针等几个指针的内存,因此只需常数级别的空间复杂度
     *
     * @param list
     * @return
     */
    public static boolean checkCircle(Node list) {
        if (list == null) return false;

        Node fast = list; // 快指针依次走两步
        Node slow = list; // 慢指针一次走一步
        while (fast.next != null && fast.next.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                return true;
            }
        }

        return false;
    }

    /**
     * 3)返回链表中环的入口节点
     *
     * 先检测链表中是否有环,如果有环,则慢指针继续从环中相遇节点往前遍历,并重新定义一个临时的指针指向头结点,与慢指针一样每次走
     * 一步,两者相遇处即为环的入口节点。
     *
     * 时间复杂度:O(n)
     * 空间复杂度:O(1)
     *
     * @param head
     * @return
     */
    public Node entryNodeOfList(Node head) {
        // 链表为空或者只有一个节点时,没有环
        if (head == null || head.next == null) {
            return null;
        }

        Node fast = head;
        Node slow = head;
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                Node newSlow = head;
                while (newSlow != slow) {
                    slow = slow.next;
                    newSlow = newSlow.next;
                }
                return slow;
            }
        }

        return null;
    }

    /**
     * 4)有序链表的合并
     *
     * @param l1 链表 l1
     * @param l2 链表 l2
     * @return 合并后的链表
     */
    public Node mergeTwoLists(Node l1, Node l2) {
        Node soldier = new Node(0); // 利用哨兵节点简化实现难度
        Node p = soldier;

        while (l1 != null && l2 != null) {
            if (l1.data < l2.data) {
                p.next = l1;
                l1 = l1.next;
            } else {
                p.next = l2;
                l2 = l2.next;
            }
            p = p.next;
        }

        /**
         * 处理还未处理的节点,哪条链表不为空则将其插入合并的链表中
         */
        if (l1 != null) {
            p.next = l1;
        }
        if (l2 != null) {
            p.next = l2;
        }
        return soldier.next;
    }

    /**
     * 5)链表中倒数第 K 个节点
     *
     * 定义两个指针,如果第一个指针走到链表尾节点时,第二个节点正好走到链表中的倒数第 K 个节点处,那么此时第二个节点即为倒数第 K
     * 个节点。也就是说,此时两个节点之间的距离为 k-1。所以我们现在可以反过来,先让第一个指针走 k-1 步,然后两个指针再同时每次往
     * 前移动一步,当第一个指针走到链表尾结点处时,此时第二个节点正好指向倒数第 K 个节点。
     *
     * 时间复杂度:O(n) 需要遍历一遍链表
     * 空间复杂度:O(1) 不需要额外存储空间,只需要临时存储几个指针
     *
     * @param list 单链表
     * @param k 倒数第 K 个节点
     * @return 返回倒数第 K 个节点
     */
    public static Node deleteLastKth(Node list, int k) {
        if (list == null || k == 0) {
            return null;
        }

        Node aheadNode = list; // 先走 k-1 个步的指针
        Node behhindNode = list; // 后走的指针
        // 第一个指针先移动 k-1 步
        for (int i = 0; i < k - 1; i++) {
            // k 的值比链表的节点数大
            if (aheadNode.next == null) {
                return null;
            }
            aheadNode = aheadNode.next;
        }

        // 将两个指针同时移动,直到第一个指针指向链表尾
        while (aheadNode.next != null) {
            aheadNode = aheadNode.next;
            behhindNode = behhindNode.next;
        }
        return behhindNode;
    }

    /**
     * 6)求链表中间节点
     *
     * 采用快慢指针的方式查找单链表的中间节点,快指针一次走两步,慢指针一次走一步,当快指针走到
     * 链表尾时,慢指针刚好到达中间节点。
     *
     * 时间复杂度:O(n)
     * 空间复杂度:O(1)
     *
     * @param list
     * @return
     */
    public static Node findMiddleNode(Node list) {
        if (list == null) return null;

        Node fast = list;
        Node slow = list;

        while (fast.next != null & fast.next.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }

    /**
     * 7)删除有序链表中的重复节点,只保留其中一个节点
     *
     * 这题要求在一个有序的链表里面删除重复的元素,只保留一个,
     * 也是比较简单的一个题目,我们只需要判断当前指针以及下一个指针是否重复,如果是,则删除下一个指针就可以了。
     *
     * @param head 链表
     * @return 删除了重复元素后的链表
     */
    public Node deleteDulplicatesI(Node head) {
        if (head == null || head.next == null) {
            return head;
        }

        int val = head.data;
        Node p = head;
        while (p != null && p.next != null) {
            if (p.next.data != val) {
                val = p.next.data;
                p = p.next;
            } else {
                // 删除 next
                Node n = p.next.next;
                p.next = n;
            }
        }

        return head;
    }

    /**
     * 8)删除有序链表中所有重复节点
     *
     * 不同于上一题中可以保留一个,这次需要全部删除。也就是说,当前节点及其后面紧跟着的所有的重复节点都要删除掉,
     * 为了链表不断开,我们可以在遍历的时候记录一个前驱结点 prev,用来处理删除重复节点之后链表的重新连接问题。
     *
     * 时间复杂度:O(n)
     * 空间复杂度:O(1)
     *
     * @param head 链表
     * @return 删除所有重复节点之后的链表
     */
    public Node deleteDulplicatesII(Node head) {
        if (head == null || head.next == null) {
            return head;
        }

        // 建立一个新的头节点代替原来的头结点 head(相当于新建一个哨兵节点),当作头结点的 prev;
        // 因为链表有序,所以新建节点的值设为头结点的值减去 1,可以保证一定不会与链表中其他节点的值相同。
        Node soldier = new Node(head.data - 1);
        soldier.next = head;
        Node prev = soldier;
        Node p = head;
        while (p != null && p.next != null) {
            // 如果没有重复,则 prev=p, next为p.next
            if (p.data != p.next.data) {
                prev = p;
                p = p.next;
            } else {
                // 如果有重复,继续遍历,直到不重复的节点
                int val = p.data;
                Node n = p.next.next;
                while (n != null) {
                    if (n.data != val) {
                        break;
                    }
                    n = n.next;
                }

                // 删除重复节点
                prev.next = n;
                p = n;
            }
        }
        // 这里不能返回
        return soldier.next;
    }

    /**
     * 10)删除链表节点(假设要删除的节点确实在链表中)——常规法
     *
     * 删除某个链表节点需要遍历找到该链表的前一个节点,由于单链表没有指针指向前一个节点,所以需要从头开始遍历,
     * 时间复杂度为 O(n)
     *
     * @param head
     * @param toBeDeleted
     */
    public void deleteNodeI(Node head, Node toBeDeleted) {
        if (head == null || toBeDeleted == null) {
            return;
        }

        // 链表中只有一个节点或者第一个节点就是要删除的节点
        if (head == toBeDeleted) {
            head = head.next;
        } else {
            Node curr = head;
            while (curr.next != null && curr.next != toBeDeleted) {
                curr = curr.next;
            }
            // 要删除节点不存在的情况
            if (curr.next == null) {
                return;
            }
            // cur为toBeDel的前一个结点
            curr.next = curr.next.next;
        }
    }

    // 删除链表节点——在O(1)时间内删除链表节点
    public void deleteNodeII(Node head, Node toBeDeleted) {
        if (head == null || toBeDeleted == null) {
            return;
        }

        // 要删除的节点不是最后一个节点
        if (toBeDeleted.next != null) {
            Node p = toBeDeleted.next;
            toBeDeleted.data = p.data; // 将要删除节点的后继节点的值覆盖它
            toBeDeleted.next = p.next;
            // 既是头结点也是尾节点
        } else if (head == toBeDeleted) {
            head = head.next;
        // 要删除的节点仅仅是尾节点,即在含有多个节点的链表中删除链表尾节点,此时因为要删除节点不存在后继节点,所以需要从头
        // 开始白能力链表,找到它的前驱节点
        } else {
            Node curr = head;
            while (curr.next != toBeDeleted) {
                curr = curr.next;
            }
            curr.next = null;
        }
    }

    /**
     * 10)从尾到头打印链表——使用栈的方法
     *
     * 从尾到头打印链表,可以顺序遍历一遍链表然后依次将遍历到的每个节点
     * 的值压入栈中,因为栈是“后进先出”的,所以得到的就是尾节点在前,头节点在后的列表。
     */
    public ArrayList<Integer> printListReversingly_Interatively(Node head) {
        LinkedList<Integer> stack = new LinkedList<>();
        Node pHead = head;
        while (pHead != null) {
            stack.push(pHead.data);
            pHead = pHead.next;
        }

        return new ArrayList<>(stack);
    }

    /**
     * 10)从尾到头打印链表——使用递归的方法
     *
     * 递归的本质也是栈(系统默认创建)。我们可以利用递归,先递归到最后一个节点再依次返回。但如果链表很长的话
     * 不适用于递归,因为递归的深度会很大,可能会造成堆栈溢出。
     *
     * @param head
     * @return
     */
    // 这是一个类成员变量
    private ArrayList<Integer> stack = new ArrayList<>();

    public ArrayList<Integer> printListReversingly_Recursively(Node head) {
        if (head != null) {
            printListReversingly_Recursively(head.next);
            stack.add(head.data);
        }
        return stack;
    }

    /**
     * 11)两个链表的第一个公共节点
     *
     * 首先遍历得到两个链表的长度,就可以得知哪个链表的长度更大。同时也就可以得知短的链表长度比长的链表的长度
     * 短多少,此时可以让长的链表先在链表上走若干步(两链表的长度之差),然后此时接同时继续遍历两个链表,找到
     * 第一个相同的节点就是它们的第一个公共节点。
     *
     * 时间复杂度:O(m+n) m和n分别表示两个链表的长度,因为要遍历两个链表得到它们的长度,所以时间复杂度为 O(m+n)
     * 空间复杂度:O(1) 不需要栈等额外的存储空间,所以为 O(1)
     *
     * @param list1
     * @param list2
     * @return
     */
    public Node findFirstCommonNode(Node list1, Node list2) {
        // 得到两个链表的长度
        int lengthOfList1 = getLengthOfList(list1);
        int lengthOfList2 = getLengthOfList(list2);
        int lengthDif = lengthOfList1 - lengthOfList2;

        Node pListHeadLong = list1; // 假设 list1 为更长的链表
        Node pListHeadShort = list2;
        if (lengthOfList1 < lengthOfList2) {
            pListHeadLong = list2;
            pListHeadShort = list1;
            lengthDif = lengthOfList2 - lengthOfList1;
        }

        // 先让长链表先走 lengthDir 步,让后两个链表再同时走,
        for (int i = 0; i < lengthDif; i++) {
            pListHeadLong = pListHeadLong.next;
        }

        while (pListHeadLong != null && pListHeadShort != null
        || (pListHeadLong != pListHeadShort)) {
            pListHeadLong = pListHeadLong.next;
            pListHeadShort = pListHeadShort.next;
        }
        // 得到第一个公共节点
        Node firstCommonNode = pListHeadLong;
        return firstCommonNode;
    }

    // 查找链表的长度
    public int getLengthOfList(Node list) {
        int lengthOfList = 0;
        while (list != null) {
            lengthOfList++;
            list = list.next;
        }
        return lengthOfList;
    }


    public static Node createNode(int value) {
        return new Node(value, null);
    }

    public static class Node {
        private int data;
        private Node next;

        public Node(int data) {
            this.data = data;
        }

        public Node(int data, Node next) {
            this.data = data;
            this.next = next;
        }
        public int getData() {
            return data;
        }
    }
}


后记

如果你同我一样想要努力学好数据结构与算法、想要刷 LeetCode 和剑指 offer,欢迎关注我 GitHub 上的 LeetCode 题解:awesome-java-notes

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

必须要掌握的单链表操作大全 的相关文章

  • Markdown中的LaTeX公式——希腊字母详解

    若要在Markdown中使用 xff0c 则在两个美元符号之间敲入对应LaTeX代码实现公式行显示效果 xff0c 若为公式块 xff0c 则要在四个美元符号中间敲入 xff0c 类似Markdown代码行和代码块 共24个希腊字母 xff
  • FFmpeg学习(一)-- ffmpeg 播放器的基础

    FFmpeg学习 xff08 一 xff09 FFmpeg学习 xff08 二 xff09 FFmpeg学习 xff08 三 xff09 FFmpeg的的是一套可以用来记录 xff0c 转换数字音频 xff0c 视频 xff0c 并能将其转
  • ios Instruments之Allocations

    文章目录 一 span class hljs function Allocations 监测内存分配 span 1 简介 2 如何使用 一 Allocations 1 简介 性能优化中使用Instruments Allocations工具进
  • linux-Centos-7-64位:4、 mysql安装

    从最新版本的Linux系统开始 xff0c 默认的是 Mariadb而不是MySQL xff01 这里依旧以mysql为例进行展示 1 先检查系统是否装有mysql rpm qa span class hljs string style c
  • Win10 WSL忘记用户密码,重置密码

    win10中WSL登录是不用密码的 xff0c 当需要使用用户权限但是忘记密码的时候 xff0c 可以使用如下办法以root身份登录WSL并重置密码 1 以管理员身份打开 PowerShell 2 输入命令 wsl exe user roo
  • 51单片机定时时间的计算

    单片机根据计时 计数模式的不同 xff0c 来进行计算 M1 M0 工作模式 说明 0 0 0 13位计时计数器 xff08 8192 xff09 0 1 1 16位计时计数器 xff08 65536 xff09 1 0 2 8位计时计数器
  • Go语言之禅

    本文翻译自Go社区知名Gopher和博主Dave Cheney的文章 The Zen of Go 本文来自我在GopherCon Israel 2020上的演讲 文章很长 如果您希望阅读精简版 xff0c 请移步到the zen of go
  • UIScrollView及其子类停止滚动的监测

    作为iOS中最重要的滑动控件 UIScrollView居然没有停止滚动的Delegate方法 这有点蛋疼 但是我们可以根据滚动状态来判断是否滚动 span class hljs preprocessor pragma mark scroll
  • PCL库中Marching Cubes(移动立方体)算法的解析

    PCL库中Marching Cubes xff08 移动立方体 xff09 算法解析 1 Marching Cubes算法的原理这里不再赘述 xff0c 不懂的话 xff0c 提供一下文献资源 xff1a 链接 xff1a MARCHING
  • ubuntu18.04安装cuda-10.0和cudnn-7.4.2

    安装cuda 10 0 1 gcc 版本 Ubuntu18 04默认gcc g 43 43 7 3版本 xff0c 如果安装cuda 9并不支持 gcc g 43 43 7 xff0c 所以先降级至6或6以下 我自己的gcc是7 5 0 安
  • Ubuntu安装anaconda3后找不到conda命令

    Ubuntu安装anaconda3后找不到conda命令的原因是没有把anaconda3添加到路径 xff0c 类似于Windows中添加到环境变量 xff0c 所以找不到命令 解决方法是在终端中运行一下命令 xff1a echo 39 e
  • uCharts Y轴格式化

    官方文档 uCharts跨平台图表库 1 Y轴格式化用法 xff1a yAxis data calibration true position 39 left 39 title 39 折线 39 titleFontSize 12 forma
  • C#/.NET Winform 界面库UI推荐

    以下是C CSkin界面库的官方板块 xff1a http bbs cskin net thread 622 1 1 html 几款开源的Windows界面库 https blog csdn net blade2001 article de
  • layui中实现按钮点击事件

    首先 xff0c 小编要告诉大家一个残酷的现实 xff0c 那就是小编没有找到layui对点击事件的支持 这里的点击事件是指单纯的点击事件 xff0c 而不是提交事件 xff0c 或者是数据表格中内嵌的button xff0c 对于这两者
  • C# devexpress gridcontrol 分页 控件制作

    这个小小的功能实现起来还是有一点点复杂 分页单独一个usercontrol 出来 导致查询换页 与gridcontrol页面分离 一般通过换页事件通知girdcontrol 做出查询 查询来说有时是查询所有 有时是查询一个月 或者别的时间
  • SQL Server 创建索引(CREATE NONCLUSTERED INDEX )

    索引的简介 xff1a 索引分为聚集索引和非聚集索引 xff0c 数据库中的索引类似于一本书的目录 xff0c 在一本书中通过目录可以快速找到你想要的信息 xff0c 而不需要读完全书 索引主要目的是提高了SQL Server系统的性能 x
  • .NET Core/.NET5/.NET6 开源项目汇总:(权限)管理系统

    前言 企业管理系统一般包含后台管理UI 组织机构管理 权限管理 日志 数据访问 表单 工作流等常用必备功能 下面收集的几款优秀开源的管理系统 xff0c 值得大家入门学习 如有新的优秀项目 xff0c 我会不断补充 开源项目是众多组织与个人
  • Nginx配置指令(一)

    1 daemon 语法 xff1a daemon on off 默认 xff1a on 如果使用daemon off xff0c nginx将会运行在前台 生产远景不建议如此使用 xff0c 虽然可以 2 env 语法 xff1a env
  • SQL将Json字符串转为表格

    支持复杂结构的使用 使用Parent ID来对应Object ID产生关系就好 实现对Json数据的从文字到表变量的转换 例 34 FieldName 34 34 DateKey 34 34 Title 34 34 汇总后日期 34 34
  • JavaScript实现动态添加的元素添加点击事件

    在页面开发过程中常常遇到需要动态添加元素 xff0c 然后给这一元素绑定相关事件的情况 xff0c 这种情况下一般需要给元素加上相关属性 xff0c 然后写这些元素的事件函数即可 动态添加的元素怎么绑定事件呢 xff1f 原生JavaScr

随机推荐

  • javascript解决小数的加减乘除精度丢失的方案

    原因 js按照2进制来处理小数的加减乘除 在arg1的基础上 将arg2的精度进行扩展或逆扩展匹配 所以会出现如下情况 javascript js 的小数点加减乘除问题 xff0c 是一个js的bug如0 3 1 61 0 29999999
  • SqlServer 获取字符串中数字,中文及字符部分数据

    获取英文字符数据 Create function dbo Fun GetChar 64 No varchar 100 RETURNS varchar 100 AS BEGIN WHILE PATINDEX 39 A Za z 39 64 N
  • Asp.net 如何跳过基于表单的身份验证(authentication)

    淘到的Form验证过程 xff1a xff08 如果所有页面继承了同一个判断是否登录的类 xff0c 路径的判断是个问题 xff0c 文件所处的位置可能不同 xff0c 有的是二级菜单 xff0c 有的三级 还有的是通过Request Ur
  • ASP.NET Core读取Request.Body的正确方法

    参考文章 xff1a 深入探究ASP NET Core读取Request Body的正确方式 https www cnblogs com wucy archive 2021 05 06 14699717 html 当然我们也可以自己实现一套
  • 【Python+OpenCV入门学习】五、绘制几何图形

    本篇文章 xff0c 将学习如何 绘制几何图形 xff0c 如画线 圆 矩形 椭圆等 xff0c 另外还学习在图像中增加文本信息 主要学习 函数 line circle rectangle ellipse putText 等 的使用 环境
  • 交换机性能的常用指标及术语解释

    交换机性能的常用指标及术语解释 流量控制 背压技术Back pressure 基于IEEE802 3X标准 xff0c 当处理发现缓冲器将要填满时 xff0c 就 向源发站发出一个假冲突信号 xff0c 使之延迟一个随机时间 xff0c 然
  • Ubuntu22.04-添加中文输入法

    1 安装中文语言包 进入setting xff08 设置 xff09 gt 区域与语言 选项卡 进入 管理已安装的语言 第一进入将提示 语言支持没有完整安装 xff0c 点击安装即可 安装过程会将为进行补充安装的语言进行下载安装 设置中文
  • 修改apache设置,支持UTF8和GBK

    1 修改 etc httpd conf httpd conf 文件 xff0c 将其中AddDefaultCharset行注释掉 前面加 2 保存后重新启动apache usr sbin apachectl restart或者service
  • 数论——GCD

    ZOJ Problem Set 3846 题意 xff1a 给 N 个数 xff0c 任取两个数Ai Aj xff0c 求出这两数的GCD xff0c 然后用GCD替换这两个数的值 直至这n个数的值都相等为止 xff0c 此时输出求GCD的
  • 群晖DDNS和端口转发等相关讲解

    文章目录 废话篇前言本文知识概要域名和IP地址的了解域名解析内网IP和外网IPDDNS是什么 xff1f 群晖如何设置DDNS端口转发后言协助改进 废话篇 本篇文章为原创文章 xff0c 转载请注明出处 xff0c 感谢 本人也有个人博客
  • Python更新失败:SSL错误——Conda/Python

    Python更新失败 SSL错误 xff08 1 xff09 是正常Python环境下的错误 xff1a 例如 xff1a Could not fetch URL https pypi tuna tsinghua edu cn simple
  • c语言经典题目--字符串篇

    1 有效的字母异位词 给定两个字符串 s 和 t xff0c 编写一个函数来判断 t 是否是 s 的字母异位词 注意 xff1a 若 s 和 t 中每个字符出现的次数都相同 xff0c 则称 s 和 t 互为字母异位词 include lt
  • UITextField和UITextView被键盘遮住的处理办法

    void textFieldDidBeginEditing UITextField textField float offset 61 0 0f if self txtField 61 61 textField offset 61 180
  • CAShapeLayer动画(画圆效果)

    关于CAShapeLayer和DrawRect的比较 DrawRect xff1a DrawRect属于CoreGraphic框架 xff0c 占用CPU xff0c 消耗性能大 CAShapeLayer xff1a CAShapeLaye
  • iOS调用各大地图APP导航,进行路线规划

    最近收到了这么一个需求 xff0c 就是支持目前主流的地图APP导航 xff0c 也就是说跳转至第三方应用 说实在的一开始我是拒绝的 xff0c 不过最后还是做了 xff0c 全是体力活 xff0c 为了方便大家 xff0c 我就终结一下
  • stm32cubeMX+vscode开发编译调试stm32程序

    stm32cubeMX 43 vscode开发编译调试stm32程序 安装vscode安装make工具安装交叉编译工具链安装openocd安装clang llvm生成并编译代码配置vscode安装插件配置文件c cpp properties
  • 如何在 Ubuntu 20.04 上安装 Jenkins?

    介绍 当面临重复性技术任务时 xff0c 寻找可行的自动化解决方案可能是一件苦差事 使用开源自动化服务器 Jenkins xff0c 您可以有效地管理从构建到部署软件的任务 Jenkins 是基于 Java 的 xff0c 从 Ubuntu
  • 并查集

    先上题目 题目描述 如题 xff0c 现在有一个并查集 xff0c 你需要完成合并和查询操作 输入格式 第一行包含两个整数N M xff0c 表示共有N个元素和M个操作 接下来M行 xff0c 每行包含三个整数Zi Xi Yi 当Zi 61
  • 使用PN532进行IC卡的Linux和Windows平台的数据读取以及写入过程

    强调 xff1a 勿用于非法用途 本文介绍使用PN532进行IC卡的Linux和Windows平台的数据读取以及写入过程 注意 xff1a 在树莓派平台只做到了卡片解密 xff0c 并没能写入UID卡 xff0c 我不清楚具体原因 xff0
  • 必须要掌握的单链表操作大全

    前言 号外号外 xff0c 笔者最近在系统整理一些 Java 后台方面的面试题和参考解答 xff0c 有找工作需求的童鞋 xff0c 欢迎关注我的 Github 仓库 xff0c 如果觉得不错可以点个 star 关注 xff1a 1 awe