代码随想录 Day13 哈希表 | LC202 快乐数 & LC1 两数之和

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

四、快乐数

题目:

力扣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

提示:

  • 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:

在这里插入图片描述

五、两数之和

题目:

力扣1:两数之和

给定一个整数数组 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:

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值