四、快乐数
题目:
编写一个算法来判断一个数 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
提示:
- 1 <= n <= 231 - 1
解题思路分析:
这道题目看上去貌似一道数学问题,其实并不是!
题目中说了会 无限循环,那么也就是说求和的过程中,sum会重复出现,这对解题很重要!
通过前几个小节的内容可知:当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了。
所以这道题目使用哈希法,来判断这个sum是否重复出现,如果重复了就是return false, 否则一直找到sum为1为止。
判断sum是否重复出现就用HashSet。
还有一个难点就是求和的过程,如果对取数值各个位上的单数操作不熟悉的话,做这道题也会比较艰难。
- 取数值各个位置上的单数:
- 取整数n的个位数字:n%10 (也就是除以10取余)
- 接着让n等于上一步的商 (也就是去掉个位数字后的数值)
- 循环前两步的操作,直到n=0结束循环
代码讲解:
//首先定义一个HashSet,用来记录出现过的sum
Set<Integer> record = new HashSet<>();
//循环判断sum是否已经出现过(是否存在于set中)
while(n != 1 && !record.contains(n)) {
record.add(n);
//调用下面定义好的方法获取sum,并将n替换成sum
n = getNextNumber(n);
}
//如果结束循环后 n==1是true,则代表sum=1了,是快乐数;n==1是false,则代表触发的是条件record.contains(n),sum出现过(开始循环了)不是快乐数
return n == 1;
//定义一个取数值各个位置上的单个数字平方和的方法getNextNumber
private int getNextNumber(int n) {
int res = 0;
while(n > 0) {
//用临时变量temp来存储取出来的数字
int temp = n%10;
//用sum来存储各个位置的数字的平方和
res += temp * temp;
//n取值为取余时的商
n = n / 10;
}
return sum;
}
题解:
HashSet:

五、两数之和
题目:
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那** 两个** 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例3:
输入:nums = [3,3], target = 6
输出:[0,1]
提示:
- 2 <= nums.length <= 104
- -109 <= nums[i] <= 109
- -109 <= target <= 109
- 只会存在一个有效答案
进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?
解题思路分析:
HashMap的经典题目。
HashMap的具体内容可以参考这篇文章: https://blog.youkuaiyun.com/asad21654864/article/details/129972009
如何想到用哈希法?
因为我们在遍历一个元素的时候,要判断它之前是否被遍历过,那么就要存放之前遍历的元素。
这里可能不太好理解,举个例子:数组中是162436,目标值是9;
初始时哈希表为空;
遍历到1的时候在哈希表中找8,没有,就把遍历过的1放进去;
遍历到6的时候在哈希表中找3,没有,就把遍历过的6放进去;
那么遍历到3的时候,就需要去找元素6,这时我们就需要判断元素6之前是否被遍历过了,此时6已经在哈希表中了,那么就找到了这两个元素。直接返回第一个6的下标以及3的下标的数组即可。
应该用什么样的哈希表结构来存储遍历过的元素?
因为我们不仅要直到这个元素的值是否出现过,还需要知道这个元素在数组中的下标;
这里相当于要存放的是两个元素(值以及对应下标),用数组和set都不能实现,所以此时要用map来实现;
注意:这里不能只将下标存入集合来做题,因为查找的时候查的是元素是否出现过,即元素的值
map在本题中用来存放什么?map中的key和value用来存什么的?
通过上面的分析可以知道:map在本题中存放的是已经遍历过的元素
map中的key是元素值,value是元素下标。
再次借用上面的例子:数组162436,目标值是9;那么1遍历过了,就需要存入map,map中的key就是1,value就是0。
代码讲解:
//定义一个result数组,用来存放最终找到的两个元素的数组下标
int[] res = new int[2];
//定义一个HashMap,存放遍历过的元素及下标
Map<Integer, Integer> map = new HashMap<>();
//从头开始遍历数组,寻找元素
for(int i = 0; i < nums.length; i++) {
//遍历当前元素,用临时变量temp存放要找的元素,并在map寻找是否有匹配的key
int temp = target - nums[i];
//如果map中找到了,那就将当前元素下标和找到的元素下标放入result数组中
if(map.containsKey(temp)) {
res[0] = map.get(temp);
res[1] = i;
break; //跳出循环
}
//如果没找到,就将当前遍历的元素放入map,继续往后遍历
map.put(num[i], i);
}
return res;
总结:
本题其实有四个重点:
- 为什么会想到用哈希表
- 哈希表为什么用map
- 本题map是用来存什么的
- map中的key和value用来存什么的
把这四点想清楚了,本题才算是理解透彻了。
题解:
自己的思路:两层for循环,暴力解法

HashMap:

文章介绍了如何使用哈希法解决力扣平台上的快乐数问题,通过计算数字各位置单数平方和并检测重复出现的和,以及在两数之和问题中利用HashMap存储已遍历元素及其下标,以提高时间效率。

被折叠的 条评论
为什么被折叠?



