要想用好双指针技术还是挺难的,尤其是快慢指针,所以单独开一篇文章
一、数组中使用双指针
(1)一个升序数字型的一维数组,给定一个目标值,找出数组中两个位置,这两个位置元素的和等于目标值。
Two Sum II - Input array is sorted
思路:采用从两端都中间移动的双指针技术。两指针元素的和大于目标值,右指针向前移,如果两指针元素的和小于目标值,左指针后移,直到相等。
class Solution {
public int[] twoSum(int[] numbers, int target) {
int left = 0;
int right = numbers.length - 1;
while (left < right) {
if (numbers[left] + numbers[right] > target) {
right--;
} else if (numbers[left] + numbers[right] < target) {
left++;
} else {
return new int[]{left + 1, right + 1};
}
}
return new int[]{0, 0};
}
}
(2)从一个数组中,移除所有指定的值,返回新数组长度,采用in-place 就地原则
思路:快指针用于遍历数组,慢指针指向下一个元素要放的位置
class Solution {
public int removeElement(int[] nums, int val) {
int k = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] != val) {
nums[k] = nums[i];
k++;
}
}
return k;
}
}
(3)从一个数组中找到一个最短的连续子数组,这个子数组的和大于或者等于目标值,返回子数组的大小。
思路:这道题还是有些难度的,一般一个数组得到一个子数组的问题,都可以使用快慢指针的,快指针i用于遍历数组,慢指针j指向找到的满足条件的子数组的起始位置,也就是说i-j,就是子数组的长度。
class Solution {
public int minSubArrayLen(int s, int[] nums) {
if (nums == null || nums.length == 0) return 0;
int i = 0, j = 0, min = Integer.MAX_VALUE;
int sum = 0;
while (i < nums.length) {
sum += nums[i++];
while (sum >= s) {
min = Math.min(min, i-j);
sum -= nums[j++];
}
}
return min == Integer.MAX_VALUE ? 0 : min;
}
}
(4) 接雨水问题(Trapping Rain Water)
二、在链表List中也常用two-pointer technique,快慢指针技术
(1)判断一个链表中是否有环
思路:快慢指针,快指针走两步,慢指针走一步,两指针迟早相遇。
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) return false;
ListNode faster = head;
ListNode slower = head;
while (faster.next != null && faster.next.next != null) {
faster = faster.next.next;
slower = slower.next;
if (faster == slower) {
return true;
}
}
return false;
}
}
(2)判断一个list是否有环,如果有的话,返回环的入口节点。
思路:首先用快慢指针判断list是否有环,如果有的话,根据“从头节点到环入口节点的距离=快慢指针相遇节点到环入口节点的距离”(证明请看:判断单链表中是否有环,找到环的入口节点)公理,找到环入口节点
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
if (head == null || head.next == null) return null;
ListNode faster = head;
ListNode slower = head;
boolean find = false;
while (faster.next != null && faster.next.next != null) {
faster = faster.next.next;
slower = slower.next;
if (faster == slower) {
find = true;
break;
}
}
if (find) {
ListNode newSlower = head;
while (newSlower != slower) {
newSlower = newSlower.next;
slower = slower.next;
}
return newSlower;
}
return null;
}
}