作业题
454. 四数相加 II
package jjn.carl.hashtable; import java.util.HashMap; import java.util.Map; /** * @author Jiang Jining * @since 2023-07-04 21:33 */ public class LeetCode454 { public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) { Map<Integer, Integer> map = new HashMap<>(); int res = 0; for (int first : nums1) { for (int second : nums2) { map.put(first + second, map.getOrDefault(first + second, 0) + 1); } } for (int third : nums3) { for (int fourth : nums4) { res += map.getOrDefault(-third - fourth, 0); } } return res; } public static void main(String[] args) { int[] nums1 = new int[]{1, 2}; int[] nums2 = new int[]{-2, -1}; int[] nums3 = new int[]{-1, 2}; int[] nums4 = new int[]{0, 2}; int fourSumCount = new LeetCode454().fourSumCount(nums1, nums2, nums3, nums4); System.out.println("fourSumCount = " + fourSumCount); } }
383. 赎金信
package jjn.carl.hashtable; /** * @author Jiang Jining * @since 2023-07-04 21:45 */ public class LeetCode383 { public boolean canConstruct(String ransomNote, String magazine) { int[] charCount = new int[26]; for (char c : ransomNote.toCharArray()) { charCount[c - 'a']++; } for (char c : magazine.toCharArray()) { charCount[c - 'a']--; } for (int j : charCount) { if (j > 0) { return false; } } return true; } public static void main(String[] args) { String ransomNote = "aa", magazine = "aab"; boolean canConstruct = new LeetCode383().canConstruct(ransomNote, magazine); System.out.println("canConstruct = " + canConstruct); } }
15. 三数之和
package jjn.carl.hashtable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * @author Jiang Jining * @since 2023-07-04 22:13 */ public class LeetCode15 { public List<List<Integer>> threeSum(int[] nums) { Arrays.sort(nums); List<List<Integer>> result = new ArrayList<>(); for (int i = 0; i < nums.length - 2; i++) { if (nums[i] > 0) { return result; } if (i > 0 && nums[i] == nums[i - 1]) { continue; } int left = i + 1, right = nums.length - 1; while (left < right) { if (nums[left] + nums[right] + nums[i] < 0) { left++; } else if (nums[left] + nums[right] + nums[i] > 0) { right--; } else { result.add(List.of(nums[i], nums[left], nums[right])); while (left < right && nums[right] == nums[right - 1]) { right--; } while (left < right && nums[left] == nums[left + 1]) { left++; } left++; right--; } } } return result; } public static void main(String[] args) { int[] nums = new int[]{-1, 0, 1, 2, -1, -4}; List<List<Integer>> threeSum = new LeetCode15().threeSum(nums); System.out.println("Arrays.toString(threeSum) = " + threeSum.toString()); } }
18. 四数之和
package jjn.carl.hashtable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * @author Jiang Jining * @since 2023-07-04 23:10 */ public class LeetCode18 { public List<List<Integer>> fourSum(int[] nums, int target) { // 排序很关键,是双指针法的前提 Arrays.sort(nums); long res = 0L; List<List<Integer>> result = new ArrayList<>(); for (int i = 0; i < nums.length - 3; i++) { // target 可以为负数,负数相加会变得更小 if (nums[i] > 0 && nums[i] > target && target >= 0) { return result; } 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, right = nums.length - 1; while (left < right) { // 防止加法越界 long cur = (long) nums[i] + (long) nums[j] + (long) nums[left] + (long) nums[right]; if (cur < target) { left++; } else if (cur > target) { right--; } else { result.add(List.of(nums[i], nums[j], nums[left], nums[right])); while (left < right && nums[left] == nums[left + 1]) { left++; } while (left < right && nums[right] == nums[right - 1]) { right--; } left++; right--; } } } } return result; } public static void main(String[] args) { int[] nums = new int[]{1, 0, -1, 0, -2, 2}; int target = 0; List<List<Integer>> fourSum = new LeetCode18().fourSum(nums, target); System.out.println("fourSum = " + fourSum); // Case two nums = new int[]{2, 2, 2, 2, 2, 2}; target = 8; fourSum = new LeetCode18().fourSum(nums, target); System.out.println("fourSum = " + fourSum); // 非常猥琐的测试用例 nums = new int[]{1000000000, 1000000000, 1000000000, 1000000000}; target = -294967296; fourSum = new LeetCode18().fourSum(nums, target); System.out.println("fourSum = " + fourSum); } }
总结
- 某些场景用数组非常合适,如只会有小写的字母等,采用哈希表速度可能不如数组快;输入的数据可能性没有限制,则只能用哈希表;
- N 数之和,基本思路:确定左边的数,留下最后两个,用双指针不断收缩,求解答案,难点在于去重。