代码随想录算法训练营第四天 | LeetCode 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II

简介: 代码随想录算法训练营第四天 | LeetCode 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II

1. LeetCode 24. 两两交换链表中的节点

1.1 思路

  1. 定义虚拟头节点dummyhead,要不然每次针对头结点(没有前一个指针指向头结点),还要单独处理,并且cur=dummyhead,因为这里的步骤是首先cur下一个先指向节点2,然后节点2下一个指向节点1,再然后是节点1下一个指向节点3,最后让cur指向翻转后的节点1,直接cur=first就行。所以需要dummyhead的原因就是因为cur要指向要翻转的两个节点的前一个节点。
  2. 具体实现先定义dummyhead,并且让dummyhead的next指向head,cur指向dummyhead,这样指向才能让最开始操作头节点和第二个节点的翻转
  3. 遍历过程while(cur.next!=null&&cur.next.next!=null),第一个条件是针对如果链表上是偶数个节点,那如果cur.next为空那就结束循环,第二个条件是针对如果链表上是奇数个节点,那如果cur.next.next为空那就结束循环,这里不理解可以画图理解一下,注意这里要用&&不能用||,因为如果用了||那如果是奇数个节点,cur.next就不为空那就进入循环里进行翻转了,但奇数个节点最后单独那个节点不用翻转,所以要用&&
  4. 翻转步骤:首先cur下一个先指向节点2,然后节点2下一个指向节点1,再然后是节点1下一个指向节点3,最后让cur指向翻转后的节点1,直接cur指向节点1就行(因为翻转的是两个节点,到下两个节点了,直接后移两位,也就是指向节点1就行)。这里问题在于如果直接用cur.next=cur.next.next;cur.next.next=cur.next的方式操作的话就找不到原来的指针了,因此要用first保存cur.next,second保存cur.next.next,temp作为节点3保存cur.next.next.next(这里节点3有可能是个空指针,但没关系的)。上面翻转的cur.next=second;second.next=first;first.next=temp;cur=first;
  5. return dummyhead.next就是新的链表

1.2 代码

class Solution {
  public ListNode swapPairs(ListNode head) {
        ListNode dumyhead = new ListNode(-1); // 设置一个虚拟头结点
        dumyhead.next = head; // 将虚拟头结点指向head,这样方面后面做删除操作
        ListNode cur = dumyhead;
        ListNode temp; // 临时节点,保存两个节点后面的节点
        ListNode firstnode; // 临时节点,保存两个节点之中的第一个节点
        ListNode secondnode; // 临时节点,保存两个节点之中的第二个节点
        while (cur.next != null && cur.next.next != null) {
            temp = cur.next.next.next;
            firstnode = cur.next;
            secondnode = cur.next.next;
            cur.next = secondnode;       // 步骤一
            secondnode.next = firstnode; // 步骤二
            firstnode.next = temp;      // 步骤三
            cur = firstnode; // cur移动,准备下一轮交换
        }
        return dumyhead.next;  
    }
}

2. LeetCode19.删除链表的倒数第N个节点

2.1 思路

  1. 如何找到倒数第n个节点呢?定义虚拟头节点dummyhead,它的next指向head,好处依然是方便我们不需要判断要删除的节点是不是头节点,这样删除的操作比较统一
  2. 定义fast和slow指针都指向dummyhead,然后让fast指针先移动n+1步,然后fast和slow同时移动直到fast指向null,此时slow就指向要删除的节点的前一个节点了

2.2 代码

public ListNode removeNthFromEnd(ListNode head, int n){
    ListNode dummyNode = new ListNode(0);
    dummyNode.next = head;
    ListNode fastIndex = dummyNode;
    ListNode slowIndex = dummyNode;
    //只要快慢指针相差 n 个结点即可
    for (int i = 0; i < n  ; i++){
        fastIndex = fastIndex.next;
    }
    while (fastIndex.next != null){
        fastIndex = fastIndex.next;
        slowIndex = slowIndex.next;
    }
    //此时 slowIndex 的位置就是待删除元素的前一个位置。
    //具体情况可自己画一个链表长度为 3 的图来模拟代码来理解
    slowIndex.next = slowIndex.next.next;
    return dummyNode.next;
}

3. LeetCode 面试题 02.07. 链表相交

3.1 思路

  1. 让curLong指向headA,curShort指向headB,假设是这样
  2. 然后遍历求出两链表的长度,以及差值len,让长的先走差值len步
  3. 然后while(curLong!=curShort)一直遍历两个后移,直到相等,最后return 其中一个就可以

3.2 代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA==null||headB==null){
            return null;
        }
        //1、分别求两个链表的长度
        int len1=0;
        int len2=0;
        ListNode curLong=headA;//假设长的是链表A
        ListNode curShort=headB;//假设短的是链表B
        while(curLong!=null){
            len1++;
            curLong=curLong.next;
        }
        while(curShort!=null){
            len2++;
            curShort=curShort.next;
        }
        //2、求差值步的len
        int len=len1-len2;
        if(len<0){//差值为负,说明长的是B
            curLong=headB;
            curShort=headA;
            len=len2-len1;
        }else{//差值为正,说明长的就是A
            curLong=headA;
            curShort=headB;
        }
        //3、长链表先走len步,这是个差值步,走了之后再一起走
        while(len>0){
            curLong=curLong.next;
            len--;
        }
        //4、一起走,直到相遇
        while(curLong!=curShort){
            curLong=curLong.next;
            curShort=curShort.next;
        }
        return curLong;//return curShort也行
    }
}

4. LeetCode 142.环形链表II

4.1 思路

  1. 这题其实有两问,一问判断是否有环,一问是找到环的入口
  2. 判断是否有环:快慢指针,相遇说明有环。怎么想到呢?假设没环是一条直线,这时快慢指针不可能相遇,这时想为什么快慢指针就会相遇呢?就不会一直错过吗?快指针每次走两步,慢指针每次走一步,肯定是快指针先入环然后才是慢指针,然后入环后就相当于快指针在追慢指针,然后速度差为1,那么快指针就相对于慢指针移动来说每次就移动一个位置,就相当于在一个节点一个节点的在靠近慢指针,所以一定会在环里相遇
  3. 如何找环入口:假设起点到环的入口距离为x,环入口到相遇点的距离为y,相遇点到环入口的距离为z。在相遇点相遇慢指针走了x+y,快指针走了x+y+n(y+z),因为快指针走了n(n>=1)圈,因为快指针速度是慢指针的2倍,因此等式2(x+y)=x+y+n(y+z),解得x=n(y+z)-y,如果n=1,则x=z

4.2 代码

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {// 有环
                ListNode index1 = fast;
                ListNode index2 = head;
                // 两个指针,从头结点和相遇结点,各走一步,直到相遇,相遇点即为环入口
                while (index1 != index2) {
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index1;
            }
        }
        return null;
    }
}
相关文章
|
18天前
【力扣】-- 移除链表元素
【力扣】-- 移除链表元素
31 1
|
22天前
|
算法
❤️算法笔记❤️-(每日一刷-160、相交链表)
❤️算法笔记❤️-(每日一刷-160、相交链表)
16 1
|
25天前
LeetCode第二十四题(两两交换链表中的节点)
这篇文章介绍了LeetCode第24题的解法,即如何通过使用三个指针(preNode, curNode, curNextNode)来两两交换链表中的节点,并提供了详细的代码实现。
14 0
LeetCode第二十四题(两两交换链表中的节点)
|
25天前
|
索引
力扣(LeetCode)数据结构练习题(3)------链表
力扣(LeetCode)数据结构练习题(3)------链表
65 0
|
2月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
3月前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
52 6
|
3月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
106 2
|
4天前
|
机器学习/深度学习 人工智能 自然语言处理
280页PDF,全方位评估OpenAI o1,Leetcode刷题准确率竟这么高
【10月更文挑战第24天】近年来,OpenAI的o1模型在大型语言模型(LLMs)中脱颖而出,展现出卓越的推理能力和知识整合能力。基于Transformer架构,o1模型采用了链式思维和强化学习等先进技术,显著提升了其在编程竞赛、医学影像报告生成、数学问题解决、自然语言推理和芯片设计等领域的表现。本文将全面评估o1模型的性能及其对AI研究和应用的潜在影响。
7 1
|
2月前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
3月前
|
索引 Python
【Leetcode刷题Python】从列表list中创建一颗二叉树
本文介绍了如何使用Python递归函数从列表中创建二叉树,其中每个节点的左右子节点索引分别是当前节点索引的2倍加1和2倍加2。
53 7