兔系刷题leetcode系列之三 快慢指针

快慢指针

常见模式

跟链表相关
判断链表是否有环 等等

第一道 环形链表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X6jlNhcv-1585725826423)(442FE650C2B4416BA0F33FB51EB9427D)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GqlXR2qT-1585725826425)(8385C5AA56EB47C1A7A98404F8DE9C1A)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ELZYyOuN-1585725826430)(D8848E7863EB4436BF4C3E6B07A4A282)]

思路:

假如该链表是循环链表,那我们可以定义两个指针,一个每次向前移动两个节点,另一个每次向前移动一个节点。这就和田径比赛是一样的,假如这两个运动员跑的是直道,那快的运动员和慢的运动员在起点位于同一位置,但快的运动员必将先到达终点,期间这两个运动员不会相遇。而如果绕圈跑的话(假设没有米数限制),跑的快的运动员在超过跑的慢的运动员一圈的时候,他们将会相遇,此刻就是循环链表。

与龟兔赛跑的不同:

关于快慢指针中两个指针的速度问题: 和龟兔赛跑问题不同的是,龟兔赛跑是一个连续性的问题,无论二者的速度差是多少,可以这样假设:假设赛道长度为s,v_f表示速度快的值,v_s表示速度慢的值,(假设二者初始位置相同),那么可以求出来:(v_f-v_s)t=s;这样求出来的t,是二者第一次相遇的时间; 本题不同的是:对于链表来说是一个离散的值,我们假设环内共有n个节点,同样假设快指针与慢指针分别是v_f,v_s;如果想要相遇(假设初始位置相同),同样有(v_f-v_s)k = n; ——这个时候 v_f,v_s 为正整数,k为循环次数,n为节点数目; k = n/(v_f-v_s)如果想要k为整数,那么可以看到二者的速度差是有要求的,必须能够被n整除;注意:这样求得是第一次相遇,也有可能v_f-v_s是n的整数倍;

代码:

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    
    
    public boolean hasCycle(ListNode head) {
    
    
        if(head==null)
		    	return false;
	        ListNode p=head;
	        ListNode q=head;
	        while(p!=null&&q!=null)
	        {
    
    
	        	p=p.next;
                if(q.next==null)
                    return false;
	        	q=q.next.next;
	        	if(p.equals(q))
	        	{
    
    
	        		return true;
	        	}
	        }
	        return false;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OMCxUWha-1585725826431)(8477DAC96AF84806B94FD8D199D1D005)]

第二道 环形链表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O0y7qasT-1585725826433)(3B0D18ED5FBE47308DF9A3C13A55D142)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AnLiVQsb-1585725826435)(E3ADA207DBD34E3095307D12A6F909AE)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8PR3Scmn-1585725826436)(E9EBF2CBBF19492FAEC3E23519308EF6)]

思路:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tROPtcOi-1585725826438)(9806B5338D2C46698C0471924351B9CD)]
如图设非环形有a个节点
设环形有b个节点
第一次相遇时

fast走的节点数=2*slow走的节点数\\

fast走的节点数-slow走的节点数=nb(多走了n圈)
第一次相遇时slow走的节点数为nb
一个节点走a+nb步一定会在入口处
slow在第一次相遇后再走a步即可
可以第一次相遇后,设置一个指针从头开始,以slow的速度,两者相遇时即为入口

代码:

public class Solution {
    
    
    public ListNode detectCycle(ListNode head) {
    
    
       if(head==null)
		    	return null;
	        ListNode p=head;
	        ListNode q=head;
            if(head.next==null)
            {
    
    
                return null;
            }
	        while(p!=null&&q!=null)
	        {
    
    
	        	p=p.next;
                if(q.next==null)
                return null;
	        	q=q.next.next;
	        	if(p.equals(q))
	        	{
    
    
	        		q=head;
	        		while(p!=null&&q!=null)
	        		{
    
    
                        if(p.equals(q))
	        			{
    
    
	        				return p;
	        			}
	        			q=q.next;
	        			p=p.next;
	        		
	        		}
	        	}
	        }
	        return null;
    }
}

第三道 链表的中间结点在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IkHYOtRQ-1585725826441)(62E78BABD53B4093A6A139F116D547F5)]

思路:

快指针一次跨两个节点;
慢指针一次跨一个节点;
快指针到结尾时,慢指针到中位。

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    
    
    public ListNode middleNode(ListNode head) {
    
    
        		ListNode fast=head;
		ListNode slow=head;
		while(true)
		{
    
    
			if(fast.next==null)
			{
    
    
				return slow;
			}
			if(fast.next.next==null)
			{
    
    
				slow=slow.next;
				return slow;
			}
			else {
    
    
				fast=fast.next.next;
				slow=slow.next;
			}
		}
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UscIrkNx-1585725826442)(158B160E1E5A4DB691DBB5D0AA6BD1A1)]

第四道 删除链表倒数第n个节点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vynUVmOn-1585725826444)(784223AA3A9D4511B33666FB30A52F12)]

思路:

快指针先行n个节点
然后快慢指针一步一个节点向下
快指针到达结尾时
慢指针到达的位置即为倒数第n个节点

代码:

public static ListNode deleteNode(ListNode head,int n) {
    
    
		ListNode p=head;
		ListNode q=head;
		for(int i=0;i<n-1;i++)
		{
    
    
			p=p.next;
		}
		while(true)
		{
    
    
			if(p.next.next==null)
			{
    
    
				q.next=q.next.next;
				return head;
			}
			p=p.next;
			q=q.next;
		}
    }

猜你喜欢

转载自blog.csdn.net/hch977/article/details/105246980
今日推荐