哈希表专题刷题总结

哈希表是用来快速判断一个元素是否出现在集合里。
常用的有三种结构:

  • 数组
  • set
  • Map
    具体使用哪一种需要根据实际情况判断。

第一类:使用数组作为hash表

题目链接: 242. 有效的字母异位词
因为本题在题目说明中,限定字符的种类仅为小写字母,种类数是固定的,可以使用数组来作为map

class Solution {
    public boolean isAnagram(String s, String t) {
        int[] map = new int[26];
        //遍历s字符串,记录每个字符出现的次数
        for(int i = 0;i < s.length();i++){
            map[s.charAt(i)-'a']++;
        }
        //判断t中的每个字符出现的次数,这里使用减的操作就只需要使用一个map了
        for(int i = 0;i < t.length();i++){
            map[t.charAt(i)-'a']--;
        }
        //如果不相同,则不是异位词
        for(int i = 0;i < map.length;i++){
             if(map[i] != 0 ){
                return false;
            }
        }
        return true;
    }
}

题目链接:383.赎金信
因为本题在题目说明中,限定字符的种类仅为小写字母,种类数是固定的,可以使用数组来作为map

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        //定义一个数组作为哈希表
        int[] map = new int[26];
        //统计magazine中每个字符出现的次数
        for(int i = 0;i < magazine.length();i++){
            map[magazine.charAt(i)-'a']++;
        }
        //统计ransomNote中每个字符出现的次数
        for(int i = 0;i < ransomNote.length();i++){
            map[ransomNote.charAt(i)-'a']--;
            //说明ransomNote中出现了magazine中没有的字符,或者次数已经超过了magazine中出现的次数
            if(map[ransomNote.charAt(i)-'a'] < 0){
                return false;
            }
        }
        return true;
    }
}

第二类:使用set作为哈希表

题目链接: 349 两个数组的交集

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        //首先判断两个数组的长度,先统一换为num1 < num2
        if(nums1.length > nums2.length){
            return intersection(nums2,nums1);
        }
        // 因为题目中要求输出结果中的每一个元素一定是唯一的,所有使用set集合
        Set<Integer> set = new HashSet<>();
        //记录num1中出现的数字
        for(int num : nums1){
            set.add(num);
        }
        //定义结果数组,这种方式还是会存在重复元素
        // int[] res = new int[nums1.length];
        // int index = 0;
        // //判断num2中的元素是否在集合中出现
        // for(int num : nums2){
        //     if(set.contains(num)){
        //         res[index++] = num;
        //     }
        // }
        // return Arrays.copyOf(res,index);
        Set<Integer> set2 = new HashSet<>();
        for(int num : nums2){
            if(set.contains(num)){
                set2.add(num);
            }
        }
        //这种方式也可以使用set直接转为数组进行简化
        // int[] res = new int[set2.size()];
        // int i = 0;
        // for(int num : set2){
        //     res[i++] = num;
        // }
        return set2.stream().mapToInt(x->x).toArray();
    }
}

题目链接:202.快乐数

class Solution {
    public boolean isHappy(int n) {
        //如果出现重复的数字那也就是进入无限循环了,直接返回false就可
        Set<Integer> set = new HashSet<>();
        n = getNext(n);
        while(!set.contains(n) && n != 1){
            set.add(n);
            n = getNext(n);
        }

        // if(n == 1){
        //     return true;
        // }else{
        //     return false;
        // }

        //上述代码可以简化为以下代码
        return n == 1;
    }
    //统计每个位置上的数字的平方和
    public int getNext(int n){
        int res = 0;
        while(n > 0){
            res += (n % 10)*(n%10);
            n = n / 10;
        }
        return res;
    }
}

map作为哈希表

题目链接:1 两数之和

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer,Integer> map = new HashMap<>(); 
        int[] res = new int[2];
        for(int i = 0;i < nums.length;i++){
        	//使用map判断之前是否出现过和当前数字相加为target的数字和下标
            int tmp = target - nums[i];
            if(map.containsKey(tmp)){
                res[0] = map.get(tmp);
                res[1] = i;
            }
            map.put(nums[i],i);
        }
        return res;
    }
}

题目链接:454.四数相加II
这道题与两数之和的思路是一样的,不过是map里存储的是num1与num2中元素之和以及出现的次数。

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map<Integer,Integer> map = new HashMap<>();
        int count = 0;
        for(int a : nums1){
            for(int b : nums2){
                int sum = a + b;
                map.put(sum,map.getOrDefault(sum,0)+1);
            }
        }
        for(int c : nums3){
            for(int d : nums4){
                int target = 0 - c - d;
                if(map.containsKey(target)){
                    count += map.get(target);
                }
            }
        }
        return count;
    }
}

题目链接:18. 四数之和
关键差别是上一个题目为四个独立的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不用考虑重复问题,而18. 四数之和一个数组(集合)里找到和为0的组合,需要考虑去重的问题,所以使用双指针法来做更加合适!!!

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        //建立一个结果数组
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);
        //本题使用双指针法来做更加合适
        for(int i = 0;i < nums.length;i++){
            //剪枝
            if(nums[i] > target && nums[i] >= 0){
                break;
            }
            //去重
            if(i > 0 && nums[i] == nums[i-1]){
                continue;
            }
            for(int k = i+1;k < nums.length;k++){
                if(nums[k] + nums[i] > target && nums[k] + nums[i] >= 0){
                    break;
                }
                if(k > i+1 && nums[k] == nums[k-1]){
                    continue;
                }
                int left = k + 1,right = nums.length-1;
                while(right > left){
                    int sum = nums[i] + nums[k] + nums[left] + nums[right];
                    if(sum > target) right--;
                    else if(sum < target) left++;
                    else{
                        res.add(Arrays.asList(nums[i],nums[k],nums[left],nums[right]));
                        //去重
                        while(right > left && nums[right] == nums[right-1]) right--;
                        while(right > left && nums[left] == nums[left + 1]) left++;
                        right--;
                        left++;
                    }
                }
            }
        }
        return res;
    }
}

题目链接:15 三数之和
本题和18四数之和基本是一致的。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);
        if(nums[0] > 0){
            return res;
        }
        for(int i = 0;i < nums.length;i++){
            //去重
            if(i > 0 && nums[i] == nums[i-1]){
                continue;
            }
            int left = i + 1,right = nums.length - 1;
            while(right > left){
                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(right > left && nums[right] == nums[right-1]) right--;
                    while(right > left && nums[left] == nums[left+1] ) left++;
                    right--;
                    left++;
                }
            }
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值