链表经典题目总结

110 阅读3分钟

前言

今天是4道链表题目,都是经典题目。 两两交换链表中的节点 删除链表的倒数第 N 个结点 面试题 02.07. 链表相交 142. 环形链表 II

两两交换链表中点节点

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

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

首先分析一下交换过程,假如有一个链表1,2,3,4。我们首先设置一个虚拟头节点0,然后让节点从0指向2,2指向1,1指向3,大概就是这么的一个过程。 这里要注意结束条件,要记得先cur.next!=null否则先判断cur.next.next!=null会报错,因为null节点没有next节点。

下面是具体代码实现:

class Solution {
    public ListNode swapPairs(ListNode head) {
        //使用虚拟头节点进行两两交换,两个节点交换一次
        ListNode headnode=new ListNode(-1);
        headnode.next=head;
        ListNode cur=headnode;
        ListNode firstNode;
        ListNode secondeNode;
        ListNode temp;//保存第三个节点
        while(cur.next!=null&&cur.next.next!=null){//如果是偶数节点是cur.next=null,奇数节点cur.next.next=null
            //记录cur的下一个节点
            temp=cur.next.next.next;//第三个节点的位置
            //节点之前两两交换。
            firstNode=cur.next;
            secondeNode=cur.next.next;
            //cur节点是0,firstnode节点是secondNode节点是2
            //需要0-2-1-3
            cur.next=secondeNode;//0到2
            secondeNode.next=firstNode;//2到1
            firstNode.next=temp;//1到3
            cur=firstNode;//将cur向前移动两个位置

            
        }

        return headnode.next;


    }
}

时间复杂度O(N),空间复杂度O(1)。

image.png

删除链表倒数第n个节点

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

进阶:你能尝试使用一趟扫描实现吗?

lic ListNode removeNthFromEnd(ListNode head, int n) {
        //删除链表的倒数第n个节点
        //两次扫描挺好想的,现在困难的是一次扫描
        //我的思路,双指针,第一个指针和第二个指针相差n个就可以了,这样就实现了一次循环找到倒数第n个节点
       
        ListNode fast=head,slow=head;
        for(int i=0;i<n;i++){
            fast=fast.next;
        }
        if(fast==null){
            return head.next;
        }
        //这样快指针比慢指针快了n个,快指针到头位置的时候慢指针就是倒数第n个指针
        while(fast.next!=null){
            slow=slow.next;
            fast=fast.next;
        }
        //现在到了第n个的位置,需要删除第n个位置指针
        if(slow.next!=null){
            slow.next=slow.next.next;
        }
        return head;



双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。

image.png

链表相交

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

链表相等的含义是两个节点相同,而不是只是值相同。我们先求链表长度,然后如果cura的长度小,将cura和curb的长度进行交换,让a节点和b节点名称进行交换,确保cura的长度更长。

然后将cura的指针移动到相关的curb长度相同的节点,然后两两节点比较,如果相同就返回,如果不相同互相移动下一个节点。

我的代码实现:

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //先求长度,
        ListNode cura=headA;
        ListNode curb=headB;
        int alength=0;
        int blegnth=0;

        while(cura!=null){
            alength++;
            cura=cura.next;
        }
          while(curb!=null){
            blegnth=blegnth+1;
            curb=curb.next;
        }
        cura=headA;
        curb=headB;
        if(alength<blegnth){
            //如果a的长度小于b的长度
            //交换长度和交换节点
            int tmp_len;
            tmp_len=alength;
            alength=blegnth;
            blegnth=tmp_len;

            //交换相关节点
            ListNode tmpNode=new ListNode(-1);
            tmpNode=cura;
            cura=curb;
           curb=tmpNode;

        }
        //
        int len_result=alength-blegnth;
          //过长的链表的进行遍历等相同长度
        while(len_result-->0){
            cura=cura.next;
        }
    

        //对比节点是否是同一个节点
        while(cura!=null){
            if(cura==curb){
                return cura;
            }

            cura=cura.next;
            curb=curb.next;


        }
        return null;
        
    }

image.png

环形链表

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

为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast=head;
        ListNode slow=head;
        while(fast!=null&&fast.next!=null){
            slow=slow.next;
            fast=fast.next.next;
            if(fast==slow){//如果相交证明有环
            ListNode index=head;
            ListNode index2=fast;//交汇点和head不断走下去一定会交汇

            while(index!=index2){
                index = index.next;
                index2 = index2.next;
            }
            return index;


            }
           

        }
         return null;
        

        
    }
}

可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。

并且如果链表中有环,设置两个指针,一个是head链表头节点,一个是相交的位置节点,遍历下去一定会相交的。

image.png