文章目录
242. 有效的字母异位词
给定两个字符串 *s*
和 *t*
,编写一个函数来判断 *t*
是否是 *s*
的字母异位词,小写字母组成。
思路
- 判断一个字符是否包含另一个字符,可想到用hash表
- 因为单词组成字符固定为26个字母,可用数组代替hash表,下标【char - ‘1’】对应即可
复杂度
- 时间 O(n)
- 空间 O(1),数组长度固定为常量
class Solution {
public boolean isAnagram(String s, String t) {
if(t.length() != s.length()) return false;
int[] w = new int[26];
for(int i = 0 ;i<s.length() ; i++){
char c = s.charAt(i);
w[c - 'a']++;
}
for(int i = 0 ;i<t.length(); i++){
char c = t.charAt(i);
w[c - 'a']--;
}
for(int i : w){
if(i != 0 ) return false ;
}
return true ;
}
}
349. 两个数组的交集
给定两个数组 nums1
和 nums2
,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序
思考
- 交集即出现过得数,不考虑输出结果的顺序,符合hash结构,可想到用hash表存储已出现的数值
复杂度
- 时间 O(n)
- 空间 O(n)
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> res = new HashSet<>();
Set<Integer> sets = new HashSet<Integer>();
for (int i = 0; i < nums1.length; i++) {
sets.add(nums1[i]);
}
for (int i = 0; i < nums2.length; i++) {
if(sets.contains(nums2[i])){
res.add(nums2[i]);
}
}
return res.stream().mapToInt(Integer::valueOf).toArray();
}
}
202 快乐数
编写一个算法来判断一个数 n
是不是快乐数。
「快乐数」 定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n
是 快乐数 就返回 true
;不是,则返回 false
示例 1:
输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
示例 2:
输入:n = 2
输出:false
思考(hash表-递归)
- 若n不是快乐数,则会无限循环,说明n在某次计算的时候会等于自己,才能出现循环,可用hash表记录每次计算结果,再次出现时return
- 细节点:得到一个正整数n的每一位数,对n取10的模:
n%10 下次n=n/10-->n==0
即可
复杂度
- 时间 O(n*m) n: 每个数字计算次数 m:每个数字的位数
- 空间 O(n)
class Solution {
Set<Integer> sets = new HashSet<>();
public boolean isHappy(int n) {
int sum = 0 ;
while(n>0) {
int t = n % 10;
sum += t*t;
n = n/10;
}
if(sum == 1){
return true;
}else if(sets.contains(sum)){
return false;
}else{
sets.add(sum);
}
return isHappy(sum) ;
}
}
思考(hash表-迭代)
复杂度
- 时间 O(n*m) n: 每个数字计算次数 m:每个数字的位数
- 空间 O(n)
class Solution {
public boolean isHappy(int n) {
Set<Integer> s = new HashSet<>();
int sum = 0 ;
while(n != 0){
//个位的平方和
sum += (n%10) * (n%10) ;
n = n/10 ;
if(n == 0){
if(s.contains(sum)){
//第二次出现时一定会无限循环下去
return false;
}else if (sum == 1){
return true;
}else{
s.add(sum);
n = sum;
sum =0 ;
}
}
}
return true;
}
}
思考(双指针)
- 因为可能出现循环,可联想到循环链表,判断循环链表除了hash表的方式,还有快慢双针的解法
- 此题的快慢指针为n和n~2,结束条件为n==n*n对应的快乐数,若快乐数为1,返回true,其他返回false;
- 慢指针一次走一步,快指针要每次走两步,指针才能相遇
复杂度
- 时间 O(n)
- 空间 O(1)
class Solution {
public boolean isHappy(int n) {
int slow = n , fast = squareSum(n);
while(slow != fast){
slow = squareSum(slow);
fast = squareSum(squareSum(fast));
}
return slow == 1 ;
}
public int squareSum(int n ){
int sum = 0 ;
while(n>0) {
int t = n % 10;
sum += t*t;
n = n/10;
}
return sum ;
}
}
1.两数之和
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1]
思考
- 题目关键字:两个整数,返回下表;
- 可想到用hash表存储已经遍历元素,如果遍历元素的差值在hash表中,即可得到结果
class Solution {
public int[] twoSum(int[] nums, int target) {
//map value:下标, key:存放目标值和每次遍历元素的差值
Map<Integer,Integer> s = new HashMap<Integer,Integer>();
for (int i = 0; i < nums.length; i++) {
if(s.containsKey(nums[i])){
return new int[]{s.get(nums[i]),i};
}else{
s.put(target - nums[i],i);
}
}
return null ;
}
}
总结
- 若题意中隐含有判断是否已经存在的数值时,首先可想到hash表(HashSet\HashMap)
- 若字符数量为常量,可试用数组代替hash表,节省空间