(1)双指针的作用:将时间复杂度由O(n^2)降为O(n)
(2)双指针的类型:快慢指针,左右指针,滑动窗口
(3)时间换空间常用双指针,位运算,空间换时间常用哈希表
(4)看见有序,要想双指针压缩,二分搜索
(4)快慢指针:删除数组元素,移动数组元素
思路:要求不适用额外数组空间,使用常数级空间并原地修改
根据题意,我们只能将原数组中符合要求的移到前面,后面的不用管
但是数组中的移动常常是隐藏的覆盖!
就是两个for循环,外层用来遍历找到要移除元素的位置,内层负责覆盖(nums[i]=nums[i+1])
看见两个for循环,我们就要警惕看看是否能用双指针来优化时间复杂度
快慢指针思路:快指针用来遍历,慢指针用来被覆盖,数组前半部分一定是我们需要的元素,所以只有在快指针指的值不等于val时,array[left]=array[right].
class Solution {
public int removeElement(int[] nums, int val) {
int fastIndex = 0;
int slowIndex;
for (slowIndex = 0; fastIndex < nums.length; fastIndex++) {
if (nums[fastIndex] != val) {
nums[slowIndex] = nums[fastIndex];
slowIndex++;
}
}
return slowIndex;
}
}
(5)左右指针:
例题:125. 验证回文串 - 力扣(LeetCode) 977. 有序数组的平方 - 力扣(LeetCode)
有序数组的平方:复杂的情况就是前面负数,后面正数
但是注意:任何情况下的平方后的最大值永远只会出现在两侧
class Solution {
public int[] sortedSquares(int[] nums) {
int n = nums.length;
int[] ans = new int[n];
for (int i = 0, j = n - 1, pos = n - 1; i <= j;) {
if (nums[i] * nums[i] > nums[j] * nums[j]) {
ans[pos] = nums[i] * nums[i];
++i;
} else {
ans[pos] = nums[j] * nums[j];
--j;
}
--pos;
}
return ans;
}
}
(6)滑动窗口
先增大right直到大于目标值,在增大left缩小区间(也可以尝试前缀和+二分查找)
class Solution {
public static int minSubArrayLen(int target, int[] nums) {
int left=0,right=0;
int result=Integer.MAX_VALUE;
int sum=0;
while(right<nums.length){//两次while循环
sum=sum+nums[right];
while(sum>=target){
result=Math.min(result,right-left+1);
sum=sum-nums[left];
left++;//先记再减后改
}
right++;
}
if(result!=Integer.MAX_VALUE){
return result;
}else{
return 0;
}
}
}