【双指针】——快慢指针

双指针分为两类:一类是“快慢指针”,一类是“左右指针”

快慢指针:主要解决链表中的问题,比如判定链表中是否包含环
左右指针:主要解决数组(或者字符串)问题,比如二分搜索

判定链表是否含有环

  • 如果链表不含环,则指针会遇到空指针null,表示链表到头了
boolean hasCycle(ListNode head){
	while(head != null){
		head = head.next;
	}
	return false;
}
  • 如果链表含有环,则会陷入死循环,因为环形链表中没有null指针作为尾部节点
    • 双指针 ,不含环,则会遇到null;含有环,则快指针会超慢指针一圈,和慢指针相遇
boolean hasCycle(ListNode head){
	ListNode fast,slow;
	//初始化快、慢指针指向头节点
	fast = slow = head;
	while(fast != null && slow != null){
		slow = slow.next;
		fast = fast.next.next;
		if(slow == fast){
			return true;
		}
	}	
	return false;
}

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

boolean hasCycle(ListNode head){
	ListNode fast,slow;
	//初始化快、慢指针指向头节点
	fast = slow = head;
	while(fast != null && slow != null){
		slow = slow.next;
		fast = fast.next.next;
		if(slow == fast){
			break;
		}
	}	
	fast = head;
	while(slow != fast){
	//相同的速度前进
		slow = slow.next;
		fast = fast.next;
	}
	//两个指针的相遇的节点就是环的起点
	return slow;
}

设相遇点距环的起点的距离为 m, 那么环的起点距头结点 head 的距离为 k -
m, 也就是说如果从 head 前进 k - m 步就能到达环起点。
巧的是, 如果从相遇点继续前进 k - m 步, 也恰好到达环起点。

所以, 只要我们把快慢指针中的任⼀个重新指向 head, 然后两个指针同速
前进, k - m 步后就会相遇, 相遇之处就是环的起点了。在这里插入图片描述
在这里插入图片描述

寻找无环单链表的中点

  • 暴力求解:先遍历一遍链表,算出链表的长度n,再遍历一遍链表,走n/2步则是链表的中点
  • 让快指针1次前进2步, 慢指针1次前进1步, 当快指针到达链表尽头时, 慢指针就处于链表的中间位置。
while (fast != null && fast.next != null) {
	fast = fast.next.next;
	slow = slow.next;
} 
// slow 就在中间位置
return slow;

寻找单链表的倒数第k个元素

让快指针先走 k 步, 然后快慢指针开始同速前进。 这样当快指针到链表末尾 null 时, 慢指针所在的位置就是倒数第 k
个链表节点

ListNode slow, fast;
slow = fast = head;
while (k-- > 0)
	fast = fast.next;
while (fast != null) {
	slow = slow.next;
	fast = fast.next;
} 
return slow;
posted @ 2021-03-08 17:18  your_棒棒糖  阅读(70)  评论(0编辑  收藏  举报