day7 | 哈希表(2)

发布时间 2023-11-18 20:56:23作者: Inbreak

题目链接:454. 四数相加 II - 力扣(LeetCode)

题目描述:

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

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

解题思路:参考代码随想录 (programmercarl.com)

 1 class Solution {
 2     public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
 3         int res = 0;
 4         Map<Integer,Integer> map = new HashMap<Integer, Integer>(); //创建一个map
 5         for (int i : nums1){
 6             for (int j : nums2){
 7                 int sum = i + j;
 8                 map.put(sum, map.getOrDefault(sum, 0) + 1);
 9             }
10         }
11         for(int i : nums3){
12             for (int j : nums4){
13                 res += map.getOrDefault(0-i-j, 0);
14             }
15         }
16         return res;
17     }
18 }
  • 在java语言中的Map操作:

  Map初始化:

Map<String, String>map = new HashMap<String, String>();

  插入元素:

map.put("key1", "value1");

  获取元素:

map.get("key1");

  移除元素:

map.remove("key1");

  清空map:

map.clear();
  • hashmap.getOrDefault(Object key, V defaultValue)函数的用法:

  参数说明:key - 键、defaultValue - 当指定的key并不存在映射关系中,则返回的默认值。

  在题目中使用defaultValue函数对map进行插入,在遍历的过程中a+b的值出现了重复,直接将value值+1,节约了一些时间。

 

题目链接:383. 赎金信 - 力扣(LeetCode)

题目描述:

给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false 。

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

解题思路:

  这是一个很典型的 字符串a 能否组成 字符串b 的问题——数组在哈希法中的应用。

  解题一般分为4步:

  1. 定义一个哈希映射的数组record[ ]

  2. 遍历 字符串a中出现的字符,并对出现的次数进行计数;

  3. 遍历 字符串b中出现的字符,计算 b中出现的字符数-a中出现的字符数

  4. 判断 record数组中是否出现负数即b-a<0(也就是说字符串b不能由字符串a所构成)

 1 class Solution {
 2     public boolean canConstruct(String ransomNote, String magazine) {
 3         if (ransomNote.length() > magazine.length()){
 4             return false;
 5             //如果ransomNote这个字符串比magazine这个字符串还要长,那magazine必不可能有ransomNote所构成
 6         }
 7         int[] record = new int[26];
 8         for(char c : magazine.toCharArray()){
 9             record[c - 'a'] += 1;
10         }
11         for(char c : ransomNote.toCharArray()){
12             record[c - 'a'] -= 1;
13         }
14         for(int i : record){
15             if(i < 0){
16                 return false;
17             }
18         }
19         return true;
20     }
21 }

toCharArray()方法,将字符串转换为字符数组。

 

题目链接:15. 三数之和 - 力扣(LeetCode)

题目描述:

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

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

解题思路:

  因为题目中强调 答案中不可以包含重复的三元组 ,所以要对三元组中的每一个元素进行去重的操作,使用哈希法难以实现,所以采用双指针法。

  双指针法:定义一个left指针和right指针。

    1. 定义双指针,并将数组从小到大进行排序

    2. 根据三数之和对指针进行移动(三数和 > 0, 数偏大,调小,right--;三数和 < 0,数偏小,调大,left++)在这个过程中要对三个元素进行去重的操作。

  注意:

    对i进行去重:使用的判断条件是nums[i] == nums[i-1]而不是使用nums[i] == nums[i+1],要注意甄别两者的区别。前者是判断i是否有重复,后者是判断三元组中的i是否和left指针所指向的元素有重复。

    对left和right去重:在对left和right所对应的元素进行去重的时候,要在收获三元组这个结果之后进行去重,如果从whlie(right>left)这个循环一开始就进行去重的操作,会造成结果的缺失。

 1 class Solution {
 2     public List<List<Integer>> threeSum(int[] nums) {
 3         List<List<Integer>> result = new ArrayList<>();
 4         Arrays.sort(nums);
 5         for(int i = 0; i < nums.length; i++){
 6             //排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果即可。
 7             if(nums[i] > 0){return result;}
 8             //对a去重
 9             if(i > 0 && nums[i]==nums[i-1]){continue;}
10             int left = i + 1;
11             int right = nums.length-1;
12             while(right > left){
13                 int sum = nums[i] + nums[left] + nums[right];
14                 if(sum > 0){
15                     right--;
16                 }
17                 else if(sum < 0){
18                     left++;
19                 }
20                 else{
21                     result.add(Arrays.asList(nums[i],nums[left],nums[right]));
22                 
23                 while(right > left && nums[right]==nums[right-1])right--;
24                 while(right > left && nums[left]==nums[left+1])left++;
25 
26                 right--;
27                 left++;
28             }
29         }
30     }
31     return result;
32     }
33 }

存疑:这个语句不是很懂,还有一些array方法的应用

 List<List<Integer>> result = new ArrayList<>();

 

题目链接:18. 四数之和 - 力扣(LeetCode)

题目描述:

解题思路:代码随想录 (programmercarl.com)

 

 1 class Solution {
 2 public:
 3     vector<vector<int>> fourSum(vector<int>& nums, int target) {
 4         vector<vector<int>> result;
 5         sort(nums.begin(), nums.end());
 6         for (int k = 0; k < nums.size(); k++) {
 7             // 剪枝处理
 8             if (nums[k] > target && nums[k] >= 0) {
 9                 break; // 这里使用break,统一通过最后的return返回
10             }
11             // 对nums[k]去重
12             if (k > 0 && nums[k] == nums[k - 1]) {
13                 continue;
14             }
15             for (int i = k + 1; i < nums.size(); i++) {
16                 // 2级剪枝处理
17                 if (nums[k] + nums[i] > target && nums[k] + nums[i] >= 0) {
18                     break;
19                 }
20 
21                 // 对nums[i]去重
22                 if (i > k + 1 && nums[i] == nums[i - 1]) {
23                     continue;
24                 }
25                 int left = i + 1;
26                 int right = nums.size() - 1;
27                 while (right > left) {
28                     // nums[k] + nums[i] + nums[left] + nums[right] > target 会溢出
29                     if ((long) nums[k] + nums[i] + nums[left] + nums[right] > target) {
30                         right--;
31                     // nums[k] + nums[i] + nums[left] + nums[right] < target 会溢出
32                     } else if ((long) nums[k] + nums[i] + nums[left] + nums[right]  < target) {
33                         left++;
34                     } else {
35                         result.push_back(vector<int>{nums[k], nums[i], nums[left], nums[right]});
36                         // 对nums[left]和nums[right]去重
37                         while (right > left && nums[right] == nums[right - 1]) right--;
38                         while (right > left && nums[left] == nums[left + 1]) left++;
39 
40                         // 找到答案时,双指针同时收缩
41                         right--;
42                         left++;
43                     }
44                 }
45 
46             }
47         }
48         return result;
49     }
50 };