zoukankan      html  css  js  c++  java
  • 【40讲系列4】哈希表

    一、理论

    Hash冲突及解决:关键字不同的元素映射到同样地址时会产生hash冲突,解决方法有:开放定址法(探测序列)、再哈希法、链地址法。

    HashMap、HashSet-------->哈希表的查找、插入、删除的平均复杂度为O(1),

    TreeMap、TreeSet-------->二叉搜索树的查找、插入、删除的平均复杂度为O(logn),但有序。

    二、典型例题

    ①:判断有效的字母异位词(LC242)

    方法1:按字典序排序——O(nlogn)

    方法2:哈希表——O(n)

    由于仅字符串仅包含小写字母,因此可以用数组实现简易哈希表。

    class Solution {
        public boolean isAnagram(String s, String t) {
            if (s.length() != t.length()) return false;
            // 方法1:排序
            /*
            char[] chars1 = s.toCharArray();
            Arrays.sort(chars1);
            char[] chars2 = t.toCharArray();
            Arrays.sort(chars2);
            return Arrays.equals(chars1,chars2);// 注意此方法哦
            */
    
            // 方法2:哈希表
            // -------写法1
            /*int[] counts = new int[26];
            for (int i = 0; i < s.length(); i++) {
                counts[s.charAt(i) - 'a']++;
                counts[t.charAt(i) - 'a']--;
            }
            for (int count : counts){
                if (count != 0){
                    return false;
                }
            }
            return true;*/
            // ---------写法2
            int[] counts = new int[26];
            for (char c : s.toCharArray()){
                counts[c - 'a']++;
            }
            for (char c : t.toCharArray()){
                counts[c - 'a']--;
                if (counts[c - 'a'] < 0){
                    return false;
                }
            }
            return true;
        }
    }

    ②:找出数组中和为目标值的两个数(LC01)、三个数(LC15)、四个数(LC18)

    -------->两数之和

    class Solution {
        // 两数之和
        public int[] twoSum(int[] nums, int target) {
            HashMap<Integer,Integer> map = new HashMap<>();
            for (int i = 0; i < nums.length; i++) {
                if (map.containsKey(target - nums[i])){
                    return new int[]{map.get(target - nums[i]),i};
                }
                map.put(nums[i],i);
            }
            return new int[0];
        }
    }

    -------->三数之和

    方法1:使用哈希表。类似于两数之和,a = - (b+c),分别枚举b和c,查询 - (b+c)是否在Set中存在。 相当于省了一层循环,时间复杂度为O(n^2)。

    (不好实现。。。)

    ☆☆☆☆方法2:先排序,再双指针查找。 需要注意去重!

    class Solution {
        public List<List<Integer>> threeSum(int[] nums) {
            List<List<Integer>> res = new ArrayList<>();
            if (nums == null || nums.length < 3) return res;
            Arrays.sort(nums); // 排序
    
            for (int i = 0; i < nums.length - 2; i++) {
                if (nums[i] > 0) break; // 如果当前数组大于0,则三数之和一定大于0
                if (i > 0 && nums[i] == nums[i-1]) continue; // 去重
                int start = i+1;
                int end = nums.length - 1;
                while (start < end){
                    int tempSum = nums[i] + nums[start] + nums[end];
                    if (tempSum > 0){
                        end--;
                    }else if (tempSum < 0){
                        start++;
                    }else{
    //                    ArrayList<Integer> list = new ArrayList<>();
    //                    list.add(nums[i]);
    //                    list.add(nums[start]);
    //                    list.add(nums[end]);
    //                    res.add(list);
                        res.add(Arrays.asList(nums[i],nums[start],nums[end]));
                        while (start < end && nums[end] == nums[end-1]) end--;       // 去重
                        while (start < end && nums[start] == nums[start+1]) start++; // 去重
                        start++;
                        end--;
                    }
                }
            }
            return res;
        }
    }

    --------->四数之和

    M,以后补上

    三、扩展例题—查找表相关问题

    第一组(set和map的使用):LeetCode349、350. 两个数组的交集LeetCode136. 只出现一次的数字LeetCode242. 有效的字母异位词LeetCode202. 快乐数LeetCode290. 单词规律LeetCode205. 同构字符串LeetCode451. 根据字符出现频率排序

    第二组(经典问题N数之和):LeetCode1. 两数之和LeetCode15. 三数之和LeetCode18. 四数之和LeetCode16. 最接近的三数之和

    第三组(灵活选择键值):LeetCode454. 四数相加 IILeetCode49. 字母异位词分组

    第四组(灵活选择键值):LeetCode447. 回旋镖的数量LeetCode149. 直线上最多的点数LeetCode719. 找出第 k 小的距离对

    第五组(查找表+滑动窗口):LeetCode219. 存在重复元素 II

    第六组(有序查找表):LeetCode220. 存在重复元素 III

  • 相关阅读:
    mysql 版本查看
    js 中文乱码
    浏览器内核
    Squid 代理服务器
    minicygwin
    firefox 插件开发
    ocx c++
    NetBeans
    android 虚拟机
    ExpandableListView
  • 原文地址:https://www.cnblogs.com/HuangYJ/p/14012005.html
Copyright © 2011-2022 走看看