第三章 哈希表part02

67 阅读1分钟

454. 4Sum II

Given four integer arrays nums1nums2nums3, and nums4 all of length n, return the number of tuples (i, j, k, l) such that:

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

题目解析:

  • 暴力四重循环,时间复杂度O(n^4)
  • 使用hashmap存储前两个数组组成的和对应的个数,同理算出后两个的和,即k=4时的求ksum的方法,时间复杂度O(n^2)

代码:

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map<Integer, Integer> map = new HashMap<>();
        for(int v1 : nums1) {
            for (int v2 : nums2) {
                int key = - v1 - v2;
                map.put(key, map.getOrDefault(key, 0) + 1);
            }
        }
        int result = 0;
        for (int v3: nums3) {
            for (int v4: nums4) {
                int key = v3 + v4;
                if (map.containsKey(key)) {
                    result += map.get(key);
                }
            }
        }
        return result;
    }
}

383. Ransom Note

Given two strings ransomNote and magazine, return true if ransomNote can be constructed by using the letters from magazine and false otherwise.

Each letter in magazine can only be used once in ransomNote.

题目解析:

  • 就是比较字符出现的次数,可以用hashmap, 因为字符都为小写英文字符,所以可以使用长度为26的数组来统计,更高效

代码:

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        Map<Character, Integer> map = new HashMap<>();
        for (int i = 0; i < magazine.length(); i++) {
            char key = magazine.charAt(i);
            map.put(key, map.getOrDefault(key, 0) + 1);
        }
        for (int i = 0; i < ransomNote.length(); i++) {
            char key = ransomNote.charAt(i);
            map.put(key, map.getOrDefault(key, 0) - 1);
            if (map.get(key) < 0) {
                return false;
            }
        }
        return true;
    }
}

15. 3Sum

Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != ji != k, and j != k, and nums[i] + nums[j] + nums[k] == 0.

Notice that the solution set must not contain duplicate triplets.

题目解析:

  • hashmap不适合本题,因为题目需要去重,比较麻烦
  • 可以使用排序后双指针,有两个地方需要去重
    • i 指针移动时需要跳过重复的值
    • left和right移动时也需要跳过重复的值(注意,可以与i指针的值重复)

代码:

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > 0) break;
            if (i > 0 && nums[i] == nums[i-1]) continue;
            int left = i + 1, right = nums.length - 1;
            while (left < right) {
                int sum = nums[left] + nums[right] + nums[i];
                if (sum == 0) {
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    left++;
                    right--;
                } else if (sum < 0) {
                    left++;
                } else {
                    right--;
                }
                while (left < right && left > i + 1 && nums[left] == nums[left-1]) left++;
                while(left < right && right < nums.length - 1 && nums[right] == nums[right+1]) right--;
            }
        }
        return result;
    }
}

18. 4Sum

Given an array nums of n integers, return an array of all the unique quadruplets [nums[a], nums[b], nums[c], nums[d]] such that:

  • 0 <= a, b, c, d < n
  • abc, and d are distinct.
  • nums[a] + nums[b] + nums[c] + nums[d] == target

You may return the answer in any order.

题目解析:

  • 与上一题类型,两重循环+双指针,每一层循环都需要去重
  • 多个整数相加可以超过integer的范围,所以需要使用long
  • 这题不能剪枝,因为target不等于0

代码:

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            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 sum = (long)nums[i] + nums[j] + nums[left] + nums[right];
                    if (sum < target) {
                        left++;
                    } else if (sum > target) {
                        right--;
                    } else {
                        result.add(Arrays.asList(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;
    }
}

总结

  • 多数之和求个数和求组合的解决方法不一样