哈希表
- 1. 理论
- 哈希碰撞的解决方法
- 拉链法
- 线性探测法
- 2. 有效的字母异位词
- [242. 有效的字母异位词](https://leetcode.cn/problems/valid-anagram/)
- 3. 两个数组的交集
- [349. 两个数组的交集](https://leetcode.cn/problems/intersection-of-two-arrays/)
- 4. 快乐数
- [202. 快乐数](https://leetcode.cn/problems/happy-number/)
- 5.两数之和
- 6. 赎金信
- [383. 赎金信](https://leetcode.cn/problems/ransom-note/)
- 7. 三数之和
- [15. 三数之和](https://leetcode.cn/problems/3sum/)
- 双指针法
1. 理论
哈希碰撞的解决方法
拉链法
冲突采用链表的方式剞劂
线性探测法
放入元素的时候,如果碰撞了,就往后找一个空位放该元素
要求tableSize一定要大于dataSize ,要不然哈希表上就没有空置的位置来存放冲突的数据了
2. 有效的字母异位词
242. 有效的字母异位词
先遍历一遍第一个字符串,把每个字符放入Map中,重复则个数+1
然后遍历第二个,遇上就个数-1,如果是字母异位词的话,最终每个字母的个数一定为0
class Solution {
public boolean isAnagram(String s, String t) {
if(s.length() != t.length()){
return false;
}
Map<Character, Integer> map = new HashMap<>();
char[] arr1 = s.toCharArray();
char[] arr2 = t.toCharArray();
for(int i = 0; i < arr1.length; i++){
if(map.containsKey(arr1[i])){
map.put(arr1[i], map.get(arr1[i]) + 1);
}else{
map.put(arr1[i], 1);
}
}
for(int i = 0; i < arr2.length; i++){
if(map.containsKey(arr2[i])){
if(map.get(arr2[i]) == 0){
return false;
}
map.put(arr2[i], map.get(arr2[i]) - 1);
}else{
return false;
}
}
return true;
}
}
追求更快的话,可以使用长度为26的数组,然后也是差不多的思想,一个遇上就+1,第二个遇上减1
3. 两个数组的交集
349. 两个数组的交集
- 先遍历第一个数组,存入map中,每个字符的个数为1
- 遍历第二个数组,如果map中有当前数字,并且为第一次出现,说明是交集
- 如何遍历map,找到出现次数为2的数字,放入数组(采用ArrayList,包装类会报错)
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Map<Integer, Integer> map = new HashMap<>();
int sameNums = 0;
for(int i = 0; i < nums1.length; i++){
if(!map.containsKey(nums1[i])){
map.put(nums1[i], 1);
}
}
for(int i = 0; i < nums2.length; i++){
if(map.containsKey(nums2[i]) && map.get(nums2[i]) == 1){
map.put(nums2[i], 2);
sameNums++;
}
}
int[] res = new int[sameNums];
int index = 0;
for(Integer i: map.keySet()){
if(map.get(i) == 2){
res[index] = i;
index++;
}
}
return res;
}
}
4. 快乐数
202. 快乐数
用一个Set存储出现过的数字,如果一个数字经过变化后再次变为了原来的数字,那他肯定不是快乐数
class Solution {
public boolean isHappy(int n) {
Set<Integer> set = new HashSet<>();
while(n != 1 && !set.contains(n)){
set.add(n);
n = getNextNumber(n);
}
return n == 1;
}
private int getNextNumber(int n) {
int sum = 0;
while(n > 0){
int tail = n % 10;
sum += tail * tail;
n /= 10;
}
return sum;
}
}
5.两数之和
- 因为题目要找的两个数之和为target,我们可以把nums数组中第一个元素的
target - num
以及 num的下标分别放入HashMap<Integer,Integer>
的Key 和 Value中 - 按照这种方法遍历数组,进行判断,如果有元素和HashMap中的Key值相等的话,那么他们的和为target
- 输出结果
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
//放入第一个数,K中为差,V中为下标
map.put(target - nums[0],0);
for (int i = 1; i < nums.length; i++) {
//如果该元素和HashMap中的某个Key值相等的话,结束
if(map.containsKey(nums[i])){
int index = map.get(nums[i]);
return new int[]{index,i};
}else {
//放入HashMap
map.put(target - nums[i],i);
}
}
return new int[0];
}
}
6. 赎金信
383. 赎金信
类似字母异位词
- 第一个数组全放入map,如果相等就次数+1
- 第二个数组如果遇到对应的字符,就次数-1
- 如果最终map中次数都<=0 那么可以完成
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
if(ransomNote.length() > magazine.length()){
return false;
}
Map<Character, Integer> map = new HashMap<>();
char[] arr1 = ransomNote.toCharArray();
char[] arr2 = magazine.toCharArray();
for(int i = 0; i < arr1.length; i++){
if(map.containsKey(arr1[i])){
map.put(arr1[i], map.get(arr1[i]) + 1);
}else{
map.put(arr1[i], 1);
}
}
for(int i = 0; i < arr2.length; i++){
//如果存在,个数-1
if(map.containsKey(arr2[i])){
map.put(arr2[i], map.get(arr2[i]) - 1);
}
}
for(Character c: map.keySet()){
if(map.get(c) > 0){
return false;
}
}
return true;
}
}
7. 三数之和
15. 三数之和
这题用哈希法很麻烦
双指针法
- 先进行排序
- i 遍历 数组, left从i+1开始,right从 n-1开始, left 和 right向中间移动,这个过程可能发现多组,可能有重复
- 如果
nums[i] == nums[i - 1]
当前和上一个相同则重复了(i left right 都要进行重复的判断)
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> list = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
//开头>0,不可能等于0
if (nums[i] > 0) {
return list;
}
// 去重i 和上一个(左边)的比较
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum < 0) {
left++;
} else if (sum > 0) {
right--;
} else {
list.add(Arrays.asList(nums[i], nums[left], nums[right]));
//去重left 和下一个(左边)的比较
while (right > left && nums[right] == nums[right - 1]) right--;
//去重right 和下一个(右边)的比较
while (right > left && nums[left] == nums[left + 1]) left++;
left++;
right--;
}
}
}
return list;
}
}