查找问题
704-二分查找

// 盲写通过public int search(int[] nums, int target) {int left = 0, right = nums.length - 1;while (left <= right) {int mid = left + (right - left) / 2;if (nums[mid] == target) {return mid;} else if (nums[mid] > target) {right = mid - 1;} else if (nums[mid] < target) {left = mid + 1;}}return -1;}
215-数组中的第 K 个最大元素

代码:
public int findKthLargest(int[] nums, int k) {int len = nums.length;int idx = len - k;return quicksort(nums, 0, len - 1, idx);}public int quicksort(int[] nums, int start, int end, int idx) {if (start > end) {return -1;}int pivotIdx = partition(nums, start, end, idx);if (pivotIdx == idx) {return nums[pivotIdx];} else if (pivotIdx < idx) { // 基准pivotIdx小于idx时,说明预期结果在idx右侧,则对右侧进行递归遍历return quicksort(nums, pivotIdx + 1, end, idx);} else {return quicksort(nums, start, pivotIdx - 1, idx);}}public int partition(int[] nums, int start, int end, int idx) {int pviot = nums[start];int left = start, right = end;// 左右开始扫描,将基准值pviot移动到合适的位置while (left != right) {while (left < right && nums[right] >= pviot) {right--;}while (left < right && nums[left] <= pviot) {left++;}// 交换 left 和 right 的值if (left < right) {int tmp = nums[left];nums[left] = nums[right];nums[right] = tmp;}}//一次排序结束后,left和right抵达重合点,将基准值移动到这里int p = nums[start];nums[start] = nums[left];nums[left] = p;return left;}
33-搜索旋转排序数组

代码:
public int search1(int[] nums, int target) {Map<Integer, Integer> idxMap = new HashMap<>();for (int i = 0; i< nums.length; i++) {idxMap.put(nums[i], i);}if (idxMap.containsKey(target)) {return idxMap.get(target);}return -1;}public int search2(int[] nums, int target) {for (int i = 0; i < nums.length; i++) {if (nums[i] == target) {return i;}}return -1;}public int search(int[] nums, int target) {if (nums.length == 0) {return -1;}if (nums.length == 1) {return nums[0] == target ? 0 : -1;}int left = 0, right = nums.length -1;int mid = 0;while (left <= right) {mid = (left + right) / 2;if (nums[mid] == target) {return mid;}// 总有一半数据是有序的if (nums[left] <= nums[mid]) {//左边数据有序则查找左边数据if (target >= nums[left] && target < nums[mid]){right = mid - 1;} else {left = mid + 1;}} else {// 右边数据有序则查找右边数据if (target > nums[mid] && target <= nums[right]) {left = mid + 1;} else {right = mid -1;}}}return -1;}
81-搜索旋转排序数组II

代码:
public boolean search(int[] nums, int target) {if (nums.length == 0) {return false;}if (nums.length == 1) {return nums[0] == target ? true : false;}int left = 0, right = nums.length -1;int mid = 0;while (left <= right) {mid = (left + right) / 2;if (nums[mid] == target) {return true;}// 如果数组中元素有重复的,那旋转后可能无法判断哪一半有序if (nums[left] == nums[mid] ){left++;} else if (nums[mid] == nums[right]) {right--;} else{if (nums[left] <= nums[mid]) {//左边数据有序则查找左边数据if (target >= nums[left] && target < nums[mid]){right = mid - 1;} else {left = mid + 1;}} else {// 右边数据有序则查找右边数据if (target > nums[mid] && target <= nums[right]) {left = mid + 1;} else {right = mid -1;}}}}return false;}
34-排序数组查元素第一个/最后一个idx(二分)

代码:
public int[] searchRange(int[] nums, int target) {if (nums.length == 0) {return new int[]{-1, -1};}int firstPosition = findFirstPosition(nums, target);if (firstPosition == -1 ) {return new int[]{-1, -1};}int lastPosition = findLastPosition(nums, target);return new int[]{firstPosition, lastPosition};}/*** 找到第一次出现的位置* @param nums* @param target* @return*/public int findFirstPosition(int[] nums, int target) {int left = 0, right = nums.length - 1;while (left < right) {int mid = (left + right) / 2;if (nums[mid] < target) {left = mid + 1;} if (nums[mid] == target) {right = mid;} else if (nums[mid] > target) {right = mid - 1;}}if (nums[left] == target) {return left;}return -1;}/*** 向右查找最后一次出现的位置* @param nums* @param target* @return*/public int findLastPosition(int[] nums, int target) {int left = 0, right = nums.length - 1;while (left < right) {// 比如:left=4,right=5,此时 mid = 4,nums[mid]=target,left=mid 操作一直是 left=4,right=5,进入死循环int mid = (left + right + 1) / 2;if (nums[mid] < target) {left = mid + 1;} if (nums[mid] == target) {left = mid;} else if (nums[mid] > target) {right = mid - 1;}}return left;}
35-搜索插入位置

题意分析:
- 查找和插入两个条件,根据二分查找判断数组中是否存在target元素,存在直接返回,不存在则返回元素插入位置(保证数组整体有序)
解题思路:
- 二分查找,判断条件记录什么时候更新索引位置。
注意点:
- 插入时需要记录元素要插入的位置。
扩展:
代码:
public int searchInsert(int[] nums, int target) {return binarySearch(nums, target);}public int binarySearch(int[] nums, int target) {int n = nums.length;int left = 0, right = n - 1;int ans = n;while (left <= right) {int mid = left + (right - left) / 2;System.out.println("mid = " + mid);if (nums[mid] == target) {return mid;} else if (nums[mid] > target) {ans = mid;right = mid - 1;} else if (nums[mid] < target){left = mid + 1;}}return ans;}
去重问题
26-删除有序数组中的重复项

代码:
public int removeDuplicates(int[] nums) {if (nums.length == 0) {return nums.length;}int slow = 1, fast = 1;while (fast < nums.length){if (nums[fast] == nums[slow-1]) {fast++;} else {nums[slow++] = nums[fast++];}}return slow;}
80-删除有序数组中的重复项II

代码:
public int removeDuplicates(int[] nums) {if (nums.length == 0 || nums.length == 1) {return nums.length;}int slow = 2, fast = 2;while (fast < nums.length){if (nums[fast] == nums[slow-2]) {fast++;} else {nums[slow++] = nums[fast++];}}return slow;}
710-黑名单中的随机数

题意分析:
- [0, n-1] 中去掉一些数,访问剩下的数。
解题思路:
- 直接用集合去重。(存储 [0, n-1] 个元素,内存超出限制)
- 黑名单元素重定向。构建 [whitesize, n-1] 长度的数组(和黑名单数组元素相同),然后将黑名单的元素直接映射到这个数组。
注意点:
- 黑名单中大于 whitesize 索引的元素直接过滤,比较随机数索引不到,只需要对黑名单中小于 whitesize 的元素映射即可。
- 求解返回时,如果是黑名单中数据重定向,白名单数据直接返回,会用到 Map 的 getOrDefault() 方法。
代码:
public class RandomBlackList_710 {Set<Integer> set = new HashSet<>();Map<Integer, Integer> map = new HashMap<>();int whitesize;/*** 解题思路:* 1、构建白名单set,初始元素和黑名单一致。* 2、将黑名单中大于 whitesize 的元素从 set 移除,将小于 whitesize 的元素映射到 set 的剩余元素* @param n* @param blacklist*/public RandomBlackList_710(int n, int[] blacklist) {whitesize = n - blacklist.length;for (int i = whitesize; i < n; i++) set.add(i);for (int val : blacklist) set.remove(val);Iterator<Integer> iter = set.iterator();// 将黑名单数据请求到白名单其他数据for (int val : blacklist) {if (val < whitesize) {map.put(val, iter.next());}}}public int pick() {int rand = new Random().nextInt(whitesize);return map.getOrDefault(rand, rand);}public static void main(String[] args) {int n = 10;int[] blacklist = {1,2,4,8};RandomBlackList_710 obj = new RandomBlackList_710(n, blacklist);System.out.println("size = " + obj.set.toString());System.out.println("map key = " + obj.map.keySet().toString() + "; map val = " + obj.map.values().toString());for (int i = 0; i < 10; i++)System.out.println(obj.pick());}}
岛屿问题
200-岛屿数量

题意分析:
- 当前节点可达的节点集合作为一个岛屿,问题可以归结为图的遍历。
解题思路:
- dfs 遍历。一次 dfs 遍历所有节点解决不了问题,需要对每个可行节点执行 dfs 逻辑,每一次找到一个岛屿。
注意点:
扩展:
代码:
public class IslandsQuestion_200 {int[][] direction = {{-1,0},{1,0},{0,-1},{0,1}};char[][] visited;char[][] grid;int m,n;int num;public int numIslands(char[][] grid) {this.grid = grid;m = grid.length;n = grid[0].length;visited = new char[m][n];for (int i = 0; i < m; i++) {Arrays.fill(visited[i], '0');}for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (grid[i][j] == '1' && visited[i][j] == '0') {num++;dfs(i, j);}}}return num;}/*** dfs 遍历:将 '1' 周围关联的 '1' 全部设置为 visited* @param x* @param y*/private void dfs(int x, int y) {if (x < 0 || y < 0 || x >= m || y >= n) {return;}// '0' 不访问, visited-1 表示已经访问if ( grid[x][y] == '0' || visited[x][y] == '1') {return;}// 每一轮 dfs 遍历,将 '1' 周围节点的 '1' 都设置为 visitedvisited[x][y] = '1';// 将 dfs 可达节点都置为 1,表示访问过for (int i = 0; i < direction.length; i++) {int tx = x + direction[i][0];int ty = y + direction[i][1];dfs(tx, ty);}}public static void main(String[] args) {IslandsQuestion_200 obj = new IslandsQuestion_200();char[][] grid = {{'1','1','0','0','0'},{'1','1','0','0','0'},{'0','0','1','0','0'},{'0','0','0','1','1'}};int res = obj.numIslands(grid);System.out.println("res = " + res);}}
1254-统计封闭岛屿的数量

题意分析:
- 和题 200 题目类似,无非就是要过滤掉四个边边上的节点。
解题思路:
- 判断是先判断边边的节点,过滤掉。
注意点:
扩展:
代码:
public class IslandsClosed_1254 {int[][] grid;int[][] direction = {{0,-1},{0,1},{-1,0},{1,0}};int m,n;int res;public int closedIsland(int[][] grid) {this.grid = grid;m = grid.length;n = grid[0].length;// 对四周节点过滤for (int i = 0; i < m; i++) {dfs(i,0);dfs(i, n - 1);}for (int i = 0; i < n; i++) {dfs(0, i);dfs(m - 1, i);}// 对所以 0(陆地)节点遍历,判断是否能形成一个岛屿for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (grid[i][j] == 0) {res++;dfs(i,j);}}}return res;}public void dfs(int x, int y) {if (x < 0 || y < 0 || x >= m || y >= n) {return;}if (grid[x][y] == 1) {return;}// 将访问过的 0(陆地) 设置为 1(海水)grid[x][y] = 1;for (int i = 0; i < direction.length; i++) {int tx = x + direction[i][0];int ty = y + direction[i][1];dfs(tx, ty);}}}
未分类
581-最短无序连续子数组

代码:
/*** 排序 + 遍历(时间复杂度:O(N * logN)** 复制一个数组并排序,遍历对比left和right区间* @param nums* @return*/public int findUnsortedSubarray2(int[] nums) {int len = nums.length;int[] sorted = Arrays.copyOf(nums, nums.length);Arrays.sort(sorted);System.out.println("nums = " + Arrays.toString(nums));System.out.println("sorted = " + Arrays.toString(sorted));int left = 0, right = len - 1;int l = -1, r = -1;for (; left < len; left++) {if (nums[left] != sorted[left]) {l = left;break;}}for (; right >= 0; right--) {if (nums[right] != sorted[right]) {r = right;break;}}System.out.println("l = " + l + "; r = " + r);return l != r ? r - l + 1 : 0;}/*** 双指针* @param nums* @return*/public int findUnsortedSubarray(int[] nums) {int len = nums.length;int left = 0, right = 0;int max = Integer.MIN_VALUE;int min = Integer.MAX_VALUE;// 双指针左右扫描,找出 left 和 rightfor (int i = 0; i < len; i++) {// 找 right。从左到右遍历,如果某个元素小于前面所有元素的最大值,则无序,更新 rightif (nums[i] >= max) {max = nums[i];} else {right = i;}// 找left。从右往左遍历,如果某个元素大于前面所有元素的最小值,则无序,更新leftif (nums[len - i -1] <= min) {min = nums[len - i - 1];} else {left = len - i - 1;}}System.out.println("left = " + left + "; right = " + right);return left == right ? 0 : right - left + 1;}
896-单调数列

代码:
public boolean isMonotonic(int[] nums) {int len = nums.length;boolean isInc = true, isDec = true;// 如果不是单调递增或者单调递减,isInc 和 isDec 都为 falsefor (int i = 0; i < len - 1; i++) {// 一对递增数据,isDec = false;if (nums[i] < nums[i+1]) {isDec = false;}if (nums[i] > nums[i+1]) {isInc = false;}}return isInc || isDec;}
1337-矩阵中战斗力最弱的 K 行

代码:
public int[] kWeakestRows(int[][] mat, int k) {int m = mat.length, n = mat[0].length;for(int i = 0; i < m; i++) {for (int j =0; j< n; j++) {System.out.print(mat[i][j] + " ");}System.out.println();}// 记录行号和1的个数int[][] cntArr = new int[m][2];for (int i = 0; i < m; i++) {// 对每一行执行二分查找,找出 1 的个数int[] arr = mat[i];int pos = binarySearch(arr);cntArr[i][0] = i;cntArr[i][1] = pos + 1;}for (int i = 0; i < cntArr.length; i++) {System.out.println("行:1数量 == " + cntArr[i][0] + ":" + cntArr[i][1]);}// 自定义比较器排序,先按1的个数升序排序,再按行号升序排序Arrays.sort(cntArr, new Comparator<int[]>() {@Overridepublic int compare(int[] o1, int[] o2) {if (o1[1] != o2[1]) {return (o1[1] - o2[1]);} else {return (o1[0] - o2[0]);}}});System.out.println("-------排序后——--------");for (int i = 0; i < cntArr.length; i++) {System.out.println("行:1数量 == " + cntArr[i][0] + ":" + cntArr[i][1]);}// 输出前 k 行行号int[] ret = new int[k];for(int i = 0; i < k; i++) {ret[i] = cntArr[i][0];System.out.println(ret[i]);}return ret;}/*** 二分查找每一行 1 的数量* @param arr* @return*/public int binarySearch(int[] arr) {int left = 0, right = arr.length - 1;int pos = -1;while (left <= right) {int mid = left + (right - left) / 2;if (arr[mid] == 0) {right = mid - 1;} else {pos = mid;left = mid + 1;}}return pos;}
88-合并两个有序数组

代码:
/*** 申请长度为 m+n 的额外数组* @param nums1* @param m* @param nums2* @param n*/public void merge2(int[] nums1, int m, int[] nums2, int n) {int[] tmp = new int[m+n];int k = 0;int i = 0, j = 0;while (i < m && j < n) {tmp[k++] = nums1[i] < nums2[j] ? nums1[i++] : nums2[j++];}while(i < m) {tmp[k++] = nums1[i++];}while (j < n) {tmp[k++] = nums2[j++];}for(int p = 0 ;p < tmp.length; p++) nums1[p] = tmp[p];System.out.println("tmp = " + Arrays.toString(nums1));}/*** 原地复制,从尾部空位置开始填充* @param nums1* @param m* @param nums2* @param n*/public void merge(int[] nums1, int m, int[] nums2, int n) {int i = m - 1;int j = n - 1;int k = m + n - 1;while (i >= 0 && j >= 0) {nums1[k--] = nums1[i] > nums2[j] ? nums1[i--] : nums2[j--];}System.arraycopy(nums2, 0 , nums1, 0, j + 1);// System.out.println("nums = " + Arrays.toString(nums1));}
611-有效三角形的个数

代码:
/*** 排序 + 二分查找 (时间复杂度 O(N^2 * logN)** 注意:System.out 会增加统计时间,造成时间超时** @param nums* @return*/public int triangleNumber(int[] nums) {int len = nums.length;if (len <= 2) {return 0;}int ans = 0;Arrays.sort(nums);for (int i = 0; i < len-1; i++) {for (int j = i+1; j < len; j++) {int left = j + 1, right = len - 1;int k = j;while (left <= right) {int mid = left + (right - left) / 2;if (nums[i] + nums[j] > nums[mid]) {// System.out.println(nums[i] + "-" + nums[j] + "-" + nums[mid]);k = mid;left = mid + 1;} else {right = mid - 1;}}ans += k - j;}}return ans;}
912-排序数组

代码:
public int[] sortArray(int[] nums) {quicksort(nums, 0, nums.length - 1);return nums;}public void quicksort(int[] nums, int startIdx, int endIdx) {if (startIdx < endIdx) {int pivot = partition(nums, startIdx, endIdx);quicksort(nums, startIdx, pivot);quicksort(nums, pivot + 1, endIdx);}}/*** 一次快排操作* @param nums* @param startIdx* @param endIdx* @return*/public int partition(int[] nums, int startIdx, int endIdx) {int pivot = startIdx;int left = startIdx, right = endIdx;while (left != right) {while (left < right && nums[right] >= nums[pivot]) right--;while (left < right && nums[left] <= nums[pivot]) left++;// 交换left 和 right 的值if (left < right) {int tmp = nums[left];nums[left] = nums[right];nums[right] = tmp;}}// left/right 重合,交换 pivot 和 left 的值,一次快排完成int tmp = nums[pivot];nums[pivot] = nums[left];nums[left] = tmp;return left;}
189-旋转数组

代码:
public void rotate(int[] nums, int k) {k = k % nums.length;reverse(nums, 0, nums.length - 1);reverse(nums, 0, k - 1);reverse(nums, k, nums.length - 1);printArray(nums);}// 倒序数组public void reverse(int[] nums, int start, int end) {while (start < end) {int tmp = nums[start];nums[start] = nums[end];nums[end] = tmp;start++;end--;}}
915-分隔数组

题意分析:
- 分隔数组,使得left数组数据都小于right数组数据,且保证left数组长度最小。
解题思路:
- 多次遍历数组。判断条件 max(left) < min(right),满足这个条件的最小 idx 值。
- 时间复杂度:O(n)
- 空间复杂度:O(n)
注意点:
- 最后条件判断的时候要考虑 <= 相等的情况。
扩展:
- 能否减少数组遍历次数。
代码:
/*** 解题思路:* 判断条件:max(left) < min(right),满足这个条件的最小 idx 值。* 1、统计 left 数组每个分隔点的最大值* 2、统计 right 数组每个分隔点的最小值* @param nums* @return*/public int partitionDisjoint(int[] nums) {int n = nums.length;int[] maxleft = new int[n];int[] minright = new int[n];// left 数组每个位置的最大值int max = Integer.MIN_VALUE;for (int i = 0; i < n; i++) {max = Math.max(max, nums[i]);maxleft[i] = max;}System.out.println("maxleft = " + Arrays.toString(maxleft));// right 数组每个位置的最小值int min = Integer.MAX_VALUE;for (int j = n-1; j >= 0; j--) {min = Math.min(min, nums[j]);minright[j] = min;}System.out.println("minright = " + Arrays.toString(minright));// 比较切分后 left 和 right 数组的值for (int i = 1; i < n; i++) {if (maxleft[i-1] <= minright[i]) {return i;}}return n;}
27-移除元素


题意分析:
- 原地修改数组,删除数组中值为 val 的元素。
解题思路:
- 左右指针。左指针维护更新后数组元素,右指针扫描数组。
注意点:
- 右指针何时扫描。
扩展:
代码:
/*** 解题思路:双指针* @param nums* @param val* @return*/public int removeElement(int[] nums, int val) {System.out.println(Arrays.toString(nums));int left = 0, right = 0;while (right != nums.length) {if (nums[right] != val) {nums[left++] = nums[right];}right++;}// System.out.println(Arrays.toString(nums));return left;}
1909-删除一个元素使数组严格递增

题意分析:
- 删除一个元素,数组严格递增。
解题思路:
- 贪心算法。当遇到当前小于前一个数时,则比较当前数和前两个数大小,如果当前数小于前两个数,则删除当前数,如果当前数小于前两个数中的一个(即小于前一个数),则删除前一个数。
注意点:
扩展:
代码:
- https://leetcode-cn.com/problems/remove-one-element-to-make-the-array-strictly-increasing/solution/tan-xin-by-hu-li-hu-wai-1zni/
public boolean canBeIncreasing(int[] nums) {int cnt = 0;int n = nums.length;for (int i = 1; i < n && cnt <= 1; i++) {if (nums[i] <= nums[i - 1]) {cnt++;// 如果当前数小于前面两个数,则删除当前数if (i - 2 >= 0 && nums[i] <= nums[i - 2]) {nums[i] = nums[i-1];} else {// 如果当前数只小于前两个数中的第二个数,则删除前一个数nums[i - 1] = nums[i];}}}return cnt <= 1;}
1-两数之和

题意分析:
- 数组中两个元素之和等于 target。
解题思路:
- 思路一:HashMap 保存 target-nums[i] 元素。
- 思路二:排序+双指针。
注意点:
扩展:
- 返回所有和为 target 的元素对,且不存在重复项。
代码:
/*** 思路一:HashMap 保存遍历过的元素和索引* @param nums* @param target* @return*/public int[] twoSum(int[] nums, int target) {Map<Integer, Integer> map = new HashMap<>();int[] res = new int[2];for (int i = 0; i < nums.length; i++) {if (map.containsKey(nums[i])) {res[0] = map.get(nums[i]);res[1] = i;return res;} else {map.put(target - nums[i], i);}}return res;}/*** 思路二:双指针(求所有两数之和为 sum 的元素对,且不重复)* @param nums* @param target* @return*/public List<List<Integer>> twoSum2(int[] nums, int target) {List<List<Integer>> res = new ArrayList<>();// 对数组升序排序Arrays.sort(nums);int low = 0, high = nums.length - 1;while (low < high) {int low_val = nums[low];int high_val = nums[high];int sum = low_val + high_val;if (sum < target) {low++;} else if (sum > target) {high--;} else if (sum == target) {List<Integer> list = new ArrayList();list.add(nums[low++]); list.add(nums[high--]);// 如果 low 往右走出现重复元素,则继续右走,high 逻辑也一样while (nums[low] == low_val) low++;while (nums[high] == high_val) high--;res.add(list);}}return res;}
15-三数之和

题意分析:
- 数组中三个元素和为 target。
解题思路:
- 排序+双指针。排序数组,遍历数组中每个元素,调用 2Sum 求解,遇到重复遍历元素跳过。
注意点:
扩展:
代码:
public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> res = new ArrayList<>();if (nums.length <= 2) {return res;}Arrays.sort(nums);// System.out.println(Arrays.toString(nums));for (int i = 0; i < nums.length - 2; i++) {List<List<Integer>> twoRes = twoSum(nums,i + 1, 0 - nums[i]);// System.out.println("nums[i] = " + nums[i] + "; twoRes = " + twoRes);for (int j = 0; j < twoRes.size(); j++) {twoRes.get(j).add(nums[i]);res.add(twoRes.get(j));}while (i < nums.length -1 && nums[i+1] == nums[i]) i++;}return res;}/*** 两数只和* @param nums* @param start* @param target* @return*/private List<List<Integer>> twoSum(int[] nums, int start, int target) {List<List<Integer>> twoRes = new ArrayList<>();int low = start, high = nums.length - 1;while (low < high) {int low_val = nums[low], high_val = nums[high];int sum = low_val + high_val;if (sum < target) {// 优化while (low < high && nums[low] == low_val) low++;} else if (sum > target) {while (low < high && nums[high] == high_val)high--;} else if (sum == target) {List<Integer> list = new ArrayList<>();list.add(low_val); list.add(high_val);while (low < high && nums[low] == low_val) low++;while (low < high && nums[high] == high_val) high--;twoRes.add(list);}}return twoRes;}
18-四数之和(nSum问题)

题意分析:
- 数组中四个数或者 n 个数和为 target。
解题思路:
- 思路一:调用 3Sum 求解,没意义。
- 思路二:通用 nSum 求解,递归调用 (n-1)Sum 求解。
注意点:
扩展:
代码:
public List<List<Integer>> fourSum(int[] nums, int target) {int n = 4;Arrays.sort(nums);return nSumTarget(nums, n, 0, target);}/**** @param nums* @param n 表示几个数之和,比如 n=2,表示两个数之和* @param start 数组的开始元素* @param target* @return*/public List<List<Integer>> nSumTarget(int[] nums, int n, int start, int target) {int size = nums.length;List<List<Integer>> res = new ArrayList<>();// 至少 2Sum,且数组大小不应该小于 nif (n < 2 || size < n) return res;int low = start, high = nums.length - 1;if (n == 2) {// 双指针while (low < high) {int low_val = nums[low], high_val = nums[high];int sum = low_val + high_val;if (sum < target) {// 优化while (low < high && nums[low] == low_val) low++;} else if (sum > target) {// 优化while (low < high && nums[high] == high_val)high--;} else if (sum == target) {List<Integer> list = new ArrayList<>();list.add(low_val); list.add(high_val);while (low < high && nums[low] == low_val) low++;while (low < high && nums[high] == high_val) high--;res.add(list);}}} else {// n > 2 时,递归计算 (n-1)Sum 结果for (int i = start; i < size; i++) {List<List<Integer>> nRes = nSumTarget(nums, n - 1, i + 1, target - nums[i]);for (List<Integer> list : nRes) {list.add(nums[i]);res.add(list);}while (i < size - 1 && nums[i] == nums[i+1]) i++;}}return res;}
模版
题意分析:
解题思路:
注意点:
扩展:
代码:
