代码随想录算法训练营第六天|242.有效的字母异位词、349. 两个数组的交集、202. 快乐数、1. 两数之和
242.有效的字母异位词
问题简述:判断两个字符串s和t里字母是不是种类个数相同,只是顺序不同。
思考:之前没学过hashmap,看了视频学会了用数组表示,注意创建数组时默认值全为0;然后数字是直接可以直接-‘a’,这样代表了数字直接减去a的ascii码。hashmap一般情况用到三种数据结构:
- 数组:处理无需键值对的数据量较小的数据,且数据不是很离散。
- set:处理无需键值对的数据量较大的数据,数据可以很离散。
- map:处理需要有键值对的数据。
算法思路:用数组的0~25分别存储s中小写字母a~z出现的次数,再减去t中小写字母出现次数,最后查看数组是否全为0。
时间复杂度 :O(n)
空间复杂度 :O(1)
class Solution {
public boolean isAnagram(String s, String t) {
int hash[] = new int[26];
//记录字母出现次数
for (int i = 0; i < s.length(); i++) {
hash[(int)s.charAt(i) - 'a']++;
}
//剪去t中字母出现次数
for (int i = 0; i < t.length(); i++) {
hash[(int)t.charAt(i) - 'a']--;
}
//判断是否全为0
for (int i = 0; i < 26; i++) {
if(hash[i] != 0) return false;
}
return true;
}
}
349. 两个数组的交集
问题简述:求两个数组的交集存入数组,且输出数组元素不能重复。
思考:这道题用到了set,常用的操作是set.add();加入元素;set.contains();查询元素是否存在;set.remove;将元素移除。这三个操作时间复杂度都为O(1)。同时这道题因为要返回一个数组,因为开始不知道数组长度,而且为了避免重复,所有先将交集元素存入了一个新的set2,再遍历set2到数组中,注意int i : set2在循环内的i指的是元素本身而不是元素的索引,对于数组仍然成立。
算法思路:将nums1存入set,再依次判断nums2元素是否在其中,如果在的话将元素存入set2,最后将set2元素存入数组。
时间复杂度: O(n)
空间复杂度: O(n + m) //m为set存入数组
import java.util.HashSet;
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
// 创建一个 HashSet
HashSet<Integer> set = new HashSet<>();
HashSet<Integer> set2 = new HashSet<>();
//将num1存入set
for (int i : nums1) {
set.add(i);
}
//判断nums2元素是否在set中,如果在存入set2
for (int i : nums2){
if(set.contains(i)){
set2.add(i);
}
}
int[] a = new int[set2.size()];
int j = 0;
//将set2存入数组
for(int i : set2){
a[j++] = i;
}
return a;
}
}
202. 快乐数
问题简述:判断一个数是否为快乐数,快乐数指在有限次数内,不断将其各个位数字平方加和最后成为1的数。
思考:对set的再次运用,如果不为快乐数,则数字会一直循环。一般我们要判断一个及格是否存在某个元素,考虑用set来解决。
算法思路:求出两条链表的长度,将更长的链表先遍历两链表长度差值次,再同时遍历两个链表,直到找到公共节点。
时间复杂度 O(logn)
空间复杂度 O(logn)
import java.util.HashSet;
class Solution {
//判断这个新数字是否存在过,并不断把新数字添加到set,存在过就结束返回false,不存在就继续循环直到出现1为止
public boolean isHappy(int n) {
HashSet<Integer> set = new HashSet<>();
while (!set.contains(n)){
set.add(n);
n = sum(n);
if (n == 1) return true;
}
return false;
}
//求一个数各个位数字平方加
public int sum(int n){
int sum = 0;
while (n != 0){
sum += (n % 10) * (n % 10);
n /= 10;
}
System.out.println(sum);
return sum;
}
}
1. 两数之和
问题简述:找出数组中两数之和为target的两个元素下标,存入一个两个元素的数组中。
思考:这道题用到了map,今天只是先把这些怎么用弄明白了,并没有完全搞懂底层的链表、红黑树之类的,二刷再看。map常用方法:
//定义并存入键值对
Map<String, Integer> map = new HashMap<>();
map.put("apple", 10);
//获取值value
int value = map.get("apple");
//判断是否含指定的键
map.containsKey("apple")
算法思路:遍历数组,同时判断map是否存在为target - nums[i]的键。若不存在,将当前数组数字和下标存入键值对,若存在即找到了两个加和为target的数字,分别将当前i和对应键值对的值存入数组,返回数组。
时间复杂度 O(n)
空间复杂度 O(n)
import java.util.HashMap;
import java.util.Map;
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
int[] arr = new int[2];
for (int i = 0; i < nums.length; i++) {
//如果存在对应值,则找到两个数字的下标
if(map.containsKey(target - nums[i])){
arr[0] = i;
arr[1] = map.get(target - nums[i]);
break;
}
//如果目前还不存在,则把数组元素和下表存入map
map.put(nums[i], i);
}
return arr;
}
}
感想
hash是第一次接触,完全没有之前数组和链表顺利,继续加油!