18 - 四数之和
前情提要:三数之和
给你一个由 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:
1 2
| 输入:nums = [1,0,-1,0,-2,2], target = 0 输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
|
例2:
1 2
| 输入:nums = [2,2,2,2,2], target = 8 输出:[[2,2,2,2]]
|
思路:
思路和三数之和 一样,排序后,枚举nums[a]作为第一个数,枚举nums[b]作为第二个数,那么问题变成找到另外两个数,使得这四个数的和等于target,这可以用双指针解决。
对于nums[a]的枚举:
-
设 s=nums[a]+nums[a+1]+nums[a+2]+nums[a+3]。如果s>target,由于数组已经排序,后面无论怎么选,选出的四个数的和不会比s还小,所以后面不会找到等于 target的四数之和了。所以只要 s>target,就可以直接 break 外层循环了。
-
设 s=nums[a]+nums[n−3]+nums[n−2]+nums[n−1]。如果s<target,由于数组已经排序,nums[a]加上后面任意三个数都不会超过s,所以无法在后面找到另外三个数与 nums[a]相加等于 target。但是后面还有更大的 nums[a],可能出现四数之和等于 target的情况,所以还需要继续枚举,continue外层循环。
-
如果 a>0且nums[a]=nums[a−1],那么 nums[a]和后面数字相加的结果,必然在之前算出过,所以无需执行后续代码,直接 continue 外层循环。(可以放在循环开头判断。)
对于 nums[b]的枚举(b从a+1开始),也同样有类似优化:
-
设 s=nums[a]+nums[b]+nums[b+1]+nums[b+2]。如果s>targett,由于数组已经排序,后面无论怎么选,选出的四个数的和不会比s还小,所以后面不会找到等于 target的四数之和了。所以只要 s>target,就可以直接 break。
-
设 s=nums[a]+nums[b]+nums[n−2]+nums[n−1]。如果 s<target,由于数组已经排序,nums[a]+nums[b]加上后面任意两个数都不会超过 sss,所以无法在后面找到另外两个数与 nums[a]和 nums[b]相加等于 target。但是后面还有更大的 nums[b],可能出现四数之和等于 target的情况,所以还需要继续枚举,continue。
-
如果 b>a+1且 nums[b]=nums[b−1],那么 nums[b]和后面数字相加的结果,必然在之前算出过,所以无需执行后续代码,直接 continue。注意这里 b>a+1的判断是必须的,如果不判断,对于示例 2 这样的数据,会直接 continue,漏掉符合要求的答案。
solution:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| class Solution { public List<List<Integer>> fourSum(int[] nums, int target) { Arrays.sort(nums); int len = nums.length; List<List<Integer>> result = new ArrayList<>(); for (int i = 0; i < len - 3; i++) { if (i > 0 && nums[i] == nums[i - 1]) { continue; } if ((long)nums[i] + (long)nums[i + 1] + (long)nums[i + 2] + (long)nums[i + 3] > target) { break; } if ((long)nums[i] + (long)nums[len - 1] + (long)nums[len - 2] + (long)nums[len - 3] < target) { continue; } for (int j = i + 1; j < len - 2; j++) { if (j > i + 1 && nums[j] == nums[j - 1]) { continue; } if ((long)nums[i] + (long)nums[j] + (long)nums[j + 1] + (long)nums[j + 2] > target) { break; } if ((long)nums[i] + (long)nums[j] + (long)nums[len - 1] + (long)nums[len - 2] < target) { continue; } int first = j + 1; int end = len - 1; while (first < end) { long sum = nums[i] + nums[j] + nums[first] + nums[end]; if (sum > target) { end--; } else if (sum < target) { first++; } else { result.add(List.of((int)nums[i], (int)nums[j], (int)nums[first], (int)nums[end])); for (first++; first < end && nums[first] == nums[first - 1]; first++) ; for (end--; end > first && nums[end] == nums[end + 1]; end--) ; } } } } return result; } }
|
19 - 删除链表的倒数第N个结点
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
例1:
1 2
| 输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]
|
例2:
1 2
| 输入:head = [1], n = 1 输出:[]
|
solution
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { ListNode pre = new ListNode(0); pre.next = head; ListNode start = pre; ListNode end = pre; while (n != 0) { start = start.next; n--; } while(start.next!=null){ start = start.next; end = end.next; } end.next = end.next.next; return pre.next; } }
|