内容:
- 有效的字母异位词(242)
- 两个数组的交集(349)
- 快乐数(202)
- 两数之和(1)
1.有效的字母异位词
难度:🔥🔥
1.1 思路分析
最先出现在我的脑海中的思路就是两层for循环一个一个比较。时间复杂度为O(n^2).
而事实上这题可以通过数组来实现一个简单的哈希表,对于每个字母我们记录它对应的位置以及出现的次数,最后判断数组中所有元素是否为0即可。时间复杂度为O(n),空间上因为定义是的一个常量大小的辅助数组,所以空间复杂度为O(1)。
操作动画如下:
1.2 代码实现
class Solution {
public boolean isAnagram(String s, String t) {
//定义一个容纳26个字母的数组
int[] record = new int[26];
for(int i = 0;i < s.length();i++){
record[s.charAt(i) - 'a']++;
}//得到的数组就是包含s每个字母的出现次数
for(int i = 0;i < t.length();i++){
record[t.charAt(i) - 'a']--;
}
for(int count : record){
if (count != 0){
return false;
}
}
return true;
}
}
1.3 收获总结
- 理解下标的含义,因为字符a到字符z的ASCII是26个连续的数值,所以字符a映射为下标0,相应的字符z映射为下标25
2.两个数组的交集
难度:🔥🔥
2.1 思路分析
这题主要考察我们对Set集合的使用,这里我们使用Set的主要实现类HastSet, 并且HashSet的无序性可以帮助我们做去重操作。在JDK7时HashSet的底层实现为数组+链表的形式。
思路如图所示:
2.2 代码实现
数组方式
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> set = new HashSet<>();//去重
int[] record = new int[1005];
for(int i = 0; i < nums1.length;i++){
record[nums1[i]] = 1;
}
for(int i = 0;i < nums2.length;i++){
if (record[nums2[i]] == 1){
set.add(nums2[i]);
}
}
return set.stream().mapToInt(x -> x).toArray();
}
}
HashSet
方式
Set<Integer> set1 = new HashSet<>();
Set<Integer> set2 = new HashSet<>();
for(int count : nums1){
set1.add(count);
}
for(int count : nums2){
if (set1.contains(count)){
set2.add(count);
}
}
return set2.stream().mapToInt( x -> x).toArray();
2.3 总结收获
- 使用数组来做哈希的题目,是因为题目都限制了数值的大小
- 如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费
return set2.stream().mapToInt( x -> x).toArray();
这里还不是很理解,主要是通过stream().mapToInt(x -> x)
得到了IntStream
接口,里面有一个toArray()
返回int[],得到最终结果。等后面把Stream和lambada表达式练熟了可以再来看看。
3.快乐数
难度:🔥🔥🔥
该用set的时候,还是得用set
3.1 思路分析
问题的关键在于题目中说了会 无限循环,那么也就是说求和的过程中,sum会重复出现。
了解了这一点,快乐数岂不是被我哈希法轻松拿下。
3.2 代码实现
class Solution {
public boolean isHappy(int n) {
Set<Integer> set = new HashSet<>();
while(n != 1 && !set.contains(n)){
set.add(n);
n = getNextNumber(n);
}
if(n == 1){
return true;
}
return false;
}
//写一个方法用于计算n每个位置上数的平方和
private int getNextNumber(int nums){
int result = 0;
while(nums > 0){
int number = nums % 10;
result += number * number;
nums = nums / 10;
}
return result;
}
}
3.3 总结收获
- 关键:当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了
4.两数之和
难度:🔥🔥
4.1 思路分析
很显然暴力解法时间复杂度为O(n ^ 2).
而之前我们使用了数组、Set,这里我们都不用。这里我们使用map来解决这个问题是最合适不过了。同时我们需要明白:
- map用来做什么
- map中key和value分别表示什么
过程如图:
4.2 代码实现
代码虽然简短,但是需要理解每句话代表什么意思,而不能死记硬背
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] result = new int[2];
Map<Integer,Integer> map = new HashMap<>();
//key为数组元素,value为数组下标
for(int i = 0; i < nums.length;i++){
int temp = target - nums[i];
if (map.containsKey(temp)){
result[0] = i;
result[1] = map.get(temp);
return result;
}
map.put(nums[i],i);
}
return new int[2];
}
}
4.3 收获总结
- map目的用来存放我们访问过的元素,因为遍历数组的时候,需要记录我们之前遍历过哪些元素和对应的下标,这样才能找到与当前元素相匹配的(也就是相加等于target)
- map中的key存放数组元素,value为数组下标
- 要熟悉map中的
containsKey、get、put
方法的使用