【LeetCode刷题记录】 热题 100 —— 哈希

LeetCode 热题 100 —— 哈希

1. 两数之和

题目链接

这道题的暴力解法相信看到这题的所有人都能想到,使用双重 for 循环进行枚举,算出所有的结果。

    // 暴力解法
    public int[] twoSum(int[] nums, int target) {
        for (int i = 0; i < nums.length; i++) {
            for (int j = i + 1; j < nums.length; j++) {
                if (nums[i] + nums[j] == target) {
                    int[] result = {i, j};
                    return result;
                }
            }
        }
        return null;
    }

提交发现耗时还是有些长,并且当前的在热题100的分类中,这道题被分在了哈希,那么很明显这一题可以使用哈希表解决。

在这一题中,对于每一个元素 n ,都存在一个另一个数,使他们求和可以得到目标值,那个数就是差 diff。而这个差也需要在数组里找,所以将数组里全部的数存到 HashMap 中。遍历 nums 数组,判断当前元素和目标值的差是否在哈希表中,由于一个数不能重复使用,在判断的时候需要判断下标,这样就只需要通过一次 for 循环算出题目的结果。

    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer, Integer> map = new HashMap();
        int[] result = new int[2];
        for (int i = 0; i < nums.length; i++) {
            map.put(nums[i], i);
        }
        for (int i = 0; i < nums.length; i++) {
            int diff = target - nums[i];
            if (map.containsKey(diff) && (Integer)map.get(diff) != i) {
                result[0] = i;
                result[1] = map.get(diff);
                return result;
            }
        }
        return result;
    }

49. 字母异位词分组

题目链接

如果没有做过 242. 有效的字母异位词 建议先做242这一题。

看到这一题第一反应也是相同的思路,把每个单词的字符出现次数记录到数组,相同的数组就是异位词。然后将这个数组作为 哈希表 的 key,值就是一个 List<String> 里面存放单词。

    public List<List<String>> groupAnagrams(String[] strs) {
        Map<int[], List<String>> map = new HashMap<>();
        for(String str : strs) {
            int[] letter = new int[26];
            for (char c : str.toCharArray()) {
                letter[c - 'a'] ++;
            }
            List<String> list;
            if (!map.containsKey(letter)) {
                list = new ArrayList();
            } else {
                list = map.get(letter);
            }
            list.add(str);
            map.put(letter, list);
        }
        List<List<String>> result = new ArrayList<>();
        map.forEach((k, v) -> result.add(v));
        return result;
    }

运行发现,每个单词都分成了一组。想了一下,应该是key保存的并不是letter的值,而是他的内存地址。然后就思考怎么才能把数组保存成key,想到了 Arrays.toString() 方法,把数组转成字符串,这样就可以把值作为哈希的key了

    public List<List<String>> groupAnagrams(String[] strs) {
        Map<String, List<String>> map = new HashMap<>();
        for(String str : strs) {
            int[] letter = new int[26];
            for (char c : str.toCharArray()) {
                letter[c - 'a'] ++;
            }
            String key = Arrays.toString(letter);
            List<String> list;
            if (!map.containsKey(key)) {
                list = new ArrayList();
            } else {
                list = map.get(key);
            }
            list.add(str);
            map.put(key, list);
        }
        List<List<String>> result = new ArrayList<>();
        map.forEach((k, v) -> result.add(v));
        return result;
    }

运行发现大概在 15ms 左右,速度并不是很快。再回到 242 这道题,有一种解法是将两个单词的字母进行排序然后比对。这里也同样可以使用,思路和用数组保存类似。这也是leetcode官方提供的一种解法。

	public List<List<String>> groupAnagrams(String[] strs) {
        Map<String, List<String>> map = new HashMap<String, List<String>>();
        for (String str : strs) {
            char[] array = str.toCharArray();
            Arrays.sort(array);
            String key = new String(array);
            List<String> list = map.getOrDefault(key, new ArrayList<String>());
            list.add(str);
            map.put(key, list);
        }
        return new ArrayList<List<String>>(map.values());
    }

128. 最长连续序列

128. 最长连续序列

LCR 119. 最长连续序列

一个很容易想到的解法是 O(nlogn) 的,对数组进行排序,然后遍历一遍就可以得到答案。但是这个解法很显然不符合题目要求。

    public int longestConsecutive(int[] nums) {
        if (nums.length < 2) {
            return nums.length;
        }
        Arrays.sort(nums);
        int result = 0;
        int temp = 1;
        for (int i = 1; i < nums.length; i++) {
            int count = Math.abs(nums[i] - nums[i - 1]);
            if (count == 0) {
                continue;
            }
            if (count > 1) {
                result = Math.max(result, temp);
                temp = 1;
                continue;
            }
            temp++;
        }
        result = Math.max(result, temp);
        return result;
    }

那么如果想符合题目要求,就不能够排序,只能通过一次遍历得到结果。尽然题目归类在哈希,那么就要想要使用哈希表。将所有元素都作为key,存到哈希表里。根据题目给的示例2,发现也是需要去重的,所以使用哈希表也很合适。

那么保存进去之后怎么计算连续序列长度呢?

连续序列就代表两个值之间相差1,也就是一直判断某一个元素加一后的值在不在这个哈希表中。但是万一遍历到的数并不是起点怎么办呢?所以我们需要判断某个元素减一的值在不在哈希表,如果不在证明他就是起点,我们就从这个起点开始遍历,直到终点。这样的话只需要遍历一遍数组就可以得到最大的连续子序列长度。

    public int longestConsecutive(int[] nums) {
        Set<Integer> num_set = new HashSet<Integer>();
        for (int num : nums) {
            num_set.add(num);
        }

        int longestStreak = 0;

        for (int num : num_set) {
            if (!num_set.contains(num - 1)) {
                int currentNum = num;
                int currentStreak = 1;

                while (num_set.contains(currentNum + 1)) {
                    currentNum += 1;
                    currentStreak += 1;
                }

                longestStreak = Math.max(longestStreak, currentStreak);
            }
        }

        return longestStreak;
    }
  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值