242.有效的字母异位词
数组其实就是一个简单哈希表,而且这道题目中字符串只有小写字符,那么就可以定义一个数组,来记录字符串s里字符出现的次数。
需要定义一个多大的数组呢,定一个数组叫做record,大小为26 就可以了,初始化为0,因为字符a到字符z的ASCII也是26个连续的数值。
(代码很简单,建议debug看一下每一步的过程)
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']++;
}
for(int i = 0;i<t.length();i++){
record[t.charAt(i) - 'a']--;
}
for(int count : record){
if(count != 0){
return false;
}
}
return true;
}
394.两个数组的交集
这道题目,主要要学会使用一种哈希数据结构:unordered_set,这个数据结构可以解决很多类似的问题。
注意题目特意说明:输出结果中的每个元素一定是唯一的,也就是说输出的结果的去重的, 同时可以不考虑输出结果的顺序
但是要注意,使用数组来做哈希的题目,是因为题目都限制了数值的大小。
而这道题目没有限制数值的大小,就无法使用数组来做哈希表了。
而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。
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<>();
for(int num : nums1){
set1.add(num);
}
for(int n : nums2){
if(set1.contains(n)){
resSet.add(n);
}
}
//第一种(方便简洁)
return resSet.stream().mapToInt(x -> x).toArray();
//第二种
// int[] arr = new int[resSet.size()];
// int j = 0;
// for(int i : resSet){
// arr[j++] = i;
// }
// return arr;
}
202.快乐数
快乐数定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
public static boolean isHappy(int n) {
Set<Integer> record = new HashSet();
while(n != 1 && !record.contains(n)){
record.add(n);
n = getNextNumber(n);
}
return n ==1;
}
private static int getNextNumber(int n){
int res = 0;
while(n >0){
int temp = n % 10;
res += temp *temp;
n = n / 10;
}
return res;
}
1.两数之和
因为本题,我们不仅要知道元素有没有遍历过,还要知道这个元素对应的下标,需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适。
再来看一下使用数组和set来做哈希法的局限。
- 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
- set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用。
此时就要选择另一种数据结构:map ,map是一种key value的存储结构,可以用key保存数值,用value再保存数值所在的下标。
第一种解法:
public int[] twoSum(int[] nums, int target) {
int[] res = new int[2];
if(nums == null || nums.length == 0){
return res;
}
Map<Integer, Integer> map = new HashMap<>();
for(int i = 0; i < nums.length; i++){
int temp = target - nums[i]; // 遍历当前元素,并在map中寻找是否有匹配的key
if(map.containsKey(temp)){
res[1] = i;
res[0] = map.get(temp);
break;
}
map.put(nums[i], i); // 如果没找到匹配对,就把访问过的元素和下标加入到map中
}
return res;
}
第二种:
public int[] twoSum(int[] nums, int target) {
Map<Integer,Integer> map = new HashMap<>();
for(int i = 0;i<nums.length;i++){
if(map.containsKey(target-nums[i])){
return new int[]{map.get(target-nums[i]),i};
}
map.put(nums[i],i);
}
throw new IllegalArgumentException("No two sum solution");
}