双指针 Two Pointers
双指针题型
典型例题
背向双指针
Example 1: 最长回文子串
/*
解题思路:中心拓展
1.遍历整个字符串
2. 以每个字符为中心向两边拓展
3. 拓展分为两种情况:
1. 回文子串长度为奇数:abcba, 以c为中心:helper(s, i, i);
2. 回文子串长度为偶数:abba, 以中间的两个b为中心: helper(s, i, i+1);
4. 记录每次发现的回文长度, 取最大值
*/
class Solution {
int left = 0;
int right = 0;
public String longestPalindrome(String s) {
for(int i = 0; i < s.length(); i++) {
helper(s, i, i); //处理长度为奇数的情况
helper(s, i, i+1); //处理长度为偶数的情况
}
return s.substring(left, right+1);
}
public void helper(String s, int left_cur, int right_cur) {
while(left_cur >= 0 && right_cur < s.length()) {
if(s.charAt(left_cur) != s.charAt(right_cur)) {
//如果不相等, 退出循环
break;
}
else {
//相等的情况下, 左指针往左一步, 右指针往右一步
left_cur--;
right_cur++;
}
}
//因为right_cur和left_cur退出循环时是不相等的,需要各回退一步,所以left_cur+1, right_cur-1
//对于aba以b为中心时的这种情况, 退出循环时: left_cur = -1, right_cur = 3
//right_cur-1 - (left_cur+1)计算回文子串的长度
if(right_cur-1 - (left_cur+1) > right - left) {
left = left_cur+1;
right = right_cur-1;
}
}
}
相向双指针
Example 2: 2 Sum
//左右两个指针
//如果array[left]+ array[right] 大于 target 则right--
//如果array[left]+ array[right] 小于 target 则left++
class Solution {
public int[] twoSum(int[] numbers, int target) {
int left = 0;
int right = numbers.length - 1;
while (left < right) {
int sum = numbers[left] + numbers[right];
if (sum == target) {
int [] myArray = {left + 1, right + 1};
return myArray;
}
if (sum < target) {
left++;
}
else {
right--;
}
}
int [] myArray = {left, right};
return myArray;
}
}
Example 2: 2 Sum - Greater than target
public class Solution {
/**
* @param nums: an array of integer
* @param target: An integer
* @return: an integer
*/
public int twoSum2(int[] nums, int target) {
if (nums.length < 2) {
return 0;
}
Arrays.sort(nums);
int left = 0;
int right = nums .length - 1;
int count = 0;
while (left < right) {
int sum = nums[left] + nums[right];
if (sum <= target) {
left++;
}
else {
count += (right - left);
right--;
}
}
return count;
}
}
Example 3: 2 Sum - Cloest to target
public class Solution {
/**
* @param nums an integer array
* @param target an integer
* @return the difference between the sum and the target
*/
public int twoSumClosest(int[] nums, int target) {
if (nums == null || nums.length < 2) {
return -1;
}
Arrays.sort(nums);
int left = 0, right = nums.length - 1;
int diff = Integer.MAX_VALUE;
while (left < right) {
if (nums[left] + nums[right] < target) {
diff = Math.min(diff, target - nums[left] - nums[right]);
left++;
} else {
diff = Math.min(diff, nums[left] + nums[right] - target);
right--;
}
}
return diff;
}
}
同向双指针
快慢指针
Example 1: Move Zeros
/*Solution: 双指针
Example:
8 7 0 0 9
初始:
R
L
8 7 0 0 9
如果 nums[right] != 0, 则num[left] = nums[right], 然后left++,right++ 直到 num[right] == 0
R R
L L
8 7 0 0 9 8 7 0 0 9
如果 num[right] == 0, 则 right++ 直到 num[right] != 0
R R
L L
8 7 0 0 9 8 7 0 0 9
如果 nums[right] != 0, 则 num[left] = nums[right]
R
L
8 7 9 0 9
因为right指针到头,所以跳出循环
然后从left指针开始往后 num[left] = 0
while (left < nums.length) {
nums[left] = 0;
left++;
}
Answer: 8 7 9 0 0
*/
class Solution {
public void moveZeroes(int[] nums) {
int left = 0;
int right = 0;
while (right < nums.length) {
if (nums[right] != 0) {
nums[left] = nums[right];
left++;
right++;
continue;
}
right++;
}
while (left < nums.length) {
nums[left] = 0;
left++;
}
}
}
Example 2: Middle of Linked List
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
/*
使用快慢指针,
慢指针每走一步,快指针走两步
*/
public class Solution {
public ListNode middleNode(ListNode head) {
if (head == null) {
return null;
}
ListNode slow = head;
ListNode fast = head;
while (fast.next != null) {
slow = slow.next;
if (fast.next.next != null) {
fast = fast.next.next;
}
else {
return slow;
}
}
return slow;
}
}