双指针算法模板
- 双指针
- 快、慢指针
- 左、右指针
1.快、慢指针常用算法
快慢指针一般会初始化指向头节点head,前进时,快指针fast在前,慢指针slow在后。
①判断链表是否有环
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;
}
②返回环的起始位置
ListNode detectCycle(ListNode head){
ListNode fast,slow;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){
break;
}
}
// 上面的代码类似hasCycle函数
// 先把一个指针重新指向head
slow = head;
while(fast != slow){
// 两个指针以相同的速度前进
slow = slow.next;
fast = fast.next;
}
// 两个指针相遇的那个节点就是环的起点
return slow;
}
③寻找无环链表的中点
让快指针一次前进两步,慢指针一次前进一步,当快指针到达链表尽头时,慢指针就处于链表的中间位置。
while(fast != null && fast != null){
fast = fast.next.next;
slow = slow.next;
}
// slow就是中间位置
return slow;
当链表的长度是奇数时,slow停在中间位置,否则slow停在中间偏右。
寻找链表的中间位置作用:实现对链表进行归并排序。
④寻找单链表的倒数第k个元素
先让快指针走k步,然后快慢指针开始同时前进,当快指针到达末尾时,慢指针所处的位置是倒数第k个链表节点。
ListNode slow,fast;
slow = fast = head;
while(k-- > 0){
fast = fast.next;
}
while(fast != null){
slow = slow.next;
fast = fast.next;
}
return slow;
2.左右指针常用算法
①二分搜索框架
int binarySearch(int[] nums,int target){
int left = 0,right = ...;
while(...){
int mid = left + (right - left)/2;
if(nums[mid] < target){
...
}else if(nums[mid] > target){
left = ...;
}else if(nums[mid] < target){
right = ...;
}
}
return ...;
}
注:代码中left + (right - left)/2和(left + right)/2结果是相同的,我们之所以使用left + (right - left)/2是因为当left和right太大时,防止溢出。
②最基本的二分搜索算法
int binary_search(int[] nums,int target){
int left = 0,right = nums.length - 1;
while(left <= right){
int mid = left + (right - left)/2;
if(nums[mid] < target){
left = mid + 1;
}else if(nums[mid] > targrt){
right = mid - 1;
}else if(nums[mid] == target){
//直接返回
return mid;
}
}
//直接返回
return -1;
}
③寻找左侧边界的二分搜索算法
int left_bound(int[] nums,int target){
int left = 0,right = nums.length - 1;
while(left <= right){
int mid = left + (right - left)/2;
if(nums[mid] < target){
left = mid + 1;
}else if(nums[mid] > target){
right = mid - 1;
}else if(nums[mid] == target){
// 收缩右边界,锁定左侧边界
right = mid - 1;
}
// 检查left越界的情况
if(left >= nums.length || nums[left] != target){
return -1;
}
return left;
}
}
④寻找右边界的二分搜索算法
int right_bound(int[] nums,int target){
int left = 0,right = nums.length - 1;
while(left <= right){
int mid = left + (right - left)/2;
if(nums[mid] < target){
left = mid + 1;
}else if(nums[mid] > target){
right = mid - 1;
}else if(nums[mid] == target){
// 收缩左边界,锁定右侧边界
left = mid + 1;
}
}
// 检查right越界的情况
if(right < 0 || nums[right] != target){
return -1;
}
return right;
}