1. 两数之和
建议:本题虽然是 力扣第一题,但是还是挺难的,也是 代码随想录中 数组,set之后,使用map解决哈希问题的第一题。
建议大家先看视频讲解,然后尝试自己写代码,在看文章讲解,加深印象。
题目链接/文章讲解/视频讲解:代码随想录

思路:242.有效的字母异位词
1,循环遍历数组,拿到每个数字x
2,以target-x作为key到hash表查找
(1)若没找到,将x作为key,将他的索引作为value放入hash表查找
(2)若找到了,返回x和他配对数的索引即可
我们直接来看代码
class Solution {
public int[] twoSum(int[] nums, int target) {
HashMap<Integer,Integer> map=new HashMap<>();
for(int i=0;i<nums.length;i++){
int x=nums[i];
int y=target-nums[i];
if(map.containsKey(y)){
return new int[]{i,map.get(y)};
}else{
map.put(x,i);
}
}
return null;
}
}
为什么用HashMap,因为它里面每一个元素可以存key和value,可以快速清晰地找到需要的元素,因为题目要求返回的是索引,我们将value作为键,索引作为值即可,这样我们调用get方法分时候返回的就是对应的索引。
349. 两个数组的交集
建议:本题就开始考虑 什么时候用set 什么时候用数组,本题其实是使用set的好题,但是后来力扣改了题目描述和 测试用例,添加了 0 <= nums1[i], nums2[i] <= 1000 条件,所以使用数组也可以了,不过建议大家忽略这个条件。 尝试去使用set。
题目链接/文章讲解/视频讲解:代码随想录

方法一:用Hashset
首先我们先来了解一下Hashset,他和HashMap的区别是什么呢
- 核心区别总结:
存储形式:
- HashMap:存储键值对(key-value)
- HashSet:仅存储单个元素
功能特点:
-
HashMap:
- 可以根据键获取值
- 可以存储重复的值(但键必须唯一)
- 允许键和值为 null
-
HashSet:
- 仅能存储元素值
- 不允许重复元素
- 只允许一个 null 元素
使用场景:
-
HashMap:
- 需要存储键值对应关系时
- 需要根据键快速查找值时
- 需要统计频率或映射关系时
-
HashSet:
- 需要去除重复元素时
- 只关心元素是否存在时
- 需要保证元素唯一性时
判断是否有重复元素,我们可以利用Hashset自动去重的功能,例如

并且hashset还有contains方法,也可以利于我们统计元素的出现数量。
这道题的思路是设置两个set,第一个set用来收集nums1中的元素,并将其添加进去,因为hashset自带的去重功能可以将重复元素去除,所以最后存放分hashset是没有重复元素的,然后我们再遍历nums2,如果set1里面的元素包含nums2中的元素,我们将这个元素加入set2,这个set2其实就是两个数组的交集,因为题目中要求返回int,所以我们再将set转化成int的类型即可,我们来看代码
import java.util.HashSet;
import java.util.Set;
class Solution {
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<>();
//遍历数组1
for (int i : nums1) {
set1.add(i);
}
//遍历数组2的过程中判断哈希表中是否存在该元素
for (int i : nums2) {
if (set1.contains(i)) {
resSet.add(i);
}
}
//方法1:将结果集合转为数组
return resSet.stream().mapToInt(x -> x).toArray();
//方法2:另外申请一个数组存放setRes中的元素,最后返回数组
int[] arr = new int[resSet.size()];
int j = 0;
for(int i : resSet){
arr[j++] = i;
}
return arr;
}
}
方法二:用哈希数组
为什么用哈希数组,什么是哈希数组
让我解释为什么这里使用哈希数组而不是普通数组:
哈希数组的特殊用途:
// 哈希数组用法
int[] hash1 = new int[1002];
for(int i : nums1) {
hash1[i]++; // 数组索引作为键,值作为计数器
}
// 普通数组用法
int[] normal = new int[nums1.length];
for(int i = 0; i < nums1.length; i++) {
normal[i] = nums1[i]; // 索引只表示位置
}
// 使用哈希数组查找 - O(1)时间复杂度
if(hash1[i] > 0) { // 直接通过索引判断数字i是否存在
// 数字i存在
}
// 使用普通数组查找 - O(n)时间复杂度
boolean found = false;
for(int num : normal) { // 需要遍历整个数组
if(num == i) {
found = true;
break;
}
}
哈希数组更加适用于频繁查找和计数统计的操作,我们来看思路,我们创建两个hash数组,将两个输入数组中的值分别存入哈希数组中,这样数组的索引作为键,数组的值作为计数次数,然后我们得到了两个哈希数组,只要判断相同索引的两个哈希数组的值是否都大于0就行,如果都大于0,就说明这个元素是重复的,我们再创建一个动态数组吗,因为具备扩容的功能等,但是最后返回的时候还是需要创建一个普通数组,因为题目要求的返回方法是int,我们来看代码。
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
int[] hash1 = new int[1002];
int[] hash2 = new int[1002];
for(int i : nums1)
hash1[i]++;
for(int i : nums2)
hash2[i]++;
List<Integer> resList = new ArrayList<>();
for(int i = 0; i < 1002; i++)
if(hash1[i] > 0 && hash2[i] > 0)
resList.add(i);
int index = 0;
int res[] = new int[resList.size()];
for(int i : resList)
res[index++] = i;
return res;
}
}
这道题的思路比较巧妙,我们结合代码来看
/**
* 242. 有效的字母异位词 字典解法
* 时间复杂度O(m+n) 空间复杂度O(1)
*/
class Solution {
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']++; // 并不需要记住字符a的ASCII,只要求出一个相对数值就可以了
}
for (int i = 0; i < t.length(); i++) {
record[t.charAt(i) - 'a']--;
}
for (int count: record) {
if (count != 0) { // record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
return false;
}
}
return true; // record数组所有元素都为零0,说明字符串s和t是字母异位词
}
}
因为
// 在ASCII码中:
// 'a' = 97
// 'b' = 98
// 'c' = 99
// ...
// 'z' = 122
// 当我们做 charAt(i) - 'a' 时:
char c = 'c'; // ASCII值为99
char a = 'a'; // ASCII值为97
int index = c - a; // 99 - 97 = 2
// 所以'c'对应的索引是2
将所有charat-a,我们可以将数组索引变成0——26,这样在建立数组的时候比较清晰,然后我们分别遍历两个数组,通过record记录,将遍历的每个字符记在对应的record索引上并将其值++,然后再遍历第二个数组时,对应的record--,这样子如果说,两个数组组成相同,最后应该所有record都是0.

class Solution {
public 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 int getNextNumber(int n) {
int res = 0;
while (n > 0) {
int temp = n % 10;
res += temp * temp;
n = n / 10;
}
return res;
}
}
思路和还是差不多,因为要判断快乐数,如果一个数陷入无限循环始终不为1,那么这个数就不是快乐数,我们可以设计一个hashset,当它不为1的时候,并且在之前没有出现过的时候(不然会陷入循环),Wimbledon将它添加在创建的hashset中,并且更新n为平方和,我们可以单独将计算的方法封装起来,每次%10,最后<0的时候退出循环,然后将每次%10的结果乘方相加,最后返回即可。

&spm=1001.2101.3001.5002&articleId=146024420&d=1&t=3&u=6ed88d1260944ae3a814f21fda02d6ee)
775

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



