代码随想录-哈希表1
判断一个元素是否出现过的场景
242.有效的字母异位词
基本思路
- 用record数组记录字符串出现过的字母,遍历第一个字符串增加数组对应位置的值,遍历第二个字符串减少数组对应位置的值。最终如果数组所有位置为0,则说明两个字符串是字母异位词。
方法代码
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是字母异位词
}
}
- 时间复杂度:O(n+∣Σ∣),其中 n 是 nums 的长度,∣Σ∣ 为字符集合的大小,本题字符均为小写字母,所以 ∣Σ∣=26。
- 空间复杂度:O(∣Σ∣)
注意点
- Java字符串操作
- 长度使用
s.length()得到 - 取特定位置的值:
s.charAt(index) - 也可以转换为字符数组:
s.toCharArray()
- 长度使用
- 如果输入字符串包含 unicode 字符,把数组改成哈希表即可
- 哈希表创建:
Map<Character, Integer> table = new HashMap<Character, Integer>() - 放入数据:
table.put(key, value) - 取数据:
table.get(key) table.getOrDefault(key, default):如果存在相应的key则返回其对应的value,否则返回给定的默认值table.put(ch, table.getOrDefault(ch, 0) + 1):通过这个操作放入的值是对应key的个数
- 哈希表创建:
349. 两个数组的交集
基本思路
- 这道题限制了数组的长度和数字范围,可以使用数组作为hash表,存储哪些元素在输入数组中出现过。然后使用List记录两个表都出现的元素,最后再使用一个数组存储这些元素并返回。
使用数组
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
int[] hash1 = new int[1003];
int[] hash2 = new int[1003];
for(int num : nums1){
hash1[num] = 1;
}
for(int num : nums2){
hash2[num] = 1;
}
List<Integer> resList = new ArrayList<Integer>();
for(int i = 0; i < 1003; i++){
if (hash1[i] != 0 && hash2[i] != 0){
resList.add(i);
}
}
int index = 0;
int[] res = new int[resList.size()];
for(int num : resList){
res[index++] = num;
}
return res;
}
}
- 时间复杂度:O(m+n)
- 空间复杂度:O(m+n)
使用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;
}
}
- 时间复杂度:O(m+n)
- 空间复杂度:O(m+n)
注意点
- 创建Set
Set<Integer> set1 = new HashSet<>();
- 对集合的操作
resSet.stream():- 将集合
resSet转换为一个流(Stream)。 - 这个流允许对集合中的元素进行操作,比如映射、过滤或收集。
- 将集合
mapToInt(x -> x):- 将流中的每个元素映射为一个整型值。
- 这里假设
resSet中的元素本身就是整数(Integer类型),因此x -> x表示直接取元素的值。
toArray():- 将流中的整型值收集并转换为一个
int[]数组。
- 将流中的整型值收集并转换为一个
第202题. 快乐数
基本思路
- 有结论:对于非快乐数,它们在重复计算各位数字的平方和的过程中不仅会形成一个循环,而且每个循环中的数字都是一样的
- 因为会存在循环,所以可以使用Set判断得到的sum是否在之前的计算过程中得到过(其实也包含了原本给出的数n,以为如果后面计算得到sum为n,则说明已经进入循环),若已经存在则返回false,若sum中途为1则返回true。
- 使用双指针(快慢指针)判断循环是否存在,这个方法更节省空间。“快指针” 每次走两步,“慢指针” 每次走一步,当二者相等时,即为一个循环周期。此时,判断是不是因为 1 引起的循环,是的话就是快乐数,否则不是快乐数
使用Set
class Solution {
public int getSum(int n){
int sum = 0;
while(n > 0){
int temp = n % 10;
sum += temp * temp;
n = n / 10;
}
return sum;
}
public boolean isHappy(int n) {
Set<Integer> record = new HashSet<>();
while(n != 1 && !record.contains(n)){
record.add(n); //先加入set,然后再改为新数字,下次判断是否加入
n = getSum(n);
}
return n == 1;
}
}
- 时间复杂度:O(logn)
- 空间复杂度:O(logn)
使用快慢指针
class Solution {
public int getSum(int n){
int sum = 0;
while(n > 0){
int temp = n % 10;
sum += temp * temp;
n = n / 10;
}
return sum;
}
public boolean isHappy(int n) {
int slow = n;
int fast = getSum(n);
while(fast != 1 && fast != slow){
slow = getSum(slow);
fast = getSum(getSum(fast));
}
return fast == 1;
}
}
- 时间复杂度:O(logn)
- 空间复杂度:O(1)
注意点
- 使用快慢指针法来判断是否存在环,判断循环
1. 两数之和
基本思路
方法代码
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
int j = 0;
int[] res = new int[2];
for(int i = 0; i < nums.length; i++){
j = target - nums[i];
if(map.containsKey(j)){
res[0] = i;
res[1] = map.get(j);
return res;
}else{
//注意:存放当前遍历的这个数的值和下标
//之后往后遍历的时候,再判断之前加入map的元素是否有符合条件的
map.put(nums[i], i);
}
}
return null;
}
}
- 时间复杂度:O(n)
- 空间复杂度:O(n)
注意点
- 使用map:
Map<Integer, Integer> map = new HashMap<>()

浙公网安备 33010602011771号