从下面三个问题综合展示和应用
快慢指针
。
快慢指针中的快慢指的是移动的步长,即每次向前移动速度的快慢。例如可以让快指针每次沿链表向前移动2,慢指针每次向前移动1次。
- 判断单链表是否为循环链表
- 在有序链表中寻找中位数
这三个分别为:
141. 环形链表
、
142. 环形链表 II
、
143. 重排链表
,三个问题我们一个一个来说,并且将其中的一道题目从朴素解法到
快慢指针
转化。
1. 141. 环形链表
https://leetcode-cn.com/problems/linked-list-cycle/
1.1. 题目描述
1.2. 解题代码
1.2.1. 基本解法
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public bool HasCycle(ListNode head) {
List<ListNode> listDicCache=new List<ListNode>();
while(head!=null)
{
if(listDicCache.Contains(head))
{
return true;
}
else
{
listDicCache.Add(head);
head=head.next;
}
}
return false;
}
}
1.2.2. 字典基本解法
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public bool HasCycle(ListNode head) {
Dictionary<ListNode,bool> dicCache=new Dictionary<ListNode, bool>();
while(head!=null)
{
if(dicCache.ContainsKey(head))
{
return true;
}
else
{
dicCache.Add(head,true);
head=head.next;
}
}
return false;
}
}
1.2.3. 快慢指针解法
假想「乌龟」和「兔子」在链表上移动,
「兔子」跑得快,「乌龟」跑得慢。
当「乌龟」和「兔子」从链表上的同一个节点开始移动时,
如果该链表中没有环,那么「兔子」将一直处于「乌龟」的前方;
如果该链表中有环,那么「兔子」会先于「乌龟」进入环,
并且一直在环内移动。
等到「乌龟」进入环时,由于「兔子」的速度快,它一定会在某个时刻与乌龟相遇,即套了「乌龟」若干圈。
我们可以根据上述思路来解决本题。
具体地,我们定义两个指针,一快一满。
慢指针每次只移动一步,而快指针每次移动两步。
初始时,慢指针在位置 head,而快指针在位置 head.next。
这样一来,如果在移动的过程中,快指针反过来追上慢指针,
就说明该链表为环形链表。否则快指针将到达链表尾部,该链表不为环形链表。
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public bool HasCycle(ListNode head) {
ListNode slowNode=head;
ListNode fastNode=head;
while(fastNode!=null&&fastNode.next!=null)
{
fastNode=fastNode.next.next;
if(slowNode==fastNode)
{
return true;
}
slowNode=slowNode.next;
}
return false;
}
}
2. 142. 环形链表 II
https://leetcode-cn.com/problems/linked-list-cycle-ii/
2.1. 题目描述
2.2. 解题代码
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode DetectCycle(ListNode head) {
ListNode slowNode=head;
ListNode preNode=head;
ListNode fastNode=head;
while(fastNode!=null&& fastNode.next!=null)
{
slowNode=slowNode.next;
fastNode=fastNode.next.next;
if(slowNode==fastNode)
{
while(preNode!=slowNode)
{
preNode=preNode.next;
slowNode=slowNode.next;
}
return preNode;
}
}
return null;
}
}
解题思路:
实在使用电脑太难绘制了 只能贴一下草稿纸
3. 143. 重排链表
https://leetcode-cn.com/problems/reorder-list/
3.1. 题目描述
2.2. 解题代码
2.2.1 List朴素解法
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int val=0, ListNode next=null) {
* this.val = val;
* this.next = next;
* }
* }
*/
public class Solution {
public void ReorderList(ListNode head) {
if (head == null) {
return;
}
List<ListNode> list=new List<ListNode>();
ListNode node = head;
while (node != null) {
list.Add(node);
node = node.next;
}
int i = 0, j = list.Count - 1;
while (i < j) {
list[i].next = list[j];
i++;
if (i == j) {
break;
}
list[j].next = list[i];
j--;
}
list[i].next = null;
}
}
2.2.2 快慢指针解法
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int val=0, ListNode next=null) {
* this.val = val;
* this.next = next;
* }
* }
*/
public class Solution {
public void ReorderList(ListNode head) {
if (head == null) {
return;
}
ListNode mid = MiddleNode(head);
ListNode l1 = head;
ListNode l2 = mid.next;
mid.next = null;
l2 = ReverseList(l2);
MergeList(l1, l2);
}
public ListNode MiddleNode(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
public ListNode ReverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}
public void MergeList(ListNode l1, ListNode l2) {
ListNode l1_tmp;
ListNode l2_tmp;
while (l1 != null && l2 != null) {
l1_tmp = l1.next;
l2_tmp = l2.next;
l1.next = l2;
l1 = l1_tmp;
l2.next = l1;
l2 = l2_tmp;
}
}
}
版权归原作者 自己的九又四分之三站台 所有, 如有侵权,请联系我们删除。