Day7 哈希表 part2

9

四数相加

四数相加 II

HashMap 存一个数组,如 A。然后计算三个数组之和,如 BCD。时间复杂度为:O(n)+O(n^3),得到 O(n^3).

HashMap 存三个数组之和,如 ABC。然后计算一个数组,如 D。时间复杂度为:O(n^3)+O(n),得到 O(n^3).

HashMap存两个数组之和,如AB。然后计算两个数组之和,如 CD。时间复杂度为:O(n^2)+O(n^2),得到 O(n^2).

我们以存 AB 两数组之和为例。首先求出 A 和 B 任意两数之和 sumAB,以 sumAB 为 key,sumAB 出现的次数为 value,存入 hashmap 中。

然后计算 C 和 D 中任意两数之和的相反数 sumCD,在 hashmap 中查找是否存在 key 为 sumCD。

    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        HashMap<Integer, Integer> result = new HashMap<>();
        int count = 0;
        for (int i = 0; i < nums1.length; i++) {
            for (int j = 0; j < nums2.length; j++) {
                int sumAB = nums1[i] + nums2[j];
                if (result.containsKey(sumAB)) {
                    result.put(sumAB, result.get(sumAB) + 1);
                } else {
                    result.put(sumAB, 1);
                }
            }
        }

        for (int i = 0; i < nums3.length; i++) {
            for (int j = 0; j < nums4.length; j++) {
                int sumCD = nums3[i] + nums4[j];
                if (result.containsKey(-sumCD)) {
                    count += result.get(-sumCD);
                }
            }
        }
        return count;
    }

赎金信

赎金信

用一个长度为26的数组来记录magazine里字母出现的次数。

然后再用ransomNote 去验证这个数组是否包含了ransomNote 所需要的所有字母。

千万注意,magazine肯定是更长的,并且类似于字典,我们是统计他字母出现次数,后面需要的才能从里面减少

    public boolean canConstruct(String ransomNote, String magazine) {
        //题意条件 1 <= ransomNote.length, magazine.length <= 105
        if (ransomNote.length() > magazine.length()) {
            return false;
        }
        //不用map,因为空间开销大,用数组,储存a~z
        int[] record = new int[26];
        //遍历,统计字母出现次数
        for (int i = 0; i < magazine.length(); i++) {
            int index = magazine.charAt(i) - 'a';
            record[index] += 1;
        }
        for (int i = 0; i < ransomNote.length(); i++) {
            int index = ransomNote.charAt(i) - 'a';
            record[index] -= 1;
        }
        // 如果数组中存在负数,说明ransomNote字符串中存在magazine中没有的字符
        for (int i : record) {
            if (i < 0) {
                return false;
            }
        }
        return true;
    }

三数之和

固定最小元素指针k,i和j两个指针取值范围在(k,nums.length)两端

要注意如果nums[k]>0,那么就不可能有结果直接结束即可。因为nums[j]>nums[i]>nums[k]

然后开始移动,需要注意去重,当k>0并且nums[k-1]==nums[k]的时候,保留nums[k]就可以了

总和是小于0的,所以i指针不断右移

继续右移,此时i和j相等了,所以不行。

k右移,i重新回到k+1位置,j来到nums.length-1位置

遇到重复的元素,跳过。此时和为0,记录k i j位置,然后跳过重复的元素,i右移,j左移

继续右移

i和 j相等,不合题意,继续

总和大于0,j左移,此时i等于j