代码随想录-哈希表1

判断一个元素是否出现过的场景

242.有效的字母异位词

力扣题目链接

基本思路

  1. 用record数组记录字符串出现过的字母,遍历第一个字符串增加数组对应位置的值,遍历第二个字符串减少数组对应位置的值。最终如果数组所有位置为0,则说明两个字符串是字母异位词。

方法代码

class Solution {
    public boolean isAnagram(String s, String t) {
        int[] record = new int[26];

        for (int i = 0; i < s.length(); i++) {
            record[s.charAt(i) - 'a']++;     // 并不需要记住字符a的ASCII,只要求出一个相对数值就可以了
        }

        for (int i = 0; i < t.length(); i++) {
            record[t.charAt(i) - 'a']--;
        }
        
        for (int count: record) {
            if (count != 0) {               // record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
                return false;
            }
        }
        return true;                        // record数组所有元素都为零0,说明字符串s和t是字母异位词
    }
}
  • 时间复杂度:O(n+∣Σ∣),其中 n 是 nums 的长度,∣Σ∣ 为字符集合的大小,本题字符均为小写字母,所以 ∣Σ∣=26。
  • 空间复杂度:O(∣Σ∣)

注意点

  1. Java字符串操作
    1. 长度使用s.length()得到
    2. 取特定位置的值:s.charAt(index)
    3. 也可以转换为字符数组:s.toCharArray()
  2. 如果输入字符串包含 unicode 字符,把数组改成哈希表即可
    1. 哈希表创建:Map<Character, Integer> table = new HashMap<Character, Integer>()
    2. 放入数据:table.put(key, value)
    3. 取数据:table.get(key)
    4. table.getOrDefault(key, default):如果存在相应的key则返回其对应的value,否则返回给定的默认值
    5. table.put(ch, table.getOrDefault(ch, 0) + 1):通过这个操作放入的值是对应key的个数

349. 两个数组的交集

力扣题目链接

基本思路

  1. 这道题限制了数组的长度和数字范围,可以使用数组作为hash表,存储哪些元素在输入数组中出现过。然后使用List记录两个表都出现的元素,最后再使用一个数组存储这些元素并返回。

使用数组

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        int[] hash1 = new int[1003];
        int[] hash2 = new int[1003];
        for(int num : nums1){
            hash1[num] = 1; 
        }
        for(int num : nums2){
            hash2[num] = 1;
        }

        List<Integer> resList = new ArrayList<Integer>();
        for(int i = 0; i < 1003; i++){
            if (hash1[i] != 0 && hash2[i] != 0){
                resList.add(i);
            }
        }

        int index = 0;
        int[] res = new int[resList.size()];
        for(int num : resList){
            res[index++] = num;
        }
        return res;
    }
}
  • 时间复杂度:O(m+n)
  • 空间复杂度:O(m+n)

使用Set

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0) {
            return new int[0];
        }
        Set<Integer> set1 = new HashSet<>();
        Set<Integer> resSet = new HashSet<>();
        //遍历数组1
        for (int i : nums1) {
            set1.add(i);
        }
        //遍历数组2的过程中判断哈希表中是否存在该元素
        for (int i : nums2) {
            if (set1.contains(i)) {
                resSet.add(i);
            }
        }
      
        //方法1:将结果集合转为数组
        return resSet.stream().mapToInt(x -> x).toArray();
        
        //方法2:另外申请一个数组存放setRes中的元素,最后返回数组
        int[] arr = new int[resSet.size()];
        int j = 0;
        for(int i : resSet){
            arr[j++] = i;
        }
        
        return arr;
    }
}
  • 时间复杂度:O(m+n)
  • 空间复杂度:O(m+n)

注意点

  1. 创建Set
    • Set<Integer> set1 = new HashSet<>();
  2. 对集合的操作
    • resSet.stream():
      • 将集合 resSet 转换为一个流(Stream)。
      • 这个流允许对集合中的元素进行操作,比如映射、过滤或收集。
    • mapToInt(x -> x):
      • 将流中的每个元素映射为一个整型值。
      • 这里假设 resSet 中的元素本身就是整数(Integer 类型),因此 x -> x 表示直接取元素的值。
    • toArray():
      • 将流中的整型值收集并转换为一个 int[] 数组。

第202题. 快乐数

力扣题目链接

基本思路

  1. 有结论:对于非快乐数,它们在重复计算各位数字的平方和的过程中不仅会形成一个循环,而且每个循环中的数字都是一样的
  2. 因为会存在循环,所以可以使用Set判断得到的sum是否在之前的计算过程中得到过(其实也包含了原本给出的数n,以为如果后面计算得到sum为n,则说明已经进入循环),若已经存在则返回false,若sum中途为1则返回true。
  3. 使用双指针(快慢指针)判断循环是否存在,这个方法更节省空间。“快指针” 每次走两步,“慢指针” 每次走一步,当二者相等时,即为一个循环周期。此时,判断是不是因为 1 引起的循环,是的话就是快乐数,否则不是快乐数

使用Set

class Solution {
    public int getSum(int n){
        int sum = 0;
        while(n > 0){
            int temp = n % 10;
            sum += temp * temp;
            n = n / 10;
        }
        return sum;
    }

    public boolean isHappy(int n) {
        Set<Integer> record = new HashSet<>();
        while(n != 1 && !record.contains(n)){
            record.add(n); //先加入set,然后再改为新数字,下次判断是否加入
            n = getSum(n);
        }
        return n == 1;
    }
}
  • 时间复杂度:O(logn)
  • 空间复杂度:O(logn)

使用快慢指针

class Solution {
    public int getSum(int n){
        int sum = 0;
        while(n > 0){
            int temp = n % 10;
            sum += temp * temp;
            n = n / 10;
        }
        return sum;
    }

    public boolean isHappy(int n) {
        int slow = n;
        int fast = getSum(n);
        while(fast != 1 && fast != slow){
            slow = getSum(slow);
            fast = getSum(getSum(fast));
        }
        return fast == 1;
    }
}
  • 时间复杂度:O(logn)
  • 空间复杂度:O(1)

注意点

  1. 使用快慢指针法来判断是否存在环,判断循环

1. 两数之和

力扣题目链接

基本思路

方法代码

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();
        int j = 0;
        int[] res = new int[2];
        for(int i = 0; i < nums.length; i++){
            j = target - nums[i];
            if(map.containsKey(j)){
                res[0] = i;
                res[1] = map.get(j);
                return res;
            }else{
            //注意:存放当前遍历的这个数的值和下标
            //之后往后遍历的时候,再判断之前加入map的元素是否有符合条件的
                map.put(nums[i], i);
            }
        }
        return null;
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

注意点

  1. 使用map:Map<Integer, Integer> map = new HashMap<>()
posted @ 2024-12-09 16:30  xloading  阅读(18)  评论(0)    收藏  举报