LeetCode刷题Day05——链表(链表元素删除、相交、环形链表)

简介: 一、删除链表中的倒数第n个节点

一、删除链表中的倒数第n个节点

题目链接:19.删除链表中的倒数第n个节点

/**
 * <pre>
 * 最简单的方法显然是先遍历一遍链表,知道长度后重新遍历一次就可以找到指定节点了,由此方法我们不难延伸到另一种解法
 * 既然是删除倒数第n个节点,那么也就是一旦遇到最后一个节点那么它前面的第n个节点就是要删除的节点
 * 我们只要使用快慢指针,慢指针在快指针前n位,那么当快指针到达链表尾时慢指针所指的就是需要删除的节点
 * </pre>
 *
 * @author <a href="https://github.com/kil1ua">Ken-Chy129</a>
 * @date 2023/1/5 14:52
 */
public class 删除链表的倒数第N个结点19 {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode pos1=new ListNode(), pos2=head, res = pos1;
        pos1.next = head;
        int i=0;
        while (pos2 != null) {
            if (i < n) { // 找的是链尾的前第n+1个,这样才能删除链尾的第n个
                i++;
            } else {
                pos1 = pos1.next;
            }
            pos2 = pos2.next;
        }
        pos1.next = pos1.next.next;
        return res.next;
    }
    public ListNode removeNthFromEnd2(ListNode head, int n) {
        ListNode p = new ListNode(), res = p;
        p.next = head;
        Deque<ListNode> stack = new LinkedList<>();
        while (p != null) {
            stack.push(p);
            p = p.next;
        }
        for (int i=0; i<n; i++) {
            stack.pop();
        }
        p = stack.peek();
        p.next = p.next.next;
        return res.next;
    }
}

二、链表相交

题目链接:160.链表相交

/**
 * <pre>
 * 计算出两个链表的长度,让长的链表先移动到和短的链表一样长(因为交点不可能在前面部分),随后两个链表同时移动,相等时即为交点
 * 或者使用哈希表将第一个链表的元素进行存储,然后遍历第二个链表判断当前节点是否存在在哈希表中
 * 两者时间复杂度相同,但是哈希表需要额外的空间开销(哈希表查找元素是需要O(1)的时间复杂度,所以总的时间开销相同)
 * </pre>
 *
 * @author <a href="https://github.com/kil1ua">Ken-Chy129</a>
 * @date 2023/1/6 13:49
 */
public class 链表相交160 {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode pa = headA, pb = headB;
        int lena=1, lenb=1;
        while (pa != null) {
            pa = pa.next;
            lena++;
        }
        while (pb != null) {
            pb = pb.next;
            lenb++;
        }
        pa = headA;
        pb = headB;
        if (lena > lenb) {
            for (int i=1; i<=lena-lenb; i++) {
                pa = pa.next;
            }
        } else if (lena < lenb) {
            for (int i = 1; i <= lenb - lena; i++) {
                pb = pb.next;
            }
        }
        while (pa != null) {
            if (pa == pb) {
                return pa;
            }
            pa = pa.next;
            pb = pb.next;
        }
        return null;
    }
    public ListNode getIntersectionNode2(ListNode headA, ListNode headB) {
        Set<ListNode> visited = new HashSet<ListNode>();
        ListNode temp = headA;
        while (temp != null) {
            visited.add(temp);
            temp = temp.next;
        }
        temp = headB;
        while (temp != null) {
            if (visited.contains(temp)) {
                return temp;
            }
            temp = temp.next;
        }
        return null;
    }
}

三、环形链表

题目链接:142.环形链表

/**
 * <pre>
 * 可以使用快慢指针的方式,让快指针每次走两格,慢指针每次走一格,快指针先入环而且一定会在环中与慢指针相遇
 * 因为在环中对于慢指针来说,其实快指针是以每次1的速度向他逼近,最终一定会碰上
 * </pre>
 *
 * @author <a href="https://github.com/kil1ua">Ken-Chy129</a>
 * @date 2023/1/6 14:26
 */
public class 环形链表II142 {
    public ListNode detectCycle(ListNode head) {
        ListNode pos1 = head, pos2 = head;
        while (pos2 != null) {
            if (pos2.next == null) {
                return null;
            }
            pos1 = pos1.next;
            pos2 = pos2.next.next;
            if (pos2 == pos1) {
                ListNode p = head;
                while (p != pos1) {
                    p = p.next;
                    pos1 = pos1.next;
                }
                return p;
            }
        }
        return null;
    }
}

注释中已经分析了如果有环为什么两个指针一定会在环中相遇,接下来分析一下如何寻找环的起点。

途中紫色点为快慢指针的相遇点,假设快指针走了n圈后与慢指针相遇,那么相遇时有:

  • 快指针走的距离:a+n(b+c)+b
  • 快指针走的距离是慢指针的两倍
  • 慢指针走的距离:a+b
  • 为什么慢指针一定会在第一圈跟快指针相遇?
  • 其实在注释中也写到了,每次循环可以理解为快指针在以每次为1的速度追赶慢指针,而在慢指针进入环的时候快指针距离它的距离最多也是少于1圈(快指针在慢指针前一位时为最长距离),那么追赶到的时候慢指针必然没有进入下一圈
  • 那么就有a+n(b+c)+b=2(a+b),化简得a=c+(n-1)(b+c),(n-1)(b+c)表示n-1圈,那么也就是说只要这时让一个指针从链表起点出发,另一个指针从快慢指针相遇点出发,那它们会正好在环的起点相遇(因为a的长度等于从快慢指针相交点绕环n-1圈后再走c的长度,而再走c的长度正好就是到环的起点)


相关文章
|
2月前
【力扣】-- 移除链表元素
【力扣】-- 移除链表元素
36 1
|
3月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
280页PDF,全方位评估OpenAI o1,Leetcode刷题准确率竟这么高
【10月更文挑战第24天】近年来,OpenAI的o1模型在大型语言模型(LLMs)中脱颖而出,展现出卓越的推理能力和知识整合能力。基于Transformer架构,o1模型采用了链式思维和强化学习等先进技术,显著提升了其在编程竞赛、医学影像报告生成、数学问题解决、自然语言推理和芯片设计等领域的表现。本文将全面评估o1模型的性能及其对AI研究和应用的潜在影响。
35 1
|
3月前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
2月前
|
算法
❤️算法笔记❤️-(每日一刷-160、相交链表)
❤️算法笔记❤️-(每日一刷-160、相交链表)
18 1
01_移除链表元素
01_移除链表元素
|
2月前
【LeetCode 06】203.移除链表元素
【LeetCode 06】203.移除链表元素
31 0
|
2月前
【数据结构】环形、相交、回文、分割、合并、反转链表
【数据结构】环形、相交、回文、分割、合并、反转链表
29 0
|
4月前
|
存储 算法
LeetCode第83题删除排序链表中的重复元素
文章介绍了LeetCode第83题"删除排序链表中的重复元素"的解法,使用双指针技术在原链表上原地删除重复元素,提供了一种时间和空间效率都较高的解决方案。
LeetCode第83题删除排序链表中的重复元素