代码随想录算法训练营第六天 | 242.有效的字母异位词、349. 两个数组的交集、202. 快乐数、1. 两数之和

有效的字母异位词

【力扣】242.有效的字母异位词

class Solution {
    public boolean isAnagram(String s, String t) {
        /*
         * 思路:
         * 用数组当做统计26个字母出现次数的哈希表
         * 
         * 参考:
         * https://programmercarl.com/0242.%E6%9C%89%E6%95%88%E7%9A%84%E5%AD%97%E6%AF%8D
         * %E5%BC%82%E4%BD%8D%E8%AF%8D.html#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%
         * 88%E6%9C%AC
         * 
         * 
         * 定义一个数组叫做record.用来上记录字符串s里字符出现的次数。
         * 需要把字符映射到数组也就是哈希表的索引下标上,因为字符a到字符z的ASCII是26个连续的数值,所以字符a映射为下标0,相应的字符z映射为下标25。
         * 再遍历字符串s的时候,只需要将s[i]-'a'所在的元素做+1操作即可,并不需要记住字符a的ASCII,只要求出一个相对数值就可以了。
         * 这样就将字符串s中字符出现的次数,统计出来了。
         * 那看一下如何检查字符串t中是否出现了这些字符,同样在遍历字符串t的时候,对t中出现的字符映射哈希表索引上的数值再做-1的操作。
         * 那么最后检查一下,record数组如果有的元素不为零0,说明字符串s和t一定是谁多了字符或者谁少了字符,return false。
         * 最后如果record数组所有元素都为零0,说明字符串s和t是字母异位词,return true。
         * 时间复杂度为O(n),空间上因为定义的是一个常量大小的辅助数组,所以空间复杂度为O(1)。
         * 
         */
        int record[] = new int[26]; // 数组哈希表,记录每个字母的出现次数

        // 记录字符串s中每个字母出现的次数
        for (int i = 0; i < s.length(); i++) {
            int index = s.charAt(i) - 'a'; // 表示26个字母中的第几个字母
            record[index]++;
        }

        // 如果字符串t含有某个字母,那么减一
        for (int i = 0; i < t.length(); i++) {
            int index = t.charAt(i) - 'a';
            record[index]--;
        }

        // record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
        for (int i : record) {
            if (i != 0) {
                return false;
            }
        }
        // record数组所有元素都为零0,说明字符串s和t是字母异位词
        return true;
    }
}

两个数组的交集

【力扣】349. 两个数组的交集

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        /*
         * 思路:
         * 使用哈希集合hashSet
         * 
         * 参考:
         * https://programmercarl.com/0349.%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84
         * %E4%BA%A4%E9%9B%86.html#_349-%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E4
         * %BA%A4%E9%9B%86
         * 
         * 注意题目特意说明:输出结果中的每个元素一定是唯一的,
         * 也就是说输出的结果的去重的,同时可以不考虑输出结果的顺序。
         * 
         * 如果用数组做哈希表,那么假设交集的数字只有5000,那么数组的下标得到4999,
         * 造成存储空间的极大浪费。也即,如果哈希值比较少、特别分散、跨度非常大,
         * 使用数组就造成空间的极大浪费。所以这个时候可以用哈希集合。
         * 
         * 本题将一个数组变成哈希集合,然后遍历另一个数组与此哈希集合比较,
         * 看是否出现过相同的元素。
         * 
         * 
         */

        // 排除异常条件:数组不存在,或数组长度为0
        if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0) {
            return new int[0];
        }

        Set<Integer> set1 = new HashSet<>(); // nums1数组的集合
        Set<Integer> interSet = new HashSet<>(); // 交集

        // 获得nums1数组的不重复元素
        for (int i : nums1) {
            set1.add(i);
        }

        // 从nums2中找到与nums1数组相同的元素
        for (int i : nums2) {
            if (set1.contains(i)) {
                interSet.add(i);
            }
        }

        // 集合变为int数组
        // 注意hashset先变为stream,才能变为数组
        return interSet.stream().mapToInt(x -> x).toArray();
    }
}

快乐数

【力扣】202. 快乐数

class Solution {
    public boolean isHappy(int n) {
        /*
         * 思路:哈希集合
         * 每次按快乐数公式计算的结果,一旦发现新的就存到哈希集合中,
         * 如果发现哈希集合中已经存在此数,那么停止计算。(因为遇到
         * 重复出现的数后,继续计算又会陷入循环当中)。
         * 
         * 最后检查这个重复的数是否为1。
         * 
         * 参考:
         * https://programmercarl.com/0202.%E5%BF%AB%E4%B9%90%E6%95%B0.html
         * 
         */

        Set<Integer> set = new HashSet<>();
        // 一直计算快乐数,直到遇到重复的为止
        // n!=1是因为题意说直到变成1,变成1就说明是快乐数满足条件可以退出循环了(1没必要再进入循环了)。
        while (n != 1 && !set.contains(n)) {
            set.add(n);
            n = getNextNumber(n); // 按快乐数公式计算下一个
        }

        // 检查重复的数是否为1
        return n == 1;
    }

    public int getNextNumber(int n) {
        /*
         * 计算快乐数
         */

        // 注意怎么取各个位的数字
        int result = 0;
        while (n != 0) {
            int tmp = n % 10; // 获得末位数
            result += tmp * tmp;
            n /= 10; // n的位数-1
        }
        return result;
    }
}

两数之和

【力扣】1. 两数之和

class Solution {
    public int[] twoSum(int[] nums, int target) {
        /*
         * 思路:哈希表 {key:数据元素,value:数组元素对应的下表}
         * 
         * 什么时候使用哈希法,当我们需要查询一个元素是否出现过,
         * 或者一个元素是否在集合里的时候,就要第一时间想到哈希法。
         * 
         * 我们不仅要知道元素有没有遍历过,还有知道这个元素对应的下标,
         * 需要使用 key value结构来存放,key来存元素,value来存下标,
         * 那么使用map正合适。
         * 
         * 再来看一下使用数组和set来做哈希法的局限:
         * 1、数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
         * 2、set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,
         * 不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x和y的下标。所以set也不能用。
         * 此时就要选择另一种数据结构:map。
         * 
         * 参考:
         * https://programmercarl.com/0001.%E4%B8%A4%E6%95%B0%E4%B9%8B%E5%92%8C.html#%E6
         * %80%9D%E8%B7%AF
         * 
         */
        // 存储满足题目条件的两个数的下标
        int result[] = new int[2];
        // 排除异常:如果数组为null或者数组长度为0
        if (nums == null || nums.length == 0) {
            return result;
        }

        // map目的用来存放我们访问过的元素,因为遍历数组的时候,
        // 需要记录我们之前遍历过哪些元素和对应的下标,
        // 这样才能找到与当前元素相匹配的(也就是相加等于target)
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            // 检查两数之和的另一个数是否存在哈希表中
            int tmp = target - nums[i];
            if (map.containsKey(tmp)) {
                result[1] = i;
                result[0] = map.get(tmp); // 获得下标
                break;
            }
            // map存元素和对应的下标
            map.put(nums[i], i);
        }
        return result;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值