2023-04-14 算法面试中常见的查找表问题
1 Set的使用#
LeetCode349号问题:两个数组的交集
| 给定两个数组,编写一个函数来计算它们的交集。 |
| |
| 示例 1: |
| |
| 输入: nums1 = [1,2,2,1], nums2 = [2,2] |
| 输出: [2] |
| 示例 2: |
| |
| 输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4] |
| 输出: [9,4] |
| 说明: |
| |
| 输出结果中的每个元素一定是唯一的。 |
| 我们可以不考虑输出结果的顺序。 |
| package Chapter04SetAndMap.IntersectionofTwoArrays; |
| |
| import java.util.*; |
| |
| |
| |
| |
| |
| |
| class Solution { |
| |
| |
| |
| |
| public int[] intersection(int[] nums1, int[] nums2) { |
| Set<Integer> numSet = new HashSet<>(); |
| for (int i : nums1) { |
| numSet.add(i); |
| } |
| |
| Set<Integer> num2Set = new HashSet<>(); |
| |
| for (int i : nums2) { |
| num2Set.add(i); |
| } |
| |
| |
| numSet.retainAll(num2Set); |
| int[] result = new int[numSet.size()]; |
| int i = 0; |
| for (Integer num : numSet) { |
| result[i] = num; |
| i++; |
| } |
| return result; |
| } |
| |
| |
| |
| |
| |
| public int[] intersection2(int[] nums1, int[] nums2) { |
| |
| TreeSet<Integer> record = new TreeSet<>(); |
| for (int num : nums1) { |
| record.add(num); |
| } |
| |
| TreeSet<Integer> resultSet = new TreeSet<>(); |
| for (int num : nums2) { |
| if (record.contains(num)) { |
| resultSet.add(num); |
| } |
| } |
| |
| int[] res = new int[resultSet.size()]; |
| int index = 0; |
| for (Integer num : resultSet) { |
| res[index++] = num; |
| } |
| |
| return res; |
| } |
| |
| |
| public static void main(String[] args) { |
| int[] nums1 = {4, 9, 5}; |
| int[] nums2 = {9, 4, 9, 8, 4}; |
| int[] result = new Solution().intersection2(nums1, nums2); |
| System.out.println(Arrays.toString(result)); |
| } |
| } |
2 Map的使用#
350.两个数组的交集 II
| 给定两个数组,编写一个函数来计算它们的交集。 |
| |
| 示例 1: |
| |
| 输入: nums1 = [1,2,2,1], nums2 = [2,2] |
| 输出: [2,2] |
| 示例 2: |
| |
| 输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4] |
| 输出: [4,9] |
| 说明: |
| |
| 输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。 |
| 我们可以不考虑输出结果的顺序。 |
| 进阶: |
| |
| package Chapter04SetAndMap.IntersectionofTwoArrays2; |
| |
| import java.util.*; |
| |
| |
| |
| |
| |
| |
| class Solution { |
| public int[] intersect(int[] nums1, int[] nums2) { |
| Map<Integer, Integer> num1Map = new HashMap<>(); |
| Set<Integer> num1Set = new HashSet<>(); |
| for (int i : nums1) { |
| num1Map.merge(i, 1, Integer::sum); |
| num1Set.add(i); |
| } |
| |
| |
| Map<Integer, Integer> num2Map = new HashMap<>(); |
| Set<Integer> num2Set = new HashSet<>(); |
| |
| for (int i : nums2) { |
| num2Map.merge(i, 1, Integer::sum); |
| num2Set.add(i); |
| } |
| |
| |
| num1Set.retainAll(num2Set); |
| |
| |
| List<Integer> resultList = new ArrayList<>(); |
| for (Integer num : num1Set) { |
| int count = Math.min(num1Map.get(num), num2Map.get(num)); |
| for (int i = 0; i < count; i++) { |
| resultList.add(num); |
| } |
| } |
| |
| int[] result = new int[resultList.size()]; |
| int i = 0; |
| for (Integer num : resultList) { |
| result[i] = num; |
| i++; |
| } |
| return result; |
| } |
| |
| public static void main(String[] args) { |
| int[] nums1 = {1, 2, 2, 1}; |
| int[] nums2 = {2}; |
| int[] result = new Solution().intersect(nums1, nums2); |
| System.out.println(Arrays.toString(result)); |
| } |
| } |
3 Set和Map不同底层实现的区别#
参考Part2Basic全课程,每部分实现地数组、链表和树可以用来作为Map的底层,不同的实现比较如下:

哈希表虽然性能高,劣势是空间占用大,而且元素不能保持顺序~~
LeetCode上更多相似问题:242、202、290、205、451
基于频率表的实现
| class Solution { |
| |
| public boolean isAnagram(String s, String t) { |
| if("".equals(s) && "".equals(t)){ |
| return true; |
| } |
| if("".equals(s) || "".equals(t) || s.length() != t.length()){ |
| return false; |
| } |
| int[] freq = new int[256]; |
| int len = s.length(); |
| for(int i = 0; i< len; i++){ |
| freq[s.charAt(i)] = freq[s.charAt(i)] + 1; |
| freq[t.charAt(i)] = freq[t.charAt(i)] - 1; |
| } |
| for(int i = 0; i< len; i++){ |
| if(freq[s.charAt(i)] != 0){ |
| return false; |
| } |
| } |
| return true; |
| } |
| } |
进一步优化,缩小数组范围,性能最高:
| class Solution { |
| |
| public boolean isAnagram(String s, String t) { |
| if("".equals(s) && "".equals(t)){ |
| return true; |
| } |
| if("".equals(s) || "".equals(t) || s.length() != t.length()){ |
| return false; |
| } |
| int[] freq = new int[26]; |
| int len = s.length(); |
| for(int i = 0; i< len; i++){ |
| int sInt = s.charAt(i) - 'a'; |
| int tInt = t.charAt(i) - 'a'; |
| freq[sInt] = freq[sInt] + 1; |
| freq[tInt] = freq[tInt] - 1; |
| } |
| for(int i = 0; i< len; i++){ |
| if(freq[s.charAt(i) - 'a'] != 0){ |
| return false; |
| } |
| } |
| return true; |
| } |
| } |
基于HashMap的实现
| class Solution { |
| |
| |
| |
| public boolean isAnagram(String s, String t) { |
| if ("".equals(s) && "".equals(t)) { |
| return true; |
| } |
| if ("".equals(s) || "".equals(t) || s.length() != t.length()) { |
| return false; |
| } |
| int len = s.length(); |
| |
| Map<Character, Integer> cMap = new HashMap<>(); |
| for (int i = 0; i < len; i++) { |
| char sC = s.charAt(i); |
| char tC = t.charAt(i); |
| if (cMap.get(sC) == null) { |
| cMap.put(sC, 1); |
| } else { |
| cMap.put(sC, cMap.get(sC) + 1); |
| } |
| if (cMap.get(tC) == null) { |
| cMap.put(tC, -1); |
| } else { |
| cMap.put(tC, cMap.get(tC) - 1); |
| } |
| } |
| for (Character c : cMap.keySet()) { |
| if (cMap.get(c) != 0) { |
| return false; |
| } |
| } |
| return true; |
| } |
| } |
关键是观察规律
| import java.util.HashSet; |
| import java.util.Set; |
| |
| class Solution { |
| int getSquareSum(int n) { |
| int sum = 0; |
| while (n != 0) { |
| sum += (n % 10) * (n % 10); |
| n = n / 10; |
| } |
| return sum; |
| } |
| |
| |
| |
| |
| |
| public boolean isHappy(int n) { |
| Set<Integer> set = new HashSet<>(); |
| while (true) { |
| n = getSquareSum(n); |
| if (n == 1) { |
| return true; |
| } |
| if (set.contains(n)) { |
| |
| return false; |
| } else { |
| set.add(n); |
| } |
| } |
| } |
| |
| public static void main(String[] args) { |
| |
| int n = 19; |
| System.out.println(new Solution().isHappy(n)); |
| } |
| } |
| class Solution { |
| public boolean wordPattern(String pattern, String str) { |
| if("".equals(pattern) || "".equals(str)){ |
| return false; |
| } |
| String[] words = str.split(" "); |
| int len = pattern.length(); |
| if(len != words.length){ |
| return false; |
| } |
| Set<Character> setPattern = new HashSet<>(); |
| Set<String> setWord = new HashSet<>(); |
| for(int i = 0; i < len; i++){ |
| setPattern.add(pattern.charAt(i)); |
| setWord.add(words[i]); |
| } |
| if(setPattern.size() != setWord.size()){ |
| return false; |
| } |
| Map<Character, String> map = new HashMap<>(); |
| for(int i = 0; i < len; i++){ |
| Character c = pattern.charAt(i); |
| String word = map.get(c); |
| if(word == null){ |
| map.put(c, words[i]); |
| }else { |
| |
| if(!word.equals(words[i])){ |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| } |
和290几乎完全相同,单词边字符而已
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Map; |
| import java.util.Set; |
| |
| class Solution { |
| public boolean isIsomorphic(String s, String t) { |
| if ("".equals(s) && "".equals(t)) { |
| return true; |
| } |
| if ("".equals(s) || "".equals(t)) { |
| return false; |
| } |
| int len = s.length(); |
| if (len != t.length()) { |
| return false; |
| } |
| Set<Character> setS = new HashSet<>(); |
| Set<Character> setT = new HashSet<>(); |
| for (int i = 0; i < len; i++) { |
| setS.add(s.charAt(i)); |
| setT.add(t.charAt(i)); |
| } |
| if (setS.size() != setT.size()) { |
| return false; |
| } |
| Map<Character, Character> map = new HashMap<>(); |
| for (int i = 0; i < len; i++) { |
| Character cS = s.charAt(i); |
| Character cSMap = map.get(cS); |
| Character cT = t.charAt(i); |
| if (cSMap == null) { |
| map.put(cS, cT); |
| } else { |
| |
| if (!cT.equals(cSMap)) { |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| public static void main(String[] args) { |
| String s = "egg"; |
| String t = "add"; |
| System.out.println(new Solution().isIsomorphic(s, t)); |
| } |
| } |
| class Solution { |
| public String frequencySort(String s) { |
| StringBuilder sb = new StringBuilder(); |
| int[] freq = new int[256]; |
| int len = s.length(); |
| for(int i = 0; i < len; i++){ |
| char c = s.charAt(i); |
| freq[c] += 1; |
| } |
| |
| for(int i = 0; i < len; i++){ |
| |
| int max = 0; |
| for(int j = 0; j < 256; j++) { |
| if(freq[j] > freq[max]){ |
| max = j; |
| } |
| } |
| |
| for(int m = 0; m < freq[max]; m++){ |
| sb.append((char)max); |
| } |
| |
| freq[max] = 0; |
| } |
| return sb.toString(); |
| } |
| |
| public static void main(String[] args) { |
| String s = "cccaaa"; |
| System.out.println(new Solution().frequencySort(s)); |
| } |
| } |
4 Two Sum的问题#
LeetCode第1号问题
| 定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 |
| |
| 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 |
| |
| 示例: |
| |
| 给定 nums = [2, 7, 11, 15], target = 9 |
| |
| 因为 nums[0] + nums[1] = 2 + 7 = 9 |
| 所以返回 [0, 1] |
第一种解法:把整个数组当做查找表
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| class Solution { |
| public int[] twoSum(int[] nums, int target) { |
| |
| Map<Integer, Integer> mapValIndex = new HashMap<>(); |
| int len = nums.length; |
| for (int i = 0; i < len; i++) { |
| |
| mapValIndex.putIfAbsent(nums[i], i); |
| } |
| int[] result = new int[2]; |
| for (int i = 0; i < len; i++) { |
| Integer index = mapValIndex.get(target - nums[i]); |
| if (index != null && index != i) { |
| |
| result[0] = Math.min(i, index); |
| result[1] = Math.max(i, index); |
| |
| break; |
| } |
| } |
| return result; |
| } |
| |
| public static void main(String[] args) { |
| int[] nums = {7, 3, 3}; |
| int target = 6; |
| int[] result = new Solution().twoSum(nums, target); |
| System.out.println(Arrays.toString(result)); |
| } |
| } |
第2种解法:把遍历过程前面的元素作为查找表,顺便还能保证顺序

| class Solution { |
| public int[] twoSum(int[] nums, int target) { |
| |
| Map<Integer, Integer> mapValIndex = new HashMap<>(); |
| int len = nums.length; |
| for (int i = 0; i < len; i++) { |
| Integer index = mapValIndex.get(target - nums[i]); |
| if (index != null) { |
| |
| return new int[]{index, i}; |
| } |
| |
| mapValIndex.put(nums[i], i); |
| } |
| return new int[0]; |
| } |
| } |
相关的题目:
- 15. 三数之和
a+b = -c
,转化为Two Sum的问题,但是注意这里的TwoSum可能不止有唯一解
| 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。 |
| 注意:答案中不可以包含重复的三元组。 |
| 例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4], |
| |
| 满足要求的三元组集合为: |
| [ |
| [-1, 0, 1], |
| [-1, -1, 2] |
| ] |
| |
| |
| |
| |
| |
| |
| |
| package Chapter03.ThreeSum; |
| |
| import java.util.*; |
| |
| class Solution { |
| |
| |
| |
| |
| |
| |
| |
| public List<int[]> twoSum(int[] nums, int target) { |
| List<int[]> resultList = new ArrayList<>(); |
| |
| Map<Integer, Integer> mapValIndex = new HashMap<>(); |
| int len = nums.length; |
| for (int i = 0; i < len; i++) { |
| Integer index = mapValIndex.get(target - nums[i]); |
| if (index != null) { |
| |
| resultList.add(new int[]{index, i}); |
| } |
| |
| mapValIndex.put(nums[i], i); |
| } |
| return resultList; |
| } |
| |
| |
| |
| |
| |
| |
| |
| public List<List<Integer>> threeSum(int[] nums) { |
| |
| Arrays.sort(nums); |
| Set<List<Integer>> result = new HashSet<>(); |
| if (nums.length < 3) { |
| return new ArrayList<>(); |
| } |
| int len = nums.length; |
| for (int i = 2; i < len; i++) { |
| |
| if (nums[i] == nums[i - 1] && nums[i] == nums[i - 2]) { |
| if (nums[i] == 0) { |
| |
| result.add(new ArrayList<>(Arrays.asList(0, 0, 0))); |
| } |
| |
| continue; |
| } |
| |
| List<int[]> twoSumResultList = twoSum(Arrays.copyOfRange(nums, 0, i), -nums[i]); |
| for (int[] twoSumResult : twoSumResultList) { |
| |
| if (twoSumResult.length == 2) { |
| |
| result.add(Arrays.asList(nums[twoSumResult[0]], nums[twoSumResult[1]], nums[i])); |
| } |
| } |
| } |
| return new ArrayList<>(result); |
| } |
| |
| |
| |
| |
| |
| |
| public static void main(String[] args) { |
| int[] nums = {-4, -2, -2, -2, 0, 1, 2, 2, 2, 3, 3, 4, 4, 6, 6}; |
| List<List<Integer>> lists = new Solution().threeSum(nums); |
| System.out.println(lists); |
| } |
| } |
- 18. 四数之和
| 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。 |
| |
| 注意: |
| |
| 答案中不可以包含重复的四元组。 |
| |
| 示例: |
| 给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。 |
| |
| 满足要求的四元组集合为: |
| [ |
| [-1, 0, 0, 1], |
| [-2, -1, 1, 2], |
| [-2, 0, 0, 2] |
| ] |
| |
| |
| |
| |
| |
| |
| |
| package Chapter03.FourSum; |
| |
| import java.util.*; |
| |
| class Solution { |
| |
| |
| |
| |
| |
| |
| |
| public List<List<Integer>> twoSum(int[] nums, int target) { |
| List<List<Integer>> resultList = new ArrayList<>(); |
| |
| Map<Integer, Integer> mapValIndex = new HashMap<>(); |
| int len = nums.length; |
| for (int i = 0; i < len; i++) { |
| Integer index = mapValIndex.get(target - nums[i]); |
| if (index != null) { |
| |
| resultList.add(new ArrayList<>(Arrays.asList(nums[index], nums[i]))); |
| } |
| |
| mapValIndex.put(nums[i], i); |
| } |
| return resultList; |
| } |
| |
| |
| |
| |
| |
| |
| |
| public List<List<Integer>> threeSum(int[] nums, int target) { |
| |
| Arrays.sort(nums); |
| Set<List<Integer>> result = new HashSet<>(); |
| if (nums.length < 3) { |
| return new ArrayList<>(); |
| } |
| int len = nums.length; |
| for (int i = 2; i < len; i++) { |
| |
| if (nums[i] == nums[i - 1] && nums[i] == nums[i - 2]) { |
| if (nums[i] + nums[i - 1] + nums[i - 2] == target) { |
| |
| result.add(new ArrayList<>(Arrays.asList(nums[i], nums[i - 1], nums[i - 2]))); |
| } |
| |
| continue; |
| } |
| |
| List<List<Integer>> twoSumResultList = twoSum(Arrays.copyOfRange(nums, 0, i), target - nums[i]); |
| for (List<Integer> twoSumResult : twoSumResultList) { |
| |
| if (twoSumResult.size() == 2) { |
| |
| result.add(Arrays.asList(twoSumResult.get(0), twoSumResult.get(1), nums[i])); |
| } |
| } |
| } |
| return new ArrayList<>(result); |
| } |
| |
| |
| public List<List<Integer>> fourSum(int[] nums, int target) { |
| |
| Arrays.sort(nums); |
| Set<List<Integer>> result = new HashSet<>(); |
| if (nums.length < 4) { |
| return new ArrayList<>(); |
| } |
| int len = nums.length; |
| for (int i = 3; i < len; i++) { |
| |
| if (nums[i] == nums[i - 1] && nums[i] == nums[i - 2] && nums[i] == nums[i - 3]) { |
| if (nums[i] + nums[i - 1] + nums[i - 2] + nums[i - 3] == target) { |
| |
| result.add(new ArrayList<>(Arrays.asList(nums[i], nums[i - 1], nums[i - 2], nums[i - 3]))); |
| } |
| |
| continue; |
| } |
| |
| List<List<Integer>> threeSumResultList = threeSum(Arrays.copyOfRange(nums, 0, i), target - nums[i]); |
| for (List<Integer> threeSumResult : threeSumResultList) { |
| |
| if (threeSumResult.size() == 3) { |
| |
| result.add(Arrays.asList(threeSumResult.get(0), threeSumResult.get(1), threeSumResult.get(2), nums[i])); |
| } |
| } |
| } |
| return new ArrayList<>(result); |
| } |
| |
| |
| |
| |
| |
| |
| public static void main(String[] args) { |
| int[] nums = {0, 0, 0, 0}; |
| int target=1; |
| List<List<Integer>> lists = new Solution().fourSum(nums, target); |
| System.out.println(lists); |
| } |
| } |
- 16.最接近的三数之和
| 给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。 |
| 例如,给定数组 nums = [-1,2,1,-4], 和 target = 1. |
| |
| 与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2). |
| |
| |
| |
| |
| |
| |
| |
| package Chapter03.ThreeSumClosest; |
| |
| import java.util.*; |
| |
| class Solution { |
| |
| |
| |
| |
| |
| |
| |
| |
| public List<List<Integer>> twoSum(int[] nums, int target) { |
| List<List<Integer>> resultList = new ArrayList<>(); |
| |
| Map<Integer, Integer> mapValIndex = new HashMap<>(); |
| int len = nums.length; |
| for (int i = 0; i < len; i++) { |
| Integer index = mapValIndex.get(target - nums[i]); |
| if (index != null) { |
| |
| resultList.add(new ArrayList<>(Arrays.asList(nums[index], nums[i]))); |
| } |
| |
| mapValIndex.put(nums[i], i); |
| } |
| return resultList; |
| } |
| |
| |
| |
| |
| |
| |
| |
| public List<List<Integer>> threeSum(int[] nums, int target) { |
| |
| Arrays.sort(nums); |
| Set<List<Integer>> result = new HashSet<>(); |
| if (nums.length < 3) { |
| return new ArrayList<>(); |
| } |
| int len = nums.length; |
| for (int i = 2; i < len; i++) { |
| |
| if (nums[i] == nums[i - 1] && nums[i] == nums[i - 2]) { |
| if (nums[i] + nums[i - 1] + nums[i - 2] == target) { |
| |
| result.add(new ArrayList<>(Arrays.asList(nums[i], nums[i - 1], nums[i - 2]))); |
| } |
| |
| continue; |
| } |
| |
| List<List<Integer>> twoSumResultList = twoSum(Arrays.copyOfRange(nums, 0, i), target - nums[i]); |
| for (List<Integer> twoSumResult : twoSumResultList) { |
| |
| if (twoSumResult.size() == 2) { |
| |
| result.add(Arrays.asList(twoSumResult.get(0), twoSumResult.get(1), nums[i])); |
| } |
| } |
| } |
| return new ArrayList<>(result); |
| } |
| |
| public int threeSumClosest(int[] nums, int target) { |
| int len = nums.length; |
| if (len < 3) { |
| return -1; |
| } |
| if (len == 3) { |
| return nums[0] + nums[1] + nums[2]; |
| } |
| Arrays.sort(nums); |
| int minTarget = nums[0] + nums[1] + nums[2]; |
| int maxTarget = nums[len - 3] + nums[len - 2] + nums[len - 1]; |
| if (target >= maxTarget) { |
| return maxTarget; |
| } |
| if (target <= minTarget) { |
| return minTarget; |
| } |
| |
| int distance = 0; |
| int maxDistance = Math.max(maxTarget - target, target - minTarget); |
| |
| while (distance < maxDistance) { |
| if (target + distance <= maxTarget && threeSum(nums, target + distance).size() != 0) { |
| return target + distance; |
| } |
| if (target - distance >= minTarget && threeSum(nums, target - distance).size() != 0) { |
| return target - distance; |
| } |
| distance++; |
| } |
| return -1; |
| } |
| |
| public static void main(String[] args) { |
| int[] nums = {-1, 2, 1, -4}; |
| int target = 1; |
| System.out.println(new Solution().threeSumClosest(nums, target)); |
| } |
| } |
5 灵活选择键值 454号问题 4Sum#
解题思路:把C+D的组合放入查找表中,通过查找A+B是否等于-(C+D)
| 给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。 |
| |
| 为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500 。所有整数的范围在 -2^28 到 2^28 - 1 之间,最终结果不会超过 2^31 - 1 。 |
| 例如: |
| |
| 输入: |
| A = [ 1, 2] |
| B = [-2,-1] |
| C = [-1, 2] |
| D = [ 0, 2] |
| |
| 输出: |
| 2 |
| |
| 解释: |
| 两个元组如下: |
| 1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0 |
| 2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0 |
| |
| |
| |
| |
| |
| |
| |
| package Chapter04.TwoSum2; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| |
| |
| |
| |
| class Solution { |
| public int fourSumCount(int[] A, int[] B, int[] C, int[] D) { |
| Map<Integer, Integer> record = new HashMap<>(); |
| for (int i = 0; i < C.length; i++) { |
| for (int j = 0; j < D.length; j++) { |
| if (record.get(C[i] + D[j]) == null) { |
| record.put(C[i] + D[j], 1); |
| } else { |
| record.put(C[i] + D[j], record.get(C[i] + D[j]) + 1); |
| } |
| } |
| } |
| int result = 0; |
| for (int i = 0; i < A.length; i++) { |
| for (int j = 0; j < B.length; j++) { |
| if (record.containsKey(-A[i] - B[j])) { |
| result += record.get(-A[i] - B[j]); |
| } |
| } |
| } |
| return result; |
| } |
| |
| public static void main(String[] args) { |
| int[] A = {1, 2}; |
| int[] B = {-2, -1}; |
| int[] C = {-1, 2}; |
| int[] D = {0, 2}; |
| int result = new Solution().fourSumCount(A, B, C, D); |
| System.out.println(result); |
| } |
| } |
类似问题:49. 字母异位词分组
下面的实现行用时 :13 ms, 在所有 Java 提交中击败了66.68%的用户;内存消耗 :40.9 MB, 在所有 Java 提交中击败了96.06%的用户
核心优化:数组或者字符串长度不要单独赋值
| |
| class Solution { |
| public List<List<String>> groupAnagrams(String[] strs) { |
| List<List<String>> result = new ArrayList<>(); |
| Map<String, List<String>> anagramsMap = new HashMap<>(); |
| for (int i = 0; i < strs.length; i++) { |
| char[] chs = strs[i].toCharArray(); |
| Arrays.sort(chs); |
| String strSorted = new String(chs); |
| if (anagramsMap.get(strSorted)==null){ |
| List<String> anagrams = new ArrayList<>(); |
| anagrams.add(strs[i]); |
| anagramsMap.put(strSorted, anagrams); |
| }else { |
| List<String> anagrams = anagramsMap.get(strSorted); |
| anagrams.add(strs[i]); |
| anagramsMap.put(strSorted,anagrams); |
| } |
| } |
| |
| for (String key : anagramsMap.keySet()) { |
| result.add(anagramsMap.get(key)); |
| } |
| return result; |
| } |
| } |
选择距离作为键
| class Solution { |
| |
| |
| |
| int getDistance(int[] p1, int[] p2) { |
| return (p2[0] - p1[0]) * (p2[0] - p1[0]) + (p2[1] - p1[1]) * (p2[1] - p1[1]); |
| } |
| |
| public int numberOfBoomerangs(int[][] points) { |
| int count = 0; |
| for (int i = 0; i < points.length; i++) { |
| |
| Map<Integer, Integer> mapDistancePoints = new HashMap<>(); |
| for (int j = 0; j < points.length; j++) { |
| int distance = getDistance(points[i], points[j]); |
| if (mapDistancePoints.get(distance) == null) { |
| mapDistancePoints.put(distance, 1); |
| } else { |
| mapDistancePoints.put(distance, mapDistancePoints.get(distance) + 1); |
| } |
| } |
| |
| for (Integer distance : mapDistancePoints.keySet()) { |
| int cnt = mapDistancePoints.get(distance); |
| |
| if (cnt > 1) { |
| |
| count += cnt * (cnt - 1); |
| } |
| } |
| } |
| return count; |
| } |
| } |
类似问题:LeetCode第149号问题:直线上最多的点数
坑非常多,同时锻炼价值也很大,用例考察地角度非常多。执行用时 :14 ms, 在所有 Java 提交中击败了81.61%的用户;内存消耗 :36 MB, 在所有 Java 提交中击败了60.83%的用户
| import java.util.HashMap; |
| import java.util.Map; |
| |
| class Solution { |
| |
| public int maxPoints(int[][] points) { |
| int max = 0; |
| if (points.length < 3) { |
| return points.length; |
| } |
| for (int i = 0; i < points.length; i++) { |
| |
| Map<Double, Integer> mapKPoints = new HashMap<>(); |
| |
| int sameCount = 1; |
| for (int j = i + 1; j < points.length; j++) { |
| |
| double k = Integer.MAX_VALUE; |
| if (points[i][1] != points[j][1]) { |
| k = (points[i][0] - points[j][0]) * 1.0 / (points[i][1] - points[j][1]); |
| } else { |
| if (points[i][0] == points[j][0]) { |
| |
| sameCount++; |
| continue; |
| } |
| } |
| |
| k += 0.0; |
| if (mapKPoints.get(k) == null) { |
| mapKPoints.put(k, 1); |
| } else { |
| mapKPoints.put(k, mapKPoints.get(k) + 1); |
| } |
| } |
| |
| for (Double k : mapKPoints.keySet()) { |
| int cnt = mapKPoints.get(k); |
| |
| max = Math.max(cnt + sameCount, max); |
| } |
| |
| max = Math.max(sameCount, max); |
| } |
| return max; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public static void main(String[] args) { |
| int[][] points = {{4, 0}, {4, -1}, {4, 5}}; |
| System.out.println(new Solution().maxPoints(points)); |
| } |
| } |

| 给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的绝对值最大为 k。 |
| 示例 1: |
| 输入: nums = [1,2,3,1], k = 3 |
| 输出: true |
| |
| 示例 2: |
| 输入: nums = [1,0,1,1], k = 1 |
| 输出: true |
| 示例 3: |
| 输入: nums = [1,2,3,1,2,3], k = 2 |
| 输出: false |
| |
| |
| |
| |
| |
| |
| |
| package Chapter04.ContainDuplicate; |
| |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| |
| |
| |
| public class Solution { |
| public boolean containsNearbyDuplicate(int[] nums, int k) { |
| Set<Integer> record = new HashSet<>(); |
| for (int i = 0; i < nums.length; i++) { |
| if (record.contains(nums[i])) { |
| |
| return true; |
| } |
| record.add(nums[i]); |
| |
| if (record.size() == k + 1) { |
| record.remove(nums[i - k]); |
| } |
| } |
| |
| return false; |
| } |
| |
| public static void main(String[] args) { |
| int[] nums = {1, 2, 3, 1}; |
| int k = 3; |
| boolean contain = new Solution().containsNearbyDuplicate(nums, k); |
| System.out.println(contain); |
| } |
| } |
相似的问题:217.存在重复元素,相似的思路,只是不用维护窗口了
| class Solution { |
| public boolean containsDuplicate(int[] nums) { |
| Set<Integer> set = new HashSet(); |
| for(int num : nums){ |
| if(set.contains(num)){ |
| return true; |
| } |
| set.add(num); |
| } |
| return false; |
| } |
| } |
8 二分搜索树底层实现的顺序性 220号问题 Contain Duplicate III#
| 给定一个整数数组,判断数组中是否有两个不同的索引 i 和 j,使得 nums [i] 和 nums [j] 的差的绝对值最大为 t,并且 i 和 j 之间的差的绝对值最大为 ķ。 |
| |
| 示例 1: |
| 输入: nums = [1,2,3,1], k = 3, t = 0 |
| 输出: true |
| 示例 2: |
| |
| 输入: nums = [1,0,1,1], k = 1, t = 2 |
| 输出: true |
| 示例 3: |
| |
| 输入: nums = [1,5,9,1,5,9], k = 2, t = 3 |
| 输出: false |
在上一节的基础上加一个判断即可:在大小为k的窗口中找值差不大于t的即可


| |
| |
| |
| |
| |
| |
| |
| package Chapter04.ContainDuplicate; |
| |
| import java.util.TreeSet; |
| |
| |
| |
| |
| public class Solution { |
| public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) { |
| TreeSet<Integer> record = new TreeSet<>(); |
| for (int i = 0; i < nums.length; i++) { |
| |
| |
| if (record.ceiling(nums[i] - t) != null && record.ceiling(nums[i] - t) <= nums[i] + t){ |
| |
| return true; |
| } |
| record.add(nums[i]); |
| |
| if (record.size() == k + 1) { |
| record.remove(nums[i - k]); |
| } |
| } |
| |
| return false; |
| } |
| |
| public static void main(String[] args) { |
| int[] nums = {1, 2, 3, 1}; |
| int k = 3; |
| int t = 0; |
| boolean contain = new Solution().containsNearbyAlmostDuplicate(nums, k, t); |
| System.out.println(contain); |
| |
| } |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人