454.四数相加II
起初看见该题目的时候有思路将4个数组分为两两数组为一组(转换为两数之和),但是不知道如何利用哈希表进行判断,固有思维就是看两两数组的和为0
在卡哥的提示下才知晓利用 p = 0 - (c + d), 然后利用map.containsKey(p)进行判断
代码如下:
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
HashMap<Integer,Integer> map = new HashMap<>();
for(int a : nums1){
for(int b : nums2){
int temp = a + b;
if(map.containsKey(temp)){
map.put(temp, map.get(temp) + 1);
}else{
map.put(temp, 1);
}
}
}
int count = 0;
for(int c : nums3){
for(int d : nums4){
int p = 0 - (c + d);
if(map.containsKey(p)){
count += map.get(p);
}
}
}
return count;
}
}
383. 赎金信
该题阅读题意其实就是 242.有效的字母异位词 的另一个版本,换汤不换药
代码如下:
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int[] count1 = toArray(ransomNote);
int[] count2 = toArray(magazine);
for(int i = 0;i<26;i++){
if(count2[i] < count1[i]){
return false;
}
}
return true;
}
public int[] toArray(String str){
int[] count = new int[26];
for(char c : str.toCharArray()){
count[c - 'a']++;
}
return count;
}
}
15. 三数之和
3Sum问题其实在2Sum问题的基础上找到第三个数相加能够满足和为target,而如何找第三个数无非就是在数组中进行穷举第一个数nums[i],剩下两个数就是 target - nums[i]
所以具体思路就如下代码:
1.先找出2Sum
2.再在2Sum基础上添加第三个数
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
int target = 0;
for(int i = 0;i<nums.length;i++){
target = 0 - nums[i];
List<List<Integer>> temps = new ArrayList<>();
temps = twoSum(nums,i + 1,target);
for(List<Integer> temp : temps){
temp.add(nums[i]);
res.add(temp);
}
while(i < nums.length - 1 && nums[i] == nums[i + 1]){
i++;
}
}
return res;
}
public List<List<Integer>> twoSum(int[] nums,int start,int target){
List<List<Integer>> res = new ArrayList<>();
int lo = start; int hi = nums.length - 1;
while(lo < hi){
int sum = nums[lo] + nums[hi];
int left = nums[lo]; int right = nums[hi];
if(sum < target){
while(lo < hi && nums[lo] == left){
lo++;
}
}else if(sum > target){
while(lo < hi && nums[hi] == right){
hi--;
}
}else{
res.add(new ArrayList<>(Arrays.asList(left,right)));
while(lo < hi && nums[lo] == left){
lo++;
}
while(lo < hi && nums[hi] == right){
hi--;
}
}
}
return res;
}
}
18. 四数之和
而根据2Sum、3Sum题目思路则就是在3Sum基础上添加一个数字
可想而知无非就是递归思维
则直接看代码:
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
return nSumTarget(nums,4,0,target);
}
public List<List<Integer>> nSumTarget(int[] nums,int n,int start,long target){
List<List<Integer>> res = new ArrayList<>();
if(n < 2 || nums.length < n) return res;
if(n == 2){
int lo = start, hi = nums.length - 1;
while(lo < hi){
int sum = nums[lo] + nums[hi];
int left = nums[lo],right = nums[hi];
if(sum < target){
while(lo < hi && nums[lo] == left){
lo++;
}
}else if(sum > target){
while(lo < hi && nums[hi] == right){
hi--;
}
}else{
res.add(new ArrayList<>(Arrays.asList(left,right)));
while(lo < hi && nums[lo] == left){
lo++;
}
while(lo < hi && nums[hi] == right){
hi--;
}
}
}
}else{
for(int i = start;i<nums.length;i++){
List<List<Integer>> temps = new ArrayList<>();
temps = nSumTarget(nums,n - 1,i + 1,target - nums[i]);
for(List<Integer> temp : temps){
temp.add(nums[i]);
res.add(temp);
}
while(i < nums.length - 1 && nums[i] == nums[i + 1]){
i++;
}
}
}
return res;
}
}
今日总结
由2Sum、3Sum、4Sum问题便可以深化出nSum问题函数
代码如下:
public List<List<Integer>> nSumTarget(List<Integer> nums, int n, int start, long target) {
int sz = nums.size(); // 获取 nums 的大小
List<List<Integer>> res = new ArrayList<>(); // 定义结果列表
// 至少是2Sum,且数组大小不应该小于n
if (n < 2 || sz < n) { // 如果 n 小于 2 或者 nums 的大小小于 n,直接返回空列表
return res;
}
// 2Sum是base case
if (n == 2) { // 如果 n 等于 2,执行 2Sum 算法
// 双指针那一套操作
int lo = start, hi = sz - 1; // 定义双指针 lo 和 hi
while (lo < hi) { // 当 lo 小于 hi 时,执行循环
int sum = nums.get(lo) + nums.get(hi); // 获取 lo 和 hi 位置上数字的和
int left = nums.get(lo), right = nums.get(hi); // 获取 lo 和 hi 位置上的数字
if (sum < target) { // 如果和小于目标值,lo 指针向右移动
while (lo < hi && nums.get(lo) == left) {
lo++;
}
} else if (sum > target) { // 如果和大于目标值,hi 指针向左移动
while (lo < hi && nums.get(hi) == right) {
hi--;
}
} else { // 如果和等于目标值,添加结果到 res 列表中,并移动指针
List<Integer> pair = new ArrayList<>(); // 定义包含两个数字的列表 pair
pair.add(left); // 添加 lo 位置上的数字到 pair 中
pair.add(right); // 添加 hi 位置上的数字到 pair 中
res.add(pair); // 将 pair 添加到结果列表 res 中
while (lo < hi && nums.get(lo) == left) { // 移动 lo 指针
lo++;
}
while (lo < hi && nums.get(hi) == right) { // 移动 hi 指针
hi--;
}
}
}
} else { // 如果 n 大于 2,递归计算 (n-1)Sum 的结果
for (int i = start; i < sz; i++) { // 遍历 nums 数组
List<List<Integer>> sub = nSumTarget(nums, n - 1, i + 1, target - nums.get(i)); // 递归调用 nSumTarget 函数,计算 (n-1)Sum 的结果
for (List<Integer> arr : sub) { // 遍历 (n-1)Sum 的结果
// (n-1)Sum 加上 nums[i] 就是 nSum
arr.add(nums.get(i)); // 将 nums[i] 添加到 (n-1)Sum 的结果中
res.add(arr); // 将新的 nSum 结果添加到 res 列表中
}
while (i < sz - 1 && nums.get(i) == nums.get(i + 1)) { // 跳过重复的数字
i++;
}
}
}
return res; // 返回结果列表 res
}