双指针算法的类型
指向两个序列
例如归并排序
指向一个序列
例如快速排序
双指针算法的用途
双指针的基本模板
举个例子:
1、给定一个字符串数组,依次输出数组中的每个字符串,str=["abc","efg","hijk"]
2、最长连续不重复子序列
在这里,j表示i左边能到达的最远的没有重复数字的距离,并且随着i++,j也是++,绝对不可能--
双指针技巧总结
快慢指针
--主要解决链表中的问题,例如典型的判定链表中是否包含环
快慢指针一般都初始化指向链表的头结点head,前进时快指针fast在前,慢指针slow在后,巧妙的解决链表中的一些问题
1、判定链表中是否含环
单链表的特点是每个节点只知道下⼀个节点,所以⼀个指针的话⽆法判断链表中是否含有环的。
如果链表中不含环,那么这个指针最终会遇到空指针 null 表⽰链表到头了,这还好说,可以判断该链表不含环。
但是如果链表中含有环,那么这个指针就会陷⼊死循环,因为环形数组中没有 null 指针作为尾部节点。
经典解法就是⽤两个指针,⼀个跑得快,⼀个跑得慢。如果不含有环,跑得快的那个指针最终会遇到 null,说明链表不含环;如果含有环,快指针最终会超慢指针⼀圈,和慢指针相遇,说明链表含有环。
2、已知链表中有环,返回这个环的起始位置
ListNode detectCycle(ListNode head) {
ListNode fast, slow;
fast = slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) break;
}
slow = head;
while (slow != fast) {
fast = fast.next;
slow = slow.next;
}
return slow;
}当快慢指针相遇,让其中一个指针指向头结点,然后让它们以心相通的速度前进,再次相遇时所在的节点位置就是环开始的位置
3、寻找链表中点
类似上面的思路,我们还可以让快指针⼀次前进两步,慢指针⼀次前进⼀步,当快指针到达链表尽头时,慢指针就处于链表的中间位置。
如果链表的长度为奇数,slow正好在中间的位置,如果是偶数,就在中间偏右的位置
4、寻找链表的倒数第 k 个元素
让快指针先⾛ k 步,然后快慢指针开始同速前进。这样当快指针⾛到链表末尾 null 时,慢指针所在的位置就是倒数第 k个链表节点
左右指针
--主要解决数组(或字符串)中的问题,例如二分查找
1、二分查找
int binarySearch(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while(left <= right) {
int mid = (right + left) / 2;
if(nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid - 1;
}
return -1;
}查找左边界
l := 0
r := len(nums) - 1
for l < r {
mid := l + r >> 1
if nums[mid] >= target {
r = mid
}else {
l = mid + 1
}
}
return r查找右边界
l = 0
r = len(nums) - 1
for l < r {
mid := l + r + 1 >> 1
if nums[mid] <= target {
l = mid
}else {
r = mid - 1
}
}
return r2、反转数组
void reverse(int[] nums) {
int left = 0;
int right = nums.length - 1;
while (left < right) {
// swap(nums[left], nums[right])
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
left++; right--;
}
}3、滑动窗口算法
这里有一个滑动窗口的基本框架,但凡用到滑动窗口的问题都可以用这个框架进行改编
/* 滑动窗⼝算法框架 */
void slidingWindow(string s, string t) {
unordered_map<char, int> need, window;
for (char c : t) need[c]++;
int left = 0, right = 0;
int valid = 0;
while (right < s.size()) {
// c 是将移⼊窗⼝的字符
char c = s[right];
// 右移窗⼝
right++;
// 进⾏窗⼝内数据的⼀系列更新
...
/*** debug 输出的位置 ***/
printf("window: [%d, %d)\n", left, right);
/********************/
// 判断左侧窗⼝是否要收缩
while (window needs shrink) {
// d 是将移出窗⼝的字符
char d = s[left];
// 左移窗⼝
left++;
// 进⾏窗⼝内数据的⼀系列更新
...
}
}
}
京公网安备 11010502036488号