Day6 哈希表 part1

8

有效的字母异位词

字符a到字符z的ASCII是26个连续的数值,所以字符a映射为下标0,相应的字符z映射为下标25。

那么任意字母和字母a相减的结果就是索引位置,在这个索引位置上计数,两个字符串分别对应计数的增cao操作和减操作,zhi'yao'zui只要最终遍历存储结果的数组,每一个位置是否为0即可

public boolean isAnagram(String s, String t) {
        int record[] = new int[26];//定义一个数组,长度为26,因为a~z是26个字母
        //分别遍历两个字符串,统计字母出现数量到record
        for (int i = 0; i < s.length(); i++){
            record[s.charAt(i) - 'a']++;
        }
        for (int i = 0; i < t.length(); i++) {
            record[t.charAt(i) - 'a']--;
        }
        //遍历record内如果数组内元素不为0,则说明字符不相等,返回false
        for (int i : record) {
            if (i != 0){
                return false;
            }
        }
        return true;
    }

两个数组的交集

思路一、数组

利用数组统计数字频率,动态检查交集并去重。

public int[] intersection(int[] nums1, int[] nums2) {
        // 假设数字范围是 0-1000(根据题目调整)
        int[] count = new int[1001]; // count[i] 表示数字 i 在 nums1 中出现的次数

        // 统计 nums1 的数字频率
        for (int num : nums1) {
            count[num]++;
        }

        // 检查 nums2 的数字是否在 nums1 中出现过
        List<Integer> resultList = new ArrayList<>();
        for (int target : nums2) {
            if (count[target] > 0) { // 如果 nums1 中有这个数字
                resultList.add(target); // 加入结果
                count[target] = 0; // 避免重复添加(题目要求结果去重)
            }
        }

        // 将 List 转为 int[]
        int[] result = new int[resultList.size()];
        for (int i = 0; i < resultList.size(); i++) {
            result[i] = resultList.get(i);
        }
        return result;
    }

思路二、HashSet

public int[] intersection(int[] nums1, int[] nums2) {
    if (nums1 == null || nums2 == null || nums1.length == 0 || nums2.length == 0) {
        return new int[0];
    }
    
    Set<Integer> set1 = new HashSet<>();
    Set<Integer> resSet = new HashSet<>();
    
    // 遍历数组1,存入set1
    for (int num : nums1) {
        set1.add(num);
    }
    
    // 遍历数组2,检查是否在set1中存在
    for (int num : nums2) {
        if (set1.contains(num)) {
            resSet.add(num);
        }
    }
    
    // 将结果转为数组
    int[] result = new int[resSet.size()];
    int index = 0;
    for (int num : resSet) {
        result[index++] = num;
    }
    return result;
}

快乐数

题意,平方和为1就是快乐数。

19 → 82 → 68 → 100 → 1(无重复,最终到 1,返回 true

2之所以不是是因为,20的平方和等于4,形成环了

2 → 4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4(进入循环,返回 false

public boolean isHappy(int n) {
    // 使用 HashSet 来记录已经出现过的数字,用于检测循环
    HashSet<Integer> seenNumbers = new HashSet<>();
    
    // 当 n 不等于 1 且没有进入循环时,继续计算
    while (n != 1 && !seenNumbers.contains(n)) {
        // 将当前数字加入已见集合,防止重复计算
        seenNumbers.add(n);
        // 计算下一个数字(各位数字的平方和)
        n = getNext(n);
    }
    
    // 如果最终 n 变成 1,则是快乐数;否则进入循环,不是快乐数
    return n == 1;
}

/**
 * 计算一个数的各位数字的平方和
 * 
 * @param n 输入的数字
 * @return 各位数字的平方和
 */
private int getNext(int n) {
    int sum = 0;
    while (n > 0) {
        // 取 n 的最后一位数字
        int digit = n % 10;
        // 将该数字的平方加到 sum 上
        sum += digit * digit;
        // 去掉 n 的最后一位(相当于 n / 10 取整)
        n = n / 10;
    }
    return sum;
}

两数之和

首先想到了遍历的办法,但是On^2

   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) {
                    return new int[]{i,j};
                }
            }
        }
        //没有就返回null
        return null;
    }

另一种思路是,用map存放遍历过的元素,key是元素值,value是下标索引,如此时间复杂度On

    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer, Integer> result = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if (result.containsKey(target - nums[i])){
                //返回目标数的索引和当前数索引
                return new int[]{result.get(target - nums[i]), i};
            }
            //没有符合的数字,继续存入map中
            result.put(nums[i], i);
        }
        return null;
    }