常见算法技巧之——双指针思想 (2)

​ 刚开始两个指针一前一后,判断两指针最中间的元素是否为查找的元素x,若是直接返回,如果不是且小于x,则将左指针移动到中间位置+1,即(l+r)/2 + 1,若大于x,则将右指针移动到中间位置-1。

public int BinarySearch (int[] nums, int target) { int l = 0, r = nums.length-1; while (l < r) { int mid = (l + r) / 2; if (nums[mid] == target) { return mid; } else if (nums[mid] > target) { r = mid - 1; } else { l = mid + 1; } } return -1; //表示未找到 } 2、n数之和的问题

​ 这里以leetcode上的一个两数之和的题为例为例,如果是三数之和可以转化为一个数与两数之和的和的问题。

两数之和 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。 示例: 给定 nums = [2, 7, 11, 15], target = 9 因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1] 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/two-sum

​ 先对数组排序,设置头尾两个指针,判断相加之后与目标数的大小,如果相加之后大于目标,则移动右指针,让右指针往左滑动,使得和更小,反之则让左指针向右滑动,直到等于target。

​ 但需要注意这道题给的并不一定是有序数组,所以并不能使用这个方法,但可以作为一个引例来启发我们,假设数组是有序的。

public int[] twoSum(int[] nums, int target) { int[] res = new int[2]; Arrays.sort(nums); int l = 0, r = nums.length - 1; while (l < r) { if (nums[l] + nums[r] == target) { return new int[] {l,r}; } else if (nums[l] + nums[r] < target) { l = l + 1; } else { r = r - 1; } } return new int[] {-1,-1}; } 三数之和 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。 注意:答案中不可以包含重复的三元组。 示例: 给定数组 nums = [-1, 0, 1, 2, -1, -4], 满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ] 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/3sum

​ 正如前文所说,可以将三数之和转化为两数与一个数之和,因为要三数之和为0,先给定一个数,则另外两个数之和就得等于这个数的相反数。则可以将这两个数的和转化为上述的两数之和问题。

class Solution { public List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> res = new ArrayList<>(); Arrays.sort(nums); for (int i = 0; i < nums.length; i++) { //剪枝,如果这个数和前一个数相等,那么由此得到的答案必和前面重复 if (i > 0 && nums[i] == nums[i-1]) continue; int target = -nums[i]; //b+c = target int k = nums.length-1; for (int j = i+1; j < nums.length; j++) { if (j > i+1 && nums[j] == nums[j-1]) //j > i+1 保证了j指针至少挪动了一次 continue; while (j < k && nums[j] + nums[k] > target) { k--; } if (j == k) { //j和k的指针重合后,没有一个k可以满足a+b+c=0 && j<k break; } if (nums[j] + nums[k] == target) { List<Integer> list = new ArrayList<Integer>(); list.add(nums[i]); list.add(nums[j]); list.add(nums[k]); res.add(list); } } } return res; } } 四数之和 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。 注意: 答案中不可以包含重复的四元组。 示例: 给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。 满足要求的四元组集合为: [ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2] ] 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/4sum

​ 继续类比前面的三数之和,不过是多了层循环而已,利用双循环先确定两个数,然后剩下的两个数就又变成了两数之和的问题,但这类问题因为有重复的元素所以要注意剪枝去掉重复的答案,还有就是数组必需有序。

class Solution { public List<List<Integer>> fourSum(int[] nums, int target) { List<List<Integer>> result = new ArrayList<>(); Arrays.sort(nums); for (int i = 0; i <= nums.length-4; i++) { if (i>0 && nums[i] == nums[i-1]) continue; for (int j = i+1; j <= nums.length-3; j++) { int tar = target - nums[i] - nums[j]; if (j>i+1 && nums[j] == nums[j-1]) continue; for (int l = j+1; l <= nums.length-2; l++) { if (l>j+1 && nums[l] == nums[l-1]) continue; int r = nums.length-1; while (r > l && nums[l] + nums[r] > tar) r--; if (r == l) { break; } if (nums[l] + nums[r] == tar) { List<Integer> res = new ArrayList<>(); res.add(nums[i]); res.add(nums[j]); res.add(nums[l]); res.add(nums[r]); result.add(new ArrayList<>(res)); } } } } return result; } } 3、反转数组

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwywzf.html