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

今日主要题目

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

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

面试题 02.07. 链表相交

142.环形链表II

主要学习网址

代码随想录

做题思路与具体代码

题目一:24. 两两交换链表中的节点

做题思路

本题思路采用虚拟头结点和移动指针

背景是交换,那肯定移动指针要在需要交换的节点前面

所以移动指针循环的条件是下一个且下一个的下一个不为空

然后每次就将下一个和下一个的下一个的位置对调,指针方向改变,这里需要用两个个临时指针来存储第一个和第三个节点的位置,(看代码更清晰)

假如是奇数指针这种方法也是可行,因为我存了第三个节点的位置,就是我在调换的时候仍能保持第三个节点在链表中的第三个位置

具体代码
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
        // 初始化虚拟头结点放在头结点前面
        ListNode dummy=new ListNode(-1,head);
        // 初始化移动指针指向虚拟头结点
        ListNode cur=dummy;
        // 两个结束条件,因为cur要在移动的两个元素之前,所以分别是偶数时的cur.next!=null
        // 还有奇数时的cur.next.next!=null
        // 注意先后顺序,因为cur.next如果为null,那么cur.next.next会报空指针异常,所以要注意先后顺序
        while(cur.next!=null&&cur.next.next!=null)
        {
            //建议画图
            //先存储1和3位置为临时值
            ListNode temp1=cur.next;
            ListNode temp2=cur.next.next.next;
            //移动指针所在位置指向2
            cur.next=cur.next.next;
            //2指向1
            cur.next.next=temp1;
            //1指向3
            temp1.next=temp2;
            //移动指针向前一次性走两格
            cur=cur.next.next;
        }
        //返回虚拟头结点的下一位置也就是整个链表
        return dummy.next;
    }
}

题目二:19.删除链表的倒数第N个节点

本题思路

删除,那仍然是要到被删除节点的前一位,采用虚拟头结点+双指针的方法

初始化快慢指针(或者可以说先后指针),两个指针之间间距N个位置,同时移动,直到快指针移动到空,慢指针所在的位置就是要删除元素的前一个位置,然后进行删除

具体代码
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    //虚拟头结点+双指针
    public ListNode removeNthFromEnd(ListNode head, int n) {
    //   初始化虚拟头结点
    ListNode dummy=new ListNode(-1,head);
    //   初始化快慢指针
    ListNode fast=dummy;
    ListNode slow=dummy;
    //快指针先走n+1步,记住此时快指针不能走到边缘
    //慢指针保持不变
    for(int i=0;i<=n;i++){
        fast=fast.next;
    }
    //快慢指针同时移动,直到快指针指向null
    while(fast!=null){
         fast=fast.next;
         slow=slow.next;
    }
    //此时慢指针所在位置就是我我们要删除的元素的前一位,进行删除
    slow.next=slow.next.next;
    //返回整个列表
    return dummy.next;
    }
}

题目三:面试题 02.07. 链表相交

本题思路

本题采用双指针方法

1.首先初始化两个移动指针算出两个链表的长度

2.将两个移动指针重置

3.我们默认第一个链表更长(后面代码也是),要是比较结果是第二个链表更长的话,那就将两个链表更换,首先更换长度,再更换头指针,都要用到中间值

4.再将链表一的移动指针向前移动两个链表差值的距离,可以看看实例3来理解,相当于统一起跑点

5.此时再将两个移动指针同时走直到相遇,中途没走一次比较一次,直到两者其中之一为空(同一起跑点其实也相当于两个移动指针后面能走的距离是一样的)

6.直接比较指针所在的节点,不能比较值,值相等不一定是同一节点

具体代码
/**
 * 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) {
    // 初始化两个链表的移动指针分别指向两个链表的头部
    ListNode curA=headA;
    ListNode curB=headB;
    //  得到每个链表的长度
    int lenA=0;
    while(curA!=null){
         curA=curA.next;
         lenA++;
    }
    int lenB=0;
    while(curB!=null){
         curB=curB.next;
         lenB++;
    }
    //回归初始位置
    curA=headA;
    curB=headB;
    //判断两个长度谁长,要是B长的话,需要A和B互换
    if(lenB>lenA){
    //  长度互换
      int temp1=lenA;
      lenA=lenB;
      lenB=temp1;
    //头指针互换,相当于换链表
      ListNode temp2=curA;
      curA=curB;
      curB=temp2;

    }
    //长度的差值
    int len=lenA-lenB;
    //需要将A向前移动差值的距离,可以看看实例3来理解,相当于统一起跑点
    while(len-->0){
        curA=curA.next;
    }
    //两者不断往前走
    while(curA!=null&&curB!=null){
        if(curA==curB){
            return curA;
        }
        //不一样就继续前进
        curA=curA.next;
        curB=curB.next;
    }
    return null;
}
}

题目四:142.环形链表II

本题思路

本题采用快慢指针的思路

简单思路(经典题):快指针每次走两步,慢指针每次走一步,那么两个指针肯定会遇到,遇到后找到交点,根据数学公式,在交点处放一个指针,和头指针同时走,遇到的点就是环的入口,再返回这个点作为结果

数学公式(不作过多讲解,贴图)

图片来源:代码随想录

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

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

具体代码
/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    //快慢指针思路
    public ListNode detectCycle(ListNode head) {
        //初始化快慢指针分别从开头开始
        //因为是寻找元素,所以在该元素位置上就行,不需要在前一位,也就不需要虚拟头结点这类
        ListNode fast=head;
        ListNode slow=head;
        //快指针走两步,慢指针走一步,直到相遇,找到相遇的点
        //循环条件是当前快指针的位置不为空且快指针的下一节点不为空
        while(fast!=null&&fast.next!=null){
        //快指针走两步,慢指针走一步,直到相遇,找到相遇的点
        fast=fast.next.next;
        slow=slow.next;
        if(fast==slow){
            //当前位置指针与头指针同时走相遇的点就是环的头
            while(fast!=head){
                fast=fast.next;
                head=head.next;
            }
            return head;
        }
        }
        return null;
    }
}

你可能感兴趣的:(链表,数据结构)