力扣hot100-哈希

6 阅读2分钟

1.两数之和

image.png

根据题目描述,我们采用哈希表的解法,可以将时间复杂度降到o(n)

核心思路

一边遍历,一边查表

  • 遍历数组时,计算当前数字需要的"另一半"(diff = target - nums[i]
  • 如果 diff 已经在哈希表中,说明之前遇到过,直接返回两个索引
  • 如果没遇到过,把当前数字存入哈希表,供后面使用
class Solution {
    public int[] twoSum(int[] nums, int target) {
        // 哈希表:key = 数字值,value = 该数字在数组中的索引
        HashMap<Integer, Integer> map = new HashMap<>();
        
        int n = nums.length;
        
        // 遍历数组
        for (int i = 0; i < n; i++) {
            // 计算当前数字需要的"另一半"
            int diff = target - nums[i];
            
            // 检查这个"另一半"是否已经出现过
            if (map.containsKey(diff)) {
                // 找到了!返回之前数字的索引和当前索引
                return new int[]{map.get(diff), i};
            } else {
                // 没找到,把当前数字存入哈希表,供后续使用
                map.put(nums[i], i);
            }
        }
        
        // 题目保证有解,实际不会执行到这里
        return null;
    }
}

详细注释已经写上。

2.字母异位词分组

image.png

核心思路

识别异位词的关键

  • "eat""tea""ate" 都是异位词
  • 把它们按字母排序后,都变成 "aet"
  • 用排序后的字符串作为哈希表的 key,异位词都放入同一个 key 对应的列表
    public List<List<String>> groupAnagrams(String[] strs) {
        // 哈希表:key = 排序后的字符串,value = 异位词列表
        HashMap<String, List<String>> map = new HashMap<>();
        
        for (String str : strs) {
            // 1. 将当前字符串转为字符数组并排序
            char[] chars = str.toCharArray();
            Arrays.sort(chars);           // 例如 "eat" → ['a','e','t']
            
            // 2. 排序后的字符数组转回字符串作为 key
            String sortedKey = new String(chars);  // "aet"
            
            // 3. 检查 key 是否已存在
            if (map.containsKey(sortedKey)) {
                // 存在:取出列表,添加当前字符串
                List<String> list = map.get(sortedKey);
                list.add(str);
            } else {
                // 不存在:创建新列表,添加当前字符串
                ArrayList<String> list = new ArrayList<>();
                list.add(str);
                map.put(sortedKey, list);
            }
        }
        
        // 4. 返回所有 value(每个 value 是一个异位词组)
        return new ArrayList<>(map.values());
    }
}

3.最长连续序列

image.png 我们用两种方法来解决该题

(1)排序法

class Solution {
    public int longestConsecutive(int[] nums) {
        int n = nums.length;
        if (n == 0) return 0;
        
        Arrays.sort(nums);  // 排序让连续数字相邻
        int res = 1;        // 最终结果
        int maxLen = 1;     // 当前连续长度
        
        for (int i = 1; i < n; i++) {
            if (nums[i] == nums[i-1]) {
                continue;  // 重复数字跳过
            } else if (nums[i] == nums[i-1] + 1) {
                maxLen++;               // 连续,长度+1
                res = Math.max(res, maxLen);
            } else {
                maxLen = 1;             // 断开,重置长度
            }
        }
        return res;
    }
}

(2)使用哈希表

    public int longestConsecutive(int[] nums) {
        if (nums == null || nums.length == 0) return 0;
        
        // 1. 所有数字放入 HashSet,去重 + O(1) 查找
        HashSet<Integer> set = new HashSet<>();
        for (int num : nums) {
            set.add(num);
        }
        
        int longest = 0;
        
        // 2. 遍历每个数字
        for (int num : set) {
            // 关键:只从连续序列的起点开始找
            // 如果 num-1 存在,说明 num 不是起点,跳过
            if (!set.contains(num - 1)) {
                // num 是起点
                int currentNum = num;
                int currentLen = 1;
                
                // 向后查找连续数字
                while (set.contains(currentNum + 1)) {
                    currentNum++;
                    currentLen++;
                }
                
                longest = Math.max(longest, currentLen);
            }
        }
        
        return longest;
    }
}

两种方法的对比

image.png