224.两两交换链表中的节点|19.删除链表的倒数第N个结点|面试题 02.07. 链表相交|142. 环形链表 II||【算法学习笔记】

324 阅读4分钟

“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情

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

要求是给一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。

🍅 虚拟头结点解法,即使用一个dummyhead,方便对后面元素进行交换操作

💡要注意操作终止的条件需考虑奇数和偶数两种条件,还有就是在操作指针转向后要注意指针丢失的情况,所以本题使用temp和temp1两个临时指针记录链表里的元素。

class Solution {
    public ListNode swapPairs(ListNode head) {
    ListNode dummy=new ListNode(0);
    dummy.next=head;
    ListNode curr=dummy;      //创建虚拟头结点
    while(curr.next != null&&curr.next.next != null){
        ListNode temp=curr.next;                //记录元素位置
        ListNode temp1=curr.next.next.next;     //记录元素位置
        //对curr后面3个元素就行交换操作
        curr.next=temp.next;
        curr.next.next=temp;
        temp.next=temp1;
        //curr向后移动两位
        curr=curr.next.next;
    }
    //因为curr指向操作元素的前一位,所以返回它的next
    return dummy.next;
    }
}

🍅递归解法 ,即通过重复调用函数得出结果,实现过程是通过改变head的位置,传入不同的head完成递归操作

// 递归版本
public ListNode swapPairs(ListNode head) {
    // 如果当前结点为null或当前结点下一个结点为null
    // 则递归终止
    if (head == null || head.next == null)
        return head;

    // subResult是head.next.next之后的结点两两交换后的头结点
    ListNode subResult = swapPairs(head.next.next);
    ListNode headNext = head.next;
    headNext.next = head;
    head.next = subResult;
    return headNext;
}

看不懂递归可以看这个大佬做的的动画演示,这题的递归是学习他的leetcode.cn/problems/sw…

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

要求是给一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点

🍅 虚拟头结点解法,即使用一个dummyhead,方便对后面元素进行交换操作

💡要注意的是返回的不能是head,而应该是虚拟头结点的next。

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
    ListNode dummy = new ListNode(0,head);
    ListNode curr = dummy;    //curr指针记录操作位置
    int length = 0;
    //定义temp指针遍历链表,得到链表长度
    ListNode temp = head;
    while(temp != null) {
        length++;
        temp = temp.next;
    }
    //将curr遍历到要删除元素的前一个位置
    for(int i = n; i < length;i++) {
        curr = curr.next;
    }
    curr.next = curr.next.next;  //删除操作
    return dummy.next;
    }
}

面试题 02.07. 链表相交

要求是给一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点

🍅 双指针解法优化版,即使用两个头指针,每个指针遍历完自己的链表后去遍历另一个链表直到找到后面结点都一样的位置

💡要注意看清楚题目的要求,要求返回的是指针指向两个链表后面结点都一样的位置,和双指针解法一样,都是要让短链表起始的指针对齐长链表后面那块指针,也就是对齐,因为只有这样才能找到题目条件的位置。还有当curA=curB=null说明没有找到符合条件的位置,会退出循环最后返回curA即可。

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    ListNode curA=headA;         //记录a链表的头指针
    ListNode curB=headB;         //记录b链表的头指针
    while(curA!=curB){
        curA=(curA!=null ?curA.next:headB);     //遍历a链表,遍历完转到b
        curB=(curB!=null ?curB.next:headA);     //遍历b链表,遍历完转到a
    }
    return curA;      //这时curA=curB,返回哪个都可以
}
}

看不懂可以参考这位大佬的解答,这题是学习他的 leetcode.cn/problems/in…

142. 环形链表 II

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

🍅 双指针解法,即使用两个快慢指针,通过快慢指针的遍历找到环的入口处。

💡这道题的难点是判断是否有环和找到环的入口位置,需理解的是如果有环在环中快慢指针是一定会相遇的,这时候快指针一直循环,然后指向头结点的指针往后走就可以找到环的入口位置。

public class Solution {
    public ListNode detectCycle(ListNode head) {
    ListNode slow = head;   //慢指针
    ListNode fast = head;   //快指针
    while(fast != null && fast.next != null) {     //判断是否有环
        slow = slow.next;         //慢指针+1
        fast = fast.next.next;    //快指针+2
        if (slow == fast) {         //当快慢指针相遇即存在环
            ListNode index1 = fast;       //记录快指针位置
            ListNode index2 = head;       //记录头结点位置
            //通过循环找到环的入口处
            while (index1!=index2) {
                index2 = index2.next;
                index1 = index1.next;
            }
            return index1;
        }
    }
    return null;        //没有环返回null
    }
}