• 【代码随想录】哈希表专栏(Java)


    理论

    哈希表是根据关键码的值而直接进行访问的数据结构。也称为散列表

    数组就是一个哈希表。

    需要快速判断一个元素是否出现在集合里面时,需要考虑使用哈希法。

    有效的字母异位词 leetcode-242

    /**
         * leetcode-242. 有效的字母异位词
         * @param s
         * @param t
         * @return
         */
    public boolean isAnagram(String s, String t) {
        int[] sArray = new int[26]; //默认是0
        for(char c : s.toCharArray()){
            sArray[c-'a']++;
        }
        for(char c : t.toCharArray()){
            sArray[c-'a']--;
        }
        for (int i = 0; i < sArray.length; i++) {
            if(sArray[i] != 0){ //若有元素不为0,则两者中每种字符的个数有差异,多或少
                return false;
            }
        }
        return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    赎金信 leetcode-383

    /**
         * leetcode-383 赎金信
         * @param ransomNote
         * @param magazine
         * @return
         */
    public boolean canConstruct(String ransomNote, String magazine) {
        int[] ransomArray = new int[26]; //默认是0
        for(char c : ransomNote.toCharArray()){
            ransomArray[c-'a']++;
        }
        for(char c : magazine.toCharArray()){
            if(ransomArray[c-'a'] != 0){ //只统计ransom中有的字母
                ransomArray[c-'a']--;
            }
        }
        for (int i = 0; i < ransomArray.length; i++) {
            if(ransomArray[i] != 0){
                return false;
            }
        }
        return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    字母异位词分组 leetcode-49

    /**
         * 字母异位词分组
         * @param strs
         * @return
         */
    public List<List<String>> groupAnagrams(String[] strs) {
        Map<String,List<String>> map = new HashMap<String, List<String>>();
        for (String str : strs) {
            char[] cArray = str.toCharArray();
            Arrays.sort(cArray); //给字符数组排序(位置虽然不同,但排序后一定是相同的)
            String key = new String(cArray);
            List<String> list = map.getOrDefault(key, new ArrayList<String>());
            list.add(str);
            map.put(key,list); //java中的map在键相同时会直接抵消
        }
        return new ArrayList<List<String>>(map.values());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    找到字符串中所有字母异位词 leetcode-438

    方法1:

    /**
         * 438. 找到字符串中所有字母异位词
         * (易于理解,但时间复杂度高)
         *
         * @param s
         * @param p
         * @return
         */
    public List<Integer> findAnagrams(String s, String p) {
        char[] sArray = s.toCharArray();
        char[] pArray = p.toCharArray();
        int[] charArray = new int[26];
        for (char c : pArray) {
            charArray[c - 'a']++;
        }
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < sArray.length; i++) {
            if (i > sArray.length - pArray.length) break;
            int temp[] = Arrays.copyOf(charArray, charArray.length); //数组是对象,不能直接赋值
            boolean flag = true;
            for (int j = i; j < i + pArray.length; j++) {
                temp[sArray[j] - 'a']--;
            }
            for (int k = 0; k < temp.length; k++) {
                if (temp[k] != 0) {
                    flag = false;
                }
            }
            if (flag) list.add(i);
        }
        return list;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    方法2:滑动窗口

    /**
         * 438. 找到字符串中所有字母异位词
         * 滑动窗口
         * 时间 9 ms击败 61.47%
         * @param s
         * @param p
         * @return
         */
    public List<Integer> findAnagrams2(String s, String p) {
        int sLen = s.length();
        int pLen = p.length();
        if (sLen < pLen) return new ArrayList<>();
        int[] needs = new int[26];
        int[] window = new int[26];
        for (char c : p.toCharArray()) {
            needs[c - 'a']++;
        }
        int count = 0;
        for (int i = 0; i < needs.length; i++) { //统计needs的实际大小 例如“aa”,实际大小为1
            if (needs[i] != 0) count++;
        }
        List<Integer> list = new ArrayList<>();
        int left = 0, right = 0, valid = 0;
        while (right < s.length()) {
            char c = s.charAt(right);
            right++;
            if (needs[c - 'a'] != 0) {
                window[c - 'a']++;
                if (window[c - 'a'] == needs[c - 'a']) {
                    valid++;
                }
            }
    
            if (right - left == p.length()) {
                if (valid == count) {
                    list.add(left);
                }
                char d = s.charAt(left);
                left++;
                if (needs[d - 'a'] > 0) {
                    if (window[d - 'a'] == needs[d - 'a']) {
                        valid--;
                    }
                    window[d - 'a']--;
                }
            }
    
        }
        return list;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    方法3:速度最快,完全匹配(顺序不考虑),窗口大小固定,个人认为这种方法更好理解

    /**
         * 438. 找到字符串中所有字母异位词
         * 把窗口大小固定更易于理解
         *
         * @param s
         * @param p
         * @return
         */
    public List<Integer> findAnagrams3(String s, String p) {
        int sLen = s.length();
        int pLen = p.length();
        if (sLen < pLen) return new ArrayList<>();
        int[] needs = new int[26];
        int[] window = new int[26];
        for (int i = 0; i < pLen; i++) {
            needs[p.charAt(i)-'a']++;
            window[s.charAt(i)-'a']++;
        }
        List<Integer> list = new ArrayList<>();
        int left = 0, right = pLen - 1;
        if (Arrays.equals(needs, window)) list.add(0); //可能0下标就相同
        while (right < sLen-1) { //下面right往后移动,这里要减1,不然下面数组越界
            //右边界往后移
            right++;
            window[s.charAt(right) - 'a']++;
            //左边界往后移
            window[s.charAt(left) - 'a']--;
            left++;
            if (Arrays.equals(needs, window)) {
                list.add(left);
            }
        }
        return list;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    两个数组的交集 leetcode-349

    方法1:

    /**
         * 349. 两个数组的交集
         * 时间
         * 1 ms
         * 击败
         * 98.73%
         * @param nums1
         * @param nums2
         * @return
         */
    public int[] intersection(int[] nums1, int[] nums2) {
        int[] arr2 = new int[1000];
        int[] ans = new int[1000];
        for (int i : nums2) {
            arr2[i]++;
        }
        int size = 0;
        for (int i = 0; i < nums1.length; i++) {
            if(arr2[nums1[i]] != 0 && ans[nums1[i]] ==0){
                ans[nums1[i]]++;
                size++;
            }
        }
        int[] res = new int[size];
        int index = 0;
        for (int i = 0; i < ans.length; i++) {
            if(ans[i]!=0){
                res[index++]=i;
            }
        }
        return res;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    方法2:

    /**
         * 时间
         * 0 ms
         * 击败
         * 100%
         * @param nums1
         * @param nums2
         * @return
         */
    public int[] intersection2(int[] nums1, int[] nums2) {
        int[] map = new int[1000];
        List<Integer> list = new ArrayList<>(); //因为不知道结果数组有多大,所以先用list存
        for (int i : nums1) {
            map[i]++;
        }
        for (int i : nums2) {
            if(map[i] != 0){
                list.add(i);
                map[i] = 0;  //删除索引,防止有相同元素时,重复添加
            }
        }
        int[] ans = new int[list.size()];
        for (int i = 0; i < list.size(); i++) {
            ans[i] = list.get(i);
        }
        return ans;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    两个数组的交集 II leetcode-350

    /**
         ** 时间
         * 0 ms
         * 击败
         * 100%
         * 350. 两个数组的交集 II 与上一题相比,该题可以统计重复的,但是两个数组中元素重复的次数不一样时,取小
         * @param nums1
         * @param nums2
         * @return
         */
    public int[] intersect(int[] nums1, int[] nums2) {
        int[] map = new int[1001];
        for (int i : nums1) {
            map[i]++;
        }
        int[] ans = new int[Math.max(nums1.length, nums2.length)];
        int j = 0;
        for (int i : nums2) {
            if(map[i] > 0){
                ans[j++] = i;
                map[i]--;  //索引减1
            }
        }
        return Arrays.copyOfRange(ans, 0, j);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    快乐数 leetcode-202

    方法1:

    /**
         * 202 快乐数
         * 用时1ms
         * @param n
         * @return
         */
    public boolean isHappy(int n){
        Set<Integer> set = new HashSet<>();
        while ( n!=1 && !set.contains(n)){
            set.add(n);
            n = nextNum(n);
        }
        return n==1;
    }
    public int nextNum(int n){
        int sum = 0;
        while (n > 0){
            int temp = n%10;
            sum+=temp*temp;
            n=n/10;
        }
        return sum;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    方法2:

    public boolean isHappy2(int n){
        int slow = n,fast = n; //类比于链表找环,设置快慢指针
        do{
            slow = nextNum(slow);
            fast = nextNum(fast);
            fast = nextNum(fast);
        }while (slow != fast);
        return slow  == 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    两数之和 leetcode-1

    /**
         * 两数之和 leetcode-1
         * @param nums
         * @param target
         * @return
         */
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();
        int[] res = new int[2];
        int i;
        for (i = 0; i < nums.length; i++) {
            int temp = target - nums[i];
            if (!map.containsKey(temp)) {
                map.put(nums[i], i);
            } else {
                res[0] = i;
                res[1] = map.get(temp);
                break;
            }
        }
        return res;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    四数相加II leetcode-454

    /**
         * 四数相加
         * @param nums1
         * @param nums2
         * @param nums3
         * @param nums4
         * @return
         */
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map<Integer,Integer> map1 = new HashMap<>();
        for (int i : nums1) {
            for (int j : nums2) {
                map1.put(i+j,map1.getOrDefault(i+j,0)+1); //统计任意两个数和的次数
    
            }
        }
    
        int count = 0;
        for (int i : nums3) {
            for (int j : nums4) {
                int temp = 0-(i+j);
                if(map1.containsKey(0-(i+j))){
                    count+=map1.get(0-(i+j));
                }
            }
        }
        return count;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    三数之和 leetcode-15

    /**
         * 三数之和 leetcode-15
         * @param nums
         * @return
         */
    public List<List<Integer>> threeSum(int nums[]) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);
    
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > 0) return res;
            if (i >0 && nums[i] == nums[i - 1]) continue; //去重
    
            int left = i+1,right = nums.length-1;
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                if(sum >0){
                    right--;
                } else if (sum < 0) {
                    left++;
                }else{
                    res.add(Arrays.asList(nums[i],nums[left],nums[right]));
                    while (left <right && nums[left] == nums[left + 1]) {
                        left++;
                    }
                    while (left <right && nums[right] == nums[right - 1]) {
                        right--;
                    }
                    right--;
                    left++;
                }
    
            }
        }
        return res;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    四数之和 leetcode-18

    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> list = new ArrayList<>();
        Arrays.sort(nums);
    
        for (int i = 0; i < nums.length - 3; i++) {
            if (nums[i] > 0 && nums[i] > target) {
                return list;
            }
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;  //去重
            }
    
            for (int j = i + 1; j < nums.length - 2; j++) {
                if (j > i + 1 && nums[j] == nums[j - 1]) {
                    continue; // 超过i+1才属于j的部分
                }
    
                int left = j + 1, right = nums.length - 1;
                while (left < right) {
                    int sum = nums[i] + nums[j] + nums[left] + nums[right];
                    if (sum < target) {
                        left++;
                    } else if (sum > target) {
                        right--;
                    } else {
                        list.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
                        left++;
                        while (left < right && nums[left] == nums[left - 1]) {
                            left++;
                        }
                        right--;
                        while (left < right && nums[right] == nums[right + 1]) {
                            right--;
                        }
                    }
                }
            }
        }
        return list;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
  • 相关阅读:
    深度解读GPT基本原理
    Redis+Caffeine两级缓存,让访问速度纵享丝滑
    python计算长方形面积 青少年编程电子学会python编程等级考试一级真题解析2022年6月
    1.8 Elasticsearch建立IK中文分词器
    在Linux上部署Servlet程序
    抖音上货API订单API:自动化上架商品批量获取商品详情信息
    ubuntu搭建sftp服务
    ON1 Photo RAW 2024照片编辑器「Mac」
    Unity UGUI的Image(图片)组件的介绍及使用
    新时代高效记账:自动化智能如何进行财务管理
  • 原文地址:https://blog.csdn.net/qq_45178685/article/details/127885495