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

69 阅读1分钟

242. 有效的字母异位词

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

注意: 若 s 和 t **中每个字符出现的次数都相同,则称 s 和 t **互为字母异位词。

image.png

思路

创建一个大小为26的整数数组,每一位代表一个字母,从0 ~ 25代表字母a~z
首先遍历字符串s,每个字母出现一次,对应数组位置的数加一;
然后遍历字符串s,每个字母出现一次,对应数组位置的数减一;
最后重新遍历数组,如果某个位置的数字不为0,那么则说明两个字符串某个字幕出现的次数不一样,因此不是字母异位词。

代码实现

class Solution {
    public boolean isAnagram(String s, String t) {
        int[] dic = new int[26];
        for (int i = 0; i < s.length(); ++i) {
            dic[s.charAt(i) - 'a']++;
        }

        for (int i = 0; i < t.length(); ++i) {
            dic[t.charAt(i) - 'a']--;
        }

        for (int i = 0; i < 26; ++i) {
            if (dic[i] != 0) {
                return false;
            }
        }
        return true;
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

349. 两个数组的交集

给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。

image.png

思路

首先遍历一遍nums1数组,把出现的数字加入set集合;
然后遍历nums2数字,并检查nums2数组中每个数字是否在set集合中出现,出现的话加入结果集,没有继续检查下一个。

代码实现

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        Set<Integer> set = new HashSet<>();
        Set<Integer> resSet = new HashSet<>();
        for (int i = 0; i < nums1.length; ++i) {
            set.add(nums1[i]);
        }

        for (int i = 0; i < nums2.length; ++i) {
            if (set.contains(nums2[i])){
                resSet.add(nums2[i]);
            }
        }
        int i = 0;
        int[] arr = new int[resSet.size()];
        for (int number : resSet) {
            arr[i++] = number;
        }
        return arr;
    }
}
  • 时间复杂度:O(n + m)
  • 空间复杂度:O(n)

202. 快乐数

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

image.png

思路

首先,我们要知道如何判断是否是无限循环始终变不到1。
可以使用set集合来辅助,如果一个数会无限循环,那么他就会反复出现;基于这个特性,每次一个数出现我们就判断其是否存在于set集合,如果存在则代表这个数会无限循环,可以直接return false,如果不存在就加入集合。通过这种方法,我们就可以排除出那些无法变为1的数。

当出现n == 1或者 set.contains(n)两种中任一种的情况时,我们就可以跳出循环,判断n是否为1,即return n == 1。这样就能得到最终结果。

代码实现

class Solution {
    public boolean isHappy(int n) {
        Set<Integer> set = new HashSet<>();
        while (n != 1 && !set.contains(n)) {
            set.add(n);
            n = getNum(n);
        }
        return n == 1;
    }
    // 通过这个方法将一个数替换为它每个位置上的数字的平方和
    private int getNum(int num) {
        int sum = 0;
        while (num != 0) {
            int temp =  num % 10;
            sum += temp * temp;
            num = num / 10;
        }
        return sum;
    }
}
  • 时间复杂度:O(log n)
  • 空间复杂度:O(log n)

1. 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

image.png

思路-使用map来解决

要使用map, 我们首先要明确两点:

  • map用来做什么
  • map中key和value分别用来表示什么

本题中,使用map的目的是用于存储数组元素与其对应的数组下标,因为我们要返回的是下标,因此value代表下标,key代表数组中的元素。

明确了这两点以后我们就可以开始我们的解题思路了;
首先我们遍历数组,同时检查map中是否存在一个key,这个key与当前数组遍历元素的和为target。如果map中存在这个key,那么我们就找到了这个唯一解。因为本体必定有且只有一个唯一解,因此不用考虑不存在答案以及复数答案的情况。
过程如下:

image.png

image.png

image.png
注意: 以上的操作都需要在一次遍历中完成,如果我下图代码就犯了一个错误:

假设题目为 {3, 2, 4}, target = 6;
在我第二遍循环带第 0 个数字的时候,因为map中已经有了 key = 3, value = 0 的键值对,因此他会直接返回 结果 {0, 0}; 而题目是不允许一个数字用两次的,因此这样是无法AC的。

image.png

代码实现

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; ++i) {
            int diff = target - nums[i];
            if (map.containsKey(diff)) {
                return new int[] {map.get(diff), i};
            }
            map.put(nums[i], i);
        }
        return new int[]{};
    }
}
  • 时间复杂度: O(n)
  • 空间复杂度: O(n)