定义

双指针,通常指的是在遍历数组对象时,使用两个指针进行扫描。根据指针前进的方向不同分为快慢指针(方向相同)对撞指针(方向相反)。双指针利用了数组索引有序的特征从而简化某些情况下的处理。

对撞指针

对撞指针是指在有序数组中,将指向最左侧的索引定义为左指针,最右侧的索引定义为右指针,然后从两头向中间遍历。对撞指针适用于有序数组,可以考虑使用对撞指针来处理有序数组相关问题。
伪代码大致如下:

1
2
3
4
5
6
7
8
9
10
public void func(list) {
int left = 0;
int right = N - 1;

while (left <= right) {
left++;
.....
right--;
}
}

快慢指针

快慢指针也是双指针,但是两个指针从同一侧开始遍历数组,将这两个指针分别定义为快指针(fast)慢指针(slow),两个指针以不同的策略移动,一般快指针移动 2,慢指针移动 1,当两个指针的值相等(或其他特殊条件)移动停止。
伪代码大致如下:

1
2
3
4
5
6
7
8
9
10
public void func(Node node) {
Node slow = node;
Node fast = node;

while (slow.value != fast.value) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}

快慢指针的应用

26 数组元素去重

1
2
3
4
5
6
7
8
9
10
11
12
public int removeDuplicates(int[] nums) {
if (nums.length == 0) return 0;
int i = 0;
for (int j = 1; j < nums.length; j++) {
// nums[i]和nums[j]不相等时,i指针才会向前移动,且a[i...j-1]的元素都是相等的
if (nums[j] != nums[i]) {
i++;
nums[i] = nums[j];
}
}
return i + 1;
}

141 环形链表

1
2
3
4
5
6
7
8
9
10
11
12
13
public boolean hasCycle(ListNode head) {
if (head == null && head.next == null) return false;

ListNode slow = head;
ListNode fast = head;

while (slow != fast) {
slow = slow.next;
fast = fast.next.next;
}

return slow;
}

142 环形列表2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public ListNode func(ListNode head) {
ListNode slow = head;
ListNode fast = head;

while (slow != fast) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
ListNode index1 = slow;
ListNode index2 = head;
while (index1 != index2) {
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}

160 相交链表

1
2
3
4
5
6
7
8
9
10
11
12
13
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) return null;

ListNode Pa = headA;
ListNode Pb = headB;

while (Pa != Pb) {
Pa = Pa == null ? headB : Pa.next;
Pb = Pb == null ? headA : Pb.next;
}

return Pa;
}

链表二分

1
2
3
4
5
6
7
8
9
10
11
public ListNode EndOfFirstHalf(ListNode head) {

ListNode slow = head;
LsitNode fast = head;

while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}

参考

  1. 对撞指针——常用题型
  2. 算法一招鲜——双指针问题
  3. 数据结构和算法-双指针法