LeetCode 454.四数相加II
四个数组,两两一组,和为0则结果加一
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
HashMap<Integer, Integer> map = new HashMap<>(); // <两数之和, 该和的出现次数>
int res = 0;
for(int a : nums1){
for(int b : nums2){
map.put(a + b, map.getOrDefault(a + b, 0) + 1);
}
}
for(int c : nums3){
for(int d : nums4){
res += map.getOrDefault(0 - (c + d), 0);
}
}
return res;
}
}
LeetCode 383. 赎金信
数组在哈希法中的应用
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
// 题目要求只有小写字母
int[] alphabet = new int[26];
for(char m : magazine.toCharArray()){
alphabet[m - 'a']++;
}
for(char r : ransomNote.toCharArray()){
alphabet[r - 'a']--;
if(alphabet[r - 'a'] < 0){
return false;
}
}
return true;
}
}
LeetCode 15. 三数之和
nSum 系列问题的核心思路就是排序 + 双指针。三数之和这里,就要固定一个指针不动,然后移动另外两个指针寻找和。
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 - 2; i++){
if(i > 0 && nums[i] == nums[i - 1])continue;
int j = i + 1, k = nums.length - 1;
while(j < k){
int sum = nums[i] + nums[j] + nums[k];
if(sum == 0){
res.add(Arrays.asList(nums[i], nums[j], nums[k]));
while(j < k && nums[j] == nums[j + 1])j++;
while(j < k && nums[k] == nums[k - 1])k--;
j++;
k--;
}
else if(sum > 0){
k--;
}
else if(sum < 0){
j++;
}
}
}
return res;
}
}
还可以以递归的形式,写出nSum的通用代码。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
// n 为 3, 从 nums[0] 开始计算和为 0 的三元组
return nSumTarget(nums, 3, 0, 0);
}
/**
调用这个函数前一定要先给nums排序
parameters:
@nums: 寻找范围的数组
@n: 想求的是几数之和
@start: 从哪个索引开始计算
@target: 想凑出的目标和
output:
@res: List<List<Integer>>
*/
private List<List<Integer>> nSumTarget(int[] nums, int n, int start, int target){
int size = nums.length;
List<List<Integer>> res = new ArrayList<>();
// 至少是两数之和,且数组大小不应该小于n
if(n < 2 || size < n)return res;
// 2Sum是base case
if(n == 2){
// 双指针那一套操作
int low = start, high = size - 1;
while(low < high){
int sum = nums[low] + nums[high];
if(sum < target){
while(low < high && nums[low] == nums[low + 1])low++;
}
else if(sum > target){
while(low < high && nums[high] == nums[high - 1])high--;
}
else{
res.add(new ArrayList<>(Arrays.asList(nums[low], nums[high])));
while(low < high && nums[low] == nums[low + 1])low++;
while(low < high && nums[high] == nums[high - 1])high--;
}
}
}
else{
// n > 2 时,递归计算(n-1)Sum的结果
for(int i = start; i < size; i++){
// 剪枝
// If the smallest possible sum is greater than target, break
if(n * nums[i] > target) break;
// If the largest possible sum is smaller than target, continue
if(nums[i] + (n - 1) * nums[size - 1] < target) continue;
List<List<Integer>> sub = nSumTarget(nums, n - 1, i + 1, target - nums[i]);
for(List<Integer> arr : sub){
// (n-1)Sum 加上 nums[i] 就是 nSum
arr.add(nums[i]);
res.add(arr);
}
while(i < size - 1 && nums[i] == nums[i + 1])i++;
}
}
return res;
}
}
LeetCode 18. 四数之和
只对此题:
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
for(int i = 0; i < nums.length; i++){
if(nums[i] > target && (nums[i] >= 0 || target >= 0)){
// nums[i] > target 并且排序后最小的数nums[i]非负,直接返回,剪枝操作
return res;
}
if(i > 0 && nums[i] == nums[i-1]){
continue;
}
for(int j = i + 1; j < nums.length;j++){
if(j > i + 1 && nums[j] == nums[j-1]){
continue;
}
int left = j + 1;
int right = nums.length - 1;
while(left < right){
int sum = nums[i] + nums[j] + nums[left] + nums[right];
if(sum > target){
right--;
}
else if(sum < target){
left++;
}
else{
res.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
while(left < right && nums[right] == nums[right - 1]) right--;
while(left < right && nums[left] == nums[left + 1]) left++;
right--;
left++;
}
}
}
}
return res;
}
}
nSum模板:
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
// n 为 4, 从 nums[0] 开始计算和为 target 的三元组
return nSumTarget(nums, 4, 0, target);
}
/**
调用这个函数前一定要先给nums排序
parameters:
@nums: 寻找范围的数组
@n: 想求的是几数之和
@start: 从哪个索引开始计算
@target: 想凑出的目标和
output:
@res: List<List<Integer>>
*/
private List<List<Integer>> nSumTarget(int[] nums, int n, int start, int target){
int size = nums.length;
List<List<Integer>> res = new ArrayList<>();
// 至少是两数之和,且数组大小不应该小于n
if(n < 2 || size < n)return res;
// 2Sum是base case
if(n == 2){
// 双指针那一套操作
int low = start, high = size - 1;
while(low < high){
int sum = nums[low] + nums[high];
int leftVal = nums[low], rightVal = nums[high];
if(sum < target){
while(low < high && nums[low] == leftVal)low++;
}
else if(sum > target){
while(low < high && nums[high] == rightVal)high--;
}
else{
res.add(new ArrayList<>(Arrays.asList(nums[low], nums[high])));
while(low < high && nums[low] == leftVal)low++;
while(low < high && nums[high] == rightVal)high--;
}
}
}
else{
// n > 2 时,递归计算(n-1)Sum的结果
for(int i = start; i < size; i++){
// 剪枝
// If the smallest possible sum is greater than target, break
if(n * nums[i] > target) break;
// If the largest possible sum is smaller than target, continue
if(nums[i] + (n - 1) * nums[size - 1] < target) continue;
List<List<Integer>> sub = nSumTarget(nums, n - 1, i + 1, target - nums[i]);
for(List<Integer> arr : sub){
// (n-1)Sum 加上 nums[i] 就是 nSum
arr.add(nums[i]);
res.add(arr);
}
while(i < size - 1 && nums[i] == nums[i + 1])i++;
}
}
return res;
}
}
// TODO: nSum模板在个别用例下会超时或是解答错误。