链表问题集合

链表问题

1.快慢指针法:

快慢指针一般都初始化指向链表的头结点head,前进时fast在前,慢指针slow在后。fast每次前进2步,slow每次前进一步

1.判定链表中是否含有环

单链表的特点是:

只知道每个结点的下一个结点,所以一个指针的话无法判断链表中是否有环。如果链表中不含环,那么指针最终会遇到空指针null表示链表到头。

但是如果链表有环,那么指针就会陷入死循环,因为环形数组中没有null指针作为尾部节点。

最终fast指针会超slow指针一圈,和slow指针相遇,说明有环

public class Solution{
	public boolean hasCycle(ListNode head){
        ListNode fast,slow;
        fast=slow=head;
        while(fast!=null&&fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast==slow) return true;
        }
        return false;
    }
}

2.已知链表有环,返回这个环的起始位置

讲解:https://www.freesion.com/article/4203888940/

当快慢指针相遇时,让其中任一个指针重新指向头节点,然后让它俩以相同速度前进,再次相遇时所在的节点位置就是环开始的位置。
第一次相遇时,假设慢指针 slow 走了 k 步,那么快指针 fast 一定走了 2k 步,也就是说比 slow 多走了 k 步(也就是环的长度)
设相遇点距环的起点的距离为 m,那么环的起点距头结点 head 的距离为 k - m,也就是说如果从 head 前进 k - m 步就能到达环起点,巧的是,如果从相遇点继续前进 k - m 步,也恰好到达环起点。
所以,只要我们把快慢指针中的任一个重新指向 head,然后两个指针同速前进,k - m 步后就会相遇,相遇之处就是环的起点了。

public class solution{
    public ListNode detectCycle(ListNode head){
        ListNode fast , slow;
        while(fast!=null&fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
         	if(fast  == slow){
                break;
            }
        }
//之所以要在第一个循环结束之后再判断if(fast == null || fast.next == null) return null;
//是因为可能存在链表中只有一个值,那么相当于根本没有进行第一个循环
//这行就是为了处理这个特殊的可能性
//即只有一个节点
        if(fast==null||fast.next==null) return null;
        fast=head;
        while(fast!=slow){
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

3.寻找链表的中点(寻找链表中点的一个重要作用是对链表进行归并排序)

我们还可以让快指针一次前进两步,慢指针一次前进一步,当快指针到达链表尽头时,慢指针就处于链表的中间位置。
当链表的长度是奇数时,slow 恰巧停在中点位置;如果长度是偶数,slow 最终的位置是中间偏右:

class solution{
    public ListNode middleNode(ListNode head){
        ListNode fast,slow;
        fast = slow = head;
        while(slow!=null){
            if(fast.next == null){
                return slow;
            }
            if(fast.next.next == null){
                return slow.next;
            }
            slow = slow.next;
            fast = fast.next.next;
        }
        return null;
    }
}

4.寻找链表倒数第k个元素

思路还是使用快慢指针,让快指针先走 k 步,然后快慢指针开始同速前进。这样当快指针走到链表末尾 null 时,慢指针所在的位置就是倒数第 k 个链表节点(为了简化,假设 k 不会超过链表长度)

class Solution{
    public ListNode getKthFromEnd(ListNode head,int k){
        ListNode fast,slow;
        fast=slow=head;
        for(int i=0;i<k;i++){
            fast = fast.next;
        }
        while(fast!=null){
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

2.链表反转

1.递归法链表反转

链表反转解释:

https://www.cnblogs.com/keeya/p/9218352.html

https://blog.csdn.net/javageektech/article/details/105236461

时间复杂度:O(n)
空间复杂度:O(n)

public Node recursiveList(Node node){
    if(node==null||node.next==null){
        return node;
    }
    Node newNode =recursiveList(node.next);
    //将下一个结点的指针指向当前指针
    node.next.next = node;
    //切断当前指针与下一个指针的连接
    node.next = null;
 	return newNode;
}
2.遍历法链表反转

时间复杂度:O(n)
空间复杂度:O(1)

public static Node reverse(Node list){
        Node current=list, // 定义 current 为当前链表
        afterReverse=null;   // 定义 afterReverse 为转换之后的新链表,初始为 null
        // 当前链表不为空,进行反转操作
        while (current!=null){
            // 1. 保存当前节点的 next 指针指向的链表
            Node next=current.next;
            // 2. 将当前节点的 next 指针指向反转之后的新链表
            current.next=afterReverse;
            // 3. 保存当前的链表状态到新链表中
            afterReverse=current;
            // 4. 将当前节点指针后移一位,进行下一次循环
            current=next;
        }
        return afterReverse;
}
3.前N个链表反转
    /**
     *反转单链表前 n 个节点
     * @param list 为传入的单链表 , n 为要反转的前 n 个节点
     */
    public static Node next;
    public static Node reverseListN(Node list,int n){
        if (n == 1) {
            // 要进行反转链表时,先将 list 后的节点数据保存到 next 中
            next = list.next;
            return  list;
        }
 
        Node reverse = reverseListN(list.next , n-1);
        list.next.next = list;
        // 将 list.next 的指针指向没有进行反转的链表
        list.next = next ;
        return reverse;
    }
4.反转一部分链表
    /**
     *反转部分单链表
     * @param list 为传入的单链表, m 为开始反转的节点, n 为结束的反转节点
     */
    public static Node reverseBetween(Node list , int m , int n){
        if (m == 1){
            return reverseListN(list,n);
        }
        list.next = reverseBetween(list.next,m-1,n-1);
        return list;

3. 链表的插入

讲解:https://blog.csdn.net/unwrapping/article/details/108578202

1.头插法链表

    private ListNode head = new ListNode(0, "", "");
    //定义一个头结点,头结点不存放数据,只有下一个结点才会存放数据
public void headinsertlist(ListNode node){
    if(head.next==null){
        //判断是否只有一个头结点第一次插入值
        head.next = node;
        return;
    }
    else{
        //如果不是第一次插入值
        ListNode temp = head.next;
        //将head的下一个结点用temp引用
        head.next = node;
        //将head.next的节点指向新插入节点node,断掉head指向temp节点的指针
        node.next = temp;
        //将新节点的node.next指针指向temp
    }
    
}

2.尾插法链表

public void tailinsertlist(ListNode node){
    if(head.next == null){
        head.next = node;
        return;
    }
    else{
        ListNode temp = head.next;
        while(true){
            if(temp.next==null){
                break;
            }
            else temp=temp.next;
        }
        temp.next = node;
    }
}

代码示例:

import java.util.List;

public class text4 {

    class ListNode{

        int data;
        ListNode next=null;
        ListNode(int data){
            this.data = data;
        }
    }
    int total=0;
    //链表里节点个数
    ListNode head= new ListNode(0);
    public boolean HasCycle(ListNode head){
        ListNode fast,slow;
        fast=slow=head;
        while(fast!=null||fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
            if(fast==slow){
                return true;
            }
        }
        return false;
    }
    public ListNode DetectCycleReturnZero(){
        ListNode fast,slow;
        fast=slow=head;
        while(fast!=null&&fast.next!=null){
            fast=fast.next.next;
            slow = slow.next;
            if(fast == slow) break;
        }
        if(fast==null||fast.next==null) return null;
        fast = head;
        while(fast!=slow){
            fast=fast.next;
            slow = slow.next;
        }
        return slow;
    }
    public void DetectListMiddle(){
        ListNode fast,slow;
        fast=slow=head;
        while(fast!=null&&fast.next!=null){
            fast=fast.next.next;
            slow = slow.next;
        }
        System.out.println("中点位置: "+IndexCount(slow));
    }
    public void DeleteList(int num){
        if(head.next==null){
            System.out.println("链表无数据");
        }
        else{
            ListNode pre = Index((num-1));
            ListNode cur = Index(num);
            if(pre==null&&cur==null){
                System.out.println("没有该节点");
            }
            else if(cur!=null&&cur.next==null){
                pre.next=null;
            }
            else {
                pre.next=cur.next;
                cur.next = null;
            }
        }
        total--;
    }
    public void UpdataList(int num,int data){
        if(head.next==null){
            System.out.println("链表无数据");
        }
        else {
            ListNode tmp = Index(num);
            tmp.data = data;
        }
    }

    public ListNode Index(int num){
        ListNode tmp=null;
        if(total<num||num<0)return null;
        if(head.next==null){
            System.out.println("链表无数据");
        }
        else{
            tmp = head.next;
            int count = 1;
            while(count!=num){
                tmp=tmp.next;
                count++;
            }
        }
        return tmp;
    }
    public int IndexCount(ListNode node){
        if(node==null)return -1;
        ListNode tmp=null;
        int count = 1;
        if(head.next==null){
            System.out.println("链表无数据");
        }
        else{
            tmp = head.next;
            while(tmp!=node){
                tmp=tmp.next;
                count++;
            }
        }
        return count;
    }
    public ListNode ReverseListRecursive(ListNode node){
        //空间效率低于遍历法
        if(node==null||node.next==null){
            head.next=node;
            return node;
        }
        ListNode tmp = ReverseListRecursive(node.next);
        node.next.next=node;
        node.next=null;
        return tmp;

    }
    public void ReverseListTraverse(){
        ListNode cur = head.next;
        ListNode pre = null;
        while(cur!=null){
            ListNode next = cur.next;
            cur.next = pre;
            pre=cur;
            cur=next;
        }
        head.next=pre;
    }
    public void HeadAddList(ListNode node){
        if(head.next==null){
            head.next = node;
        }
        else {
            ListNode temp = head.next;
            head.next = node;
            node.next = temp;
        }
        total++;

    }
    public void TailAddList(ListNode node){
        if(head.next==null){
            head.next = node;
        }
        else{
            ListNode tmp = head.next;
            while (tmp.next != null) {
                tmp = tmp.next;
            }
            tmp.next = node;
        }
        total++;
    }
    public ListNode DetectBackwardList(int num){
        ListNode fast,slow;
        fast=slow=head;
        if(total<num||num<0) return null;
        for (int i = 0; i < num; i++) {
                fast=fast.next;
        }
        while(fast!=null){
            fast=fast.next;
            slow=slow.next;
        }
        return slow;
    }
    ListNode Rnext=null;
    //记录最后一个节点的下一个节点,用于,第一个节点指向它,保持连续,需要设置成全局变量
    public ListNode ReverseListFromZeroToNum(ListNode node,int num){
        if(num==1){
            Rnext = node.next;
            head.next = node;
            return node;
        }
        ListNode tmp = ReverseListFromZeroToNum(node.next,num-1);
        node.next.next=node;
        node.next=Rnext;
        return tmp;
    }
    public ListNode ReserveListBetween(ListNode node,int m,int n){
        if(m==1){
            return ReverseListFromZeroToNum(node,n);
        }
        node.next = ReserveListBetween(node.next,m-1,n-1);
        head.next = node;
        return node;
    }
    public ListNode ProduceNode(int data){
        return new ListNode(data);
    }
    public void PrintList(){
        if(head.next==null){
            System.out.println("kong");
        }
        else{
            ListNode tmp = head.next;
            int count = 1;
            while(tmp!=null){
                System.out.println("节点: "+count+++"    "+tmp.data);
                tmp=tmp.next;
            }
        }
    }
    public static void main(String[] args) {
        text4 t = new text4();
        t.HeadAddList(t.ProduceNode(4));
        t.HeadAddList(t.ProduceNode(45));
        t.HeadAddList(t.ProduceNode(499));
        t.TailAddList(t.ProduceNode(889));
        t.TailAddList(t.ProduceNode(524));
        t.TailAddList(t.ProduceNode(257));
        t.PrintList();
        t.DeleteList(3);
        t.PrintList();
        t.UpdataList(2,4444);
        t.PrintList();
        t.DetectListMiddle();
        System.out.println(t.IndexCount(t.DetectBackwardList(15)));
        t.ReverseListRecursive(t.head.next);
        t.PrintList();
        System.out.println("/");
        t.ReverseListTraverse();
        t.PrintList();
        System.out.println("**********");
        t.ReverseListFromZeroToNum(t.head.next,3);
        t.PrintList();
        System.out.println("-----------");
        t.ReserveListBetween(t.head.next,2,4);
        t.PrintList();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值