【力扣刷题】Day05——哈希表专题


哈希表的应用

当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法

但是哈希法也是牺牲了空间换取了时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。

如果在做面试题目的时候遇到需要判断一个元素是否出现过的场景也应该第一时间想到哈希法!

1. 有效的字母异位词

题目链接:242. 有效的字母异位词 - 力扣(LeetCode)

思路:用一个数组来计数即可,遍历的时候串1的字母个数++串2的字母个数--,最后遍历26个字母,要是cnt都为0说明两个串的字母完全一样,反之有问题。

Code

class Solution {
    public boolean isAnagram(String s, String t) {

        if(s.length() != t.length()) return false;

        int[] cnt = new int[26];
        for(int i = 0; i < s.length(); i ++){
            cnt[s.charAt(i) - 'a'] ++;
            cnt[t.charAt(i) - 'a'] --;
        }
        // 枚举所有字母,看是否都为0,若存在不为0说明两个串有的字母次数不一样 
        for(int i = 0; i < 26; i ++){
            if(cnt[i] != 0)
                return false;
        }
        return true;
    }
}

2. 两个数组的交集

题目链接:349. 两个数组的交集 - 力扣(LeetCode)

思路:开一个哈希表,标记nums1,用于遍历nums2时判断nums2的元素是否在nums1出现过。注意交集是不能含有重复元素的

Code

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        
        boolean[] st = new boolean[1010];
        List<Integer> tmp = new ArrayList<>();

        for(int i = 0; i < nums1.length; i ++) st[nums1[i]] = true;
        for(int i = 0; i < nums2.length; i ++){
            if(st[nums2[i]] == true && !tmp.contains(nums2[i])){// 1在2中出现的 且不能重复
                tmp.add(nums2[i]);
            }
        }
        int[] res = new int[tmp.size()];
        for(int i = 0; i < tmp.size(); i ++) res[i] = tmp.get(i);
        return res;
    }
}

3. 快乐数

题目链接:202. 快乐数 - 力扣(LeetCode)

思路一:哈希表判重

无限循环:那么必定有重复的sum出现,本质就是判重(形成了环)

Code

// 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1
// 无限循环:那么必定有重复的sum出现,本质就是判重(形成了环)

class Solution {
    public boolean isHappy(int n) {
        Set<Integer> set = new HashSet<>();
        while(true){
            int sum = get_sum(n);
            if(sum == 1){
                return true;
            }
            if(set.contains(sum)){
                return false;
            }else {
                set.add(sum);
            }
            // 为下一次准备
            n = sum;
        }
    }
    public static int get_sum(int n){
        int res = 0;
        while(n > 0){
            int t = n % 10;
            res += (t * t);
            n /= 10;
        }
        return res;
    }
}

思路二:快慢指针判断环(环形链表II)

快慢指针从起点开始,快每次走两步,慢每次走一步,当快慢指针第一次相遇(相遇)时,说明就存在了环。此时,判断是不是因为 1 引起的循环,是的话就是快乐数,否则不是快乐数。(要是是1的话,最终快慢的值也都为1,因此最后判断是不是因为 1 引起的循环即可)

Code

// 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1
// 无限循环:那么必定有重复的sum出现,本质就是判重(形成了环)

class Solution {
    public boolean isHappy(int n) {
        int fast = n;
        int slow = n;
        // 要用do-while --- 因为一开始时是一样的
        do {
            fast = get_sum(fast);
            fast = get_sum(fast);
            slow = get_sum(slow);
        }while(fast != slow);
        return fast == 1;
    }
    public static int get_sum(int n){
        int res = 0;
        while(n > 0){
            int t = n % 10;
            res += (t * t);
            n /= 10;
        }
        return res;
    }
}

4. 两数之和

题目链接:1. 两数之和 - 力扣(LeetCode)

思路一:暴力枚举

时间复杂度:O(n * n)

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] res = new int[2];
        int cnt = 0;
        int n = nums.length;
        for(int i = 0; i < n; i ++){
            for(int j = i + 1; j < n; j ++){
                if(nums[i] + nums[j] == target){
                    res[cnt ++] = i;
                    res[cnt ++] = j;
                    break;
                }
            }
        }
        return res;
    }
}

思路二:哈希表

暴力枚举的时间复杂度在于,固定一个x后去找target - x,去找target - x这一操作的时间复杂度是O(n)的,我们可以用哈希表来对找target - x进行优化,使其为O(1)这样总的时间复杂度就从O(n * n) ---> O(n)

  • 对于每一个x,我们判断哈希表中是否存在targrt - x,若存在获取target - x值所对应的key(位置)然后和x的位置直接返回即可
  • 反之将x插入哈希表即可

Code

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer,Integer> mp = new HashMap<>();
        for(int i = 0; i < nums.length; i ++){
            if(mp.containsKey(target - nums[i])){
                return new  int[]{mp.get(target - nums[i]), i};
            }
            mp.put(nums[i], i);
        }
        return new int[0];
    }   
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值