链表的相关问题及方法整理(在O(1)时间下删除节点、单链表的反转(循环法+递归法)、求倒数第K个节点(只扫描一遍)、求链表的中间节点(只扫描一遍)、判断两个链表是否相交、找到两个链表相交的第一个节点)

1.在O(1)时间下删除节点

题目:给定链表的头指针和一个节点指针,在O(1)时间删除该节点。

分析:用要删除节点的下一个节点的数据覆盖要删除节点的数据,然后删除下一个节点。此方法不能用来删除尾节点。

代码:

class Solution{
    public static void deleteNode(ListNode head, ListNode deleteNode){
        //传入的两个节点不能为null
        if(head == null || deleteNode == null){
            return;
        }
        //要删除的节点是头节点
        if(head == deleteNode){
            head = head.next;//更新头部
            deleteNode.next == null;//删除
        }else if(deleteNode.next != null){//要删除的节点不是尾节点
            deleteNode.data = deleteNode.next.data;//修改数据
            deleteNode.next = deleteNode.next.next;//删除节点
        }else{//要删除的节点是尾节点
            ListNode cur = head;
            while(cur.next != deleteNode){
                cur = cur.next;
            }
            cur.next = null; //删除
        }
    }
}

2.单链表的反转

题目:反转一个单链表。

2.1 循环法:

分析:三个临时变量pre、head、next,循环一遍链表,改变链表每个节点的指向。如下所示:

class Solution {
    public static ListNode reverseByLoop(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode pre = null;
        ListNode next = null;
        while(head != null){
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return pre;
    }
}

2.2 递归法:

用1->2->3->4->null分析如下图所示:

代码:

class Solution {
    public static ListNode reverseByRecursion(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode newhead = reverseByRecursion(head.next);
        head.next.next = head;
        head.next = null;
        return newhead;
    }
}

2.3 头插法逆置

https://blog.csdn.net/qq_43109561/article/details/88981480

3.求倒数第K个节点(要求只扫描一遍)

题目:求单链表的倒数第K个节点

分析:设置快、慢指针,快指针先走K步,接着快、慢指针同时走,当快指针走到末尾时,慢指针刚好走到了倒数第K个节点。

代码:

class Solution {
    public static ListNode searchKNode(ListNode head,int K) {
        if(k<0){
            return null;
        }
        ListNode slowNode = head;
        ListNode fastNode = head;
        //快指针先走K步
        int i=0;
        for(; i<K && fastNode != null; i++){
            fastNode = fastNode.next;
        }
        //长度问题
        if(i != K){
            return null;
        }
        //快、慢指针同时走
        while(fastNode != null){
            slowNode = slowNode.next;
            fastNode = fastNode.next;
        }
        return slowNode;
    }
}

4.求链表的中间节点(只扫描一遍)

题目:返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

分析:设置快、慢指针,慢指针每次走一步,快指针每次走两步,当快指针为null或者快指针的下一个节点为null时停止,返回慢指针的节点。

代码:

class Solution {
    public ListNode middleNode(ListNode head) {
        ListNode slowNode = head;
        ListNode fastNode = head;
        while(fastNode != null && fastNode.next != null){
            slowNode = slowNode.next;
            fastNode = fastNode.next.next;
        }
        return slowNode;
    }
   
}

5.判断单链表中是否存在环

https://blog.csdn.net/qq_43109561/article/details/89072424

6.找出链表入环的第一个节点

https://blog.csdn.net/qq_43109561/article/details/89072424

7.判断两个链表是否相交

题目:判断两个单链表是否相交(链表无环)。

分析:相交链表的最后节点一定是公共的,只需要找到两个链表的最后一个节点比较即可。

代码:

class Solution {
    public static boolean isIntersect(ListNode headA, ListNode headB) {
        if(headA == null || headB == null){
            return false;
        }
        ListNode curA = headA;
        ListNode curB = headB;
        while(curA.next != null){
            curA = curA.next;
        }
        while(curB.next != null){
            curB = curB.next;
        }
        return curA == curB;
    }
}

8.找到两个链表相交的第一个节点

题目:找到两个链表相交的第一个节点。(链表无环)

分析:采用对齐思想,先计算出两个链表的长度,指针cur1、cur2分别指向较长的链表头部、短的链表头部,cur1先走Math.abs(lenA-lenB)步,此时抹掉了两个链表的长度差,再同时遍历两个链表,遇到相同的节点返回。

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA == null || headB == null){
            return null;
        }
        int lenA = getLength(headA);
        int lenB = getLength(headB);
        int d = Math.abs(lenA-lenB);
        ListNode cur1;//长的链表
        ListNode cur2;
        if(lenA >= lenB){
            cur1 = headA;
            cur2 = headB;
        }else{
            cur1 = headB;
            cur2 = headA;
        }
        for(int i=0; i<d; i++){
            cur1 = cur1.next;
        }
        while(cur1 != cur2){
            cur1 = cur1.next;
            cur2 = cur2.next;
        }
        return cur1;
    }
    private int getLength(ListNode head){
        ListNode cur = head;
        int count = 0;
        while(cur != null){
            count++;
            cur = cur.next;
        }
        return count;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_43109561/article/details/89150936