算法训练营(day07)

454.四数相加II

题目链接:https://leetcode.cn/problems/4sum-ii/description/

给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:

  • 0 <= i, j, k, l < n
  • nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0

解题思路

解题过程:

  1. 定义一个 res 用于统计元组个数

  2. 遍历 nums1nums2 数组,定义一个 mapkey放**nums1[i]nums2[j]两数之和valuenums1[i]nums2[j]两数之和出现的次数**

  3. 遍历 nums3nums4 数组

    • 如果 0 - (nums3[k] + nums4[l])map 中出现过,就用 resmap0 - (nums3[k] + nums4[l]) 对应的 value 累加。
  4. 最后返回统计值 res

详细代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
int res = 0;
Map<Integer, Integer> map = new HashMap<>();

for(int i : nums1){
for(int j : nums2){
int tmp = i + j;
map.put(tmp, map.getOrDefault(tmp, 0) + 1);
}
}
for(int i : nums3){
for(int j : nums4){
int count = i + j;
if(map.containsKey(0 - count)){
res += map.get(0 - count);
}
}
}
return res;
}
}

383.赎金信

题目链接:https://leetcode.cn/problems/ransom-note/description/

给你两个字符串:ransomNotemagazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。如果可以,返回 true ;否则返回 false

magazine 中的每个字符只能在 ransomNote 中使用一次。

解题思路

解题过程:

  1. 题目给定了字符仅由小写字符组成,且杂志(magazine)里面的字母不可重复使用
  2. 用数组存储 magazine 的字符
  3. 如果 ransomNote 出现了 magazine 的字符,则将 magazine 的字符删去
  4. 遍历一遍 ransomNote 后,判断 magazine 的字符长度
    • 如果 < 0,则说明不满足题意,返回 false
    • 否则返回 true

详细代码

解法一:用 magazine 字符串 作参照,< 0 为 false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int[] res = new int[26];

for(char c : magazine.toCharArray()){
res[c - 'a']++;
}
for(char c : ransomNote.toCharArray()){
res[c - 'a']--;
}
for(int count : res){
if(count < 0){
return false;
}
}
return true;
}
}

解法二:用 ransomNote 字符串作参照,> 0 为 false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int[] res = new int[26];

for(char c : ransomNote.toCharArray()){
res[c - 'a']++;
}
for(char c : magazine.toCharArray()){
res[c - 'a']--;
}
for(int count : res){
if(count > 0){
return false;
}
}
return true;
}
}

15.三数之和

题目链接:https://leetcode.cn/problems/3sum/description/?orderBy=most_votes

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足nums[i] + nums[j] + nums[k] == 0。请你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

解题思路

解题过程:

  1. 不可以包含重复,说明需要对三元组进行 去重 操作

  2. 首先对 数组 排序,如果 nums[0] 已经 > 0, 直接返回空(剪枝

  3. 使用双指针的方法,对于 j、k 用指针 left, right 代替,只需要保证 三元素 不重复即可

  4. 关键是 去重 的操作,要注意当 nums 有且仅有三个元素有元素重复满足题意 的情况(需保留)

    • i > 0 && nums[i] == nums[i - 1]
    • left < right && nums[right] == nums[right - 1]
    • left < right && nums[left] == nums[left + 1]
  5. 循环结束后,返回结果 res.add(Arrays.asList(nums[i], nums[left], nums[right]))

详细代码

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
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<>();

for(int i = 0; i < nums.length; i++){
if(nums[i] > 0){
return res;
}
if(i > 0 && nums[i] == nums[i - 1]){
continue;
}

int left = i + 1;
int right = nums.length - 1;
while(left < right){
int sum = nums[i] + nums[left] + nums[right];

if(sum > 0){
right--;
}else if(sum < 0){
left++;
}else{
res.add(Arrays.asList(nums[i], 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;
}
}

18.四数之和

题目链接:https://leetcode.cn/problems/4sum/description/

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n
  • abcd 互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按 任意顺序 返回答案 。

解题思路

解题过程:

  1. 四数之和 和 15.三数之和 是一个思路,都是 先排序再使用双指针法,基本解法就是在 三数之和 的基础上再套一层for循环
  2. 关键点还是 去重剪枝

详细代码

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
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<>();
for(int i = 0; i < nums.length; i++){
if(nums[i] > target && nums[i] > 0){
return res;
}
if(i > 0 && nums[i - 1] == nums[i]){
continue;
}

for(int j = i + 1; j < nums.length; j++){
if(j > i + 1 && nums[j - 1] == nums[j]){
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){
res.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));

while(left < right && nums[right - 1] == nums[right]){
right--;
}
while(left < right && nums[left + 1] == nums[left]){
left++;
}
right--;
left++;
}else if(sum > target){
right--;
}else{
left++;
}
}
}
}
return res;
}
}