[Java 算法] 双指针 2
1.LCR 179. 查找总价格为目标值的两个商品

class Solution {public int[] twoSum(int[] price, int target) {int left = 0, 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};}
}
利用排好序这个方面 , 使用双指针 , 每次循环都求一次和 , 如果这个 和大于 target , 只需让 right-- ; 如果这个和小于target , 只需让 left++
2.三数之和

class Solution {public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> listall = new ArrayList<>();Arrays.sort(nums);for(int i = 0;i<nums.length;i++){if (i > 0 && nums[i] == nums[i - 1]) {continue;}int left = i+1;int right = nums.length-1;while(left<right&&left<nums.length&&right>i){int sum = nums[left] + nums[right]+nums[i];if(sum>0){right--;}else if(sum<0){left++;}else{List<Integer> list1 = new ArrayList<>();list1.add(nums[left]);list1.add(nums[right]);list1.add(nums[i]);listall.add(list1);while((left<right&&nums[right] == nums[right-1])){right--;}while((left<right&&nums[left] == nums[left+1])){left++;}right--;left++;}}}return listall;}
}
核心操作 :
- 排序 : 先对数组排序 , 方便为后续去重和双指针移动
- 固定一个元素+双指针找另外两个元素 :
- 外层循环固定第一个元素 nums[i]
- 内层用双指针(left = i+1 , right = 数组末尾)寻找另外两个数 , 使得三数之和为 0
- 去重 : 跳过重复元素 , 避免结果集中出现重复的三元组
注意 :
- 去重细节:当找到一个有效三元组后,需跳过与当前
left/right相同的元素(如nums[left] == nums[left+1]则left++),否则会产生重复结果去重后需同时移动left和right(left++且right--),因为单个移动会导致重复计算 - 不漏 : 找到一种结果之后 , 不要停止 , 接着缩小区间继续寻找
3.四数之和
class Solution {public List<List<Integer>> fourSum(int[] nums, int target) {List<List<Integer>> listAll = new ArrayList<>();Arrays.sort(nums);for (int i = 0; i < nums.length; i++) {if (i > 0 && nums[i - 1] == nums[i]) {continue;}for (int j = i + 1; j < nums.length; j++) {if (j > i+1 && nums[j - 1] == nums[j]) {continue;}int left = j + 1;int right = nums.length - 1;while (left < right && left < nums.length && right > j) {long sum = (long)nums[left] + nums[right] + nums[j] + nums[i];//防止越界if (sum > target) {right--;} else if (sum < target) {left++;} else {List<Integer> list1 = new ArrayList<>();list1.add(nums[left]);list1.add(nums[right]);list1.add(nums[i]);list1.add(nums[j]);listAll.add(list1);while ((left < right && nums[right] == nums[right - 1])) {right--;}while ((left < right && nums[left] == nums[left + 1])) {left++;}right--;left++;}}}}return listAll;}
}
核心思路 :
- 排序 : 先对数组排序 , 方便后续去重和双指针移动
- 固定两个元素 : 通过两层嵌套循环 , 固定四元组中的前两个元素 num[i] 和 num[j](i<j)
- 双指针找剩余两个元素 : 再固定前两个元素后 , 用双指针(left = j+1 , right = 数组末尾) 寻找另外两个元素 , 使得四数之和为 target
- 去重 : 跳过重复元素 , 避免结果集中出现重复的三元组
注意 :
- 不漏 : 找到一种结果之后 , 不要停止 , 接着缩小区间继续寻找
- 整数有溢出的风险改用 long 类型计算
- 去重细节:找到有效四元组后,需跳过与当前
left/right相同的元素(如nums[left] == nums[left+1]则left++),否则会产生重复结果 ; 去重后同时移动left和right,避免重复计算
