双指针算法题汇总
双指针算法题目

移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12]输出: [1,3,12,0,0]
示例 2:
输入: nums = [0]输出: [0]
提示:
-
1 <= nums.length <= 10(4) -
-2(31) <= nums[i] <= 2(31) - 1
进阶:你能尽量减少完成的操作次数吗?
Related Topics
数组
双指针
class Solution {
public void moveZeroes(int[] nums) {
int dest=-1;
int cur=0;
for(int i=0;i<nums.length;i++){
if(nums[cur]!=0){
int temp=nums[cur];
nums[cur]=nums[dest+1];
nums[dest+1]=temp;
dest++;
}
cur++;
}
}
}
覆写零
给你一个长度固定的整数数组 arr ,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。
注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。
示例 1:
输入:arr = [1,0,2,3,0,4,5,0]
输出:[1,0,0,2,3,0,0,4]
解释:调用函数后,输入的数组将被修改为:[1,0,0,2,3,0,0,4]
示例 2:
输入:arr = [1,2,3]
输出:[1,2,3]
解释:调用函数后,输入的数组将被修改为:[1,2,3]
提示:
-
1 <= arr.length <= 10(4) -
0 <= arr[i] <= 9
Related Topics
数组
双指针
class Solution {
public void duplicateZeros(int[] arr) {
int n = arr.length;
int cur = 0;
int dest = -1;
// 第一遍遍历:计算目标位置
while (cur < n) {
// 根据当前元素是否为0更新dest
if (arr[cur] == 0) {
dest += 2;
} else {
dest += 1;
}
// 当dest即将超出范围时停止
if (dest >= n - 1) {
break;
}
// 统一后移cur指针
cur++;
}
// 处理最后一个元素是0但空间不足的情况
if (dest >= n) {
arr[n - 1] = 0;
cur--;
dest = n - 2;
}
// 第二遍遍历:从后往前复制
while (cur >= 0 && dest >= 0) {
if (arr[cur] != 0) {
arr[dest] = arr[cur];
dest--;
} else {
arr[dest] = 0;
dest--;
if (dest >= 0) {
arr[dest] = 0;
dest--;
}
}
cur--;
}
}
}
快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」 定义为:
-
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
-
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
-
如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。
示例 1:
输入:n = 19
输出:true
解释:
1(2) + 9(2) = 82
8(2) + 2(2) = 68
6(2) + 8(2) = 100
1(2) + 0(2) + 0(2) = 1
示例 2:
输入:n = 2
输出:false
提示:
1 <= n <= 2(31) - 1
Related Topics
哈希表
数学
双指针
class Solution {
public int bitSum(int n){
int sum=0;
while(n!=0){
int temp=n%10;
sum+=temp*temp;
n/=10;
}
return sum;
}
public boolean isHappy(int n) {
int slow=n;
int fast=bitSum(n);
while(fast!=slow){
slow=bitSum(slow);
fast=bitSum(bitSum(fast));
}
return slow==1;
}
}
盛水最多的容器
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。

示例 1:
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例 2:
输入:height = [1,1]
输出:1
提示:
-
n == height.length -
2 <= n <= 10(5) -
0 <= height[i] <= 10(4)
Related Topics
贪心
数组
双指针
class Solution {
public int maxArea(int[] height) {
int left=0,right=height.length-1;
int ret=0;
while(left<right){
int v=Math.min(height[left],height[right])*(right-left);
ret=Math.max(ret,v);
if(height[left]<height[right]) left++;
else right--;
}
return ret;
}
}
有效三角形的个数
给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。
示例 1:
输入: nums = [2,2,3,4]
输出: 3
解释:有效的组合是:
2,3,4 (使用第一个 2)
2,3,4 (使用第二个 2)
2,2,3
示例 2:
输入: nums = [4,2,3,4]
输出: 4
提示:
-
1 <= nums.length <= 1000 -
0 <= nums[i] <= 1000
Related Topics
贪心
数组
双指针
二分查找
排序
class Solution {
public int triangleNumber(int[] nums) {
Arrays.sort(nums);
int res = 0;
for (int i = nums.length - 1; i >= 2; i--) {
int left = 0, right = i - 1;
while (left < right) {
if (nums[left] + nums[right] > nums[i]) {
res += right - left;
right--;
} else {
left++;
}
}
}
return res;
}
}
两数之和
购物车内的商品价格按照升序记录于数组 price。请在购物车中找到两个商品的价格总和刚好是 target。若存在多种情况,返回任一结果即可。
示例 1:
输入:price = [3, 9, 12, 15], target = 18
输出:[3,15] 或者 [15,3]
示例 2:
输入:price = [8, 21, 27, 34, 52, 66], target = 61
输出:[27,34] 或者 [34,27]
提示:
-
1 <= price.length <= 10^5 -
1 <= price[i] <= 10^6 -
1 <= target <= 2*10^6
class Solution {
public int[] twoSum(int[] price, int target) {
int left=0;
int right=price.length-1;
while(left<right){
int sum=price[left]+price[right];
if(sum>target) right--;
else if(sum<target) left++;
else return new int[] {price[left],price[right]};
}
//照顾编辑器
return new int[]{0};
}
}
三数之和
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。
提示:
-
3 <= nums.length <= 3000 -
-10(5) <= nums[i] <= 10(5)
Related Topics
数组
双指针
排序
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
//排序
Arrays.sort(nums);
int n = nums.length;
//利用双指针解决问题
for (int i = 0; i < n; ) {
if (nums[i] > 0) break;
int left = i + 1, right = n - 1;
int target = -nums[i];
while (left < right) {
int sum = nums[left] + nums[right];
if (sum > target) right--;
else if (sum < target) left++;
else {
res.add(new ArrayList<Integer>(Arrays.asList(nums[i], nums[left], nums[right])));
left++;
right--;
//去重
while (left < right && nums[left] == nums[left - 1]) left++;
while (left < right && nums[right] == nums[right + 1]) right--;
}
}
i++;
while (i < n && nums[i] == nums[i - 1]) i++;
}
return res;
}
}
-
可能存在的问题:
ArrayIndexOutOfBoundsException错误是由于数组中数组索引越界导致的,具体问题出在对变量i的边界判断上。错误分析:
在你的代码中,有这样一行:
while (nums[i] == nums[i - 1] && i < n) i++;这里的问题是判断条件的顺序。当
i已经等于n时,先判断nums[i] == nums[i - 1]会导致访问nums[n],而数组的最大索引是n-1,从而引发索引越界异常。正确的做法是先判断
i < n,确保索引在有效范围内,再进行元素比较,就像正确代码中那样:while (i < n && nums[i] == nums[i - 1]) i++;修正后的完整代码如下:
这个修正虽然只是调整了判断条件的顺序,但却非常关键。在处理数组索引时,始终应该先确保索引在有效范围内,再进行元素访问,这是避免数组索引越界异常的重要原则。
对于测试用例
[0,0,0],修正后的代码能够正确处理,不会再出现索引越界问题,并且能正确返回包含一个三元组[0,0,0]的结果列表。
四数之和
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
-
0 <= a, b, c, d < n -
a、b、c和d互不相同 -
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。
示例 1:
输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
示例 2:
输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]
提示:
-
1 <= nums.length <= 200 -
-10(9) <= nums[i] <= 10(9) -
-10(9) <= target <= 10(9)
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
int a = 0;
int n = nums.length;
for (a = 0; a < n - 3; ) {
int b = a + 1;
for (int i = b; i < n - 2; ) {
long t1 = (long)target -nums[a] - nums[i];//防溢出
//求和为t1
int left = i + 1;
int right = n - 1;
while (left < right) {
int sum = nums[left] + nums[right];
if (sum > t1) right--;
else if (sum < t1) left++;
else {
res.add(new ArrayList<Integer>(Arrays.asList(nums[a], nums[i], nums[left], nums[right])));
left++;
right--;
//去重1
while (left < right && nums[left] == nums[left - 1]) left++;
while (left < right && nums[right] == nums[right + 1]) right--;
}
}
//去重2
i++;
while (i < n && nums[i] == nums[i - 1]) i++;
}
//去重3
a++;
while (a < n && nums[a] == nums[a - 1]) a++;
}
return res;
}
}1
- 如果遇到:

表面有溢出,用long t1 = (long)target -nums[a] - nums[i];替换int即可解决

浙公网安备 33010602011771号