一、理论基础
1.1 哈希表(散列表)
哈希表是根据关键码的值而直接进行访问的数据结构
解决什么问题:快速判断一个元素是否出现在集合里
- 通过元素的 hashCode() 参与计算得到 hash值
- 让 hash值 参与哈希函数的计算得到数组的索引下标,然后进行判断
1.2 哈希函数
1.3 哈希碰撞
- 元素个数大于数组大小
- 两个元素计算出来的索引下标相同
1.3.1 拉链法
- 元素个数大于数组大小
- 数组大小设置要适当:既不会因为数组空值而浪费大量内存,也不会因为链表太长而在查找上浪费太多时间。
1.3.2 线性探测法
- 保证元素个数小于数组大小
- 哈希碰撞则使用数组下一个空位存放
1.3 常见的三种哈希结构
当我们想使用哈希法来解决问题的时候,我们一般会选择如下三种数据结构。
1.4 总结
总结一下,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。
但是哈希法也是牺牲了空间换取了时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。
如果在做面试题目的时候遇到需要判断一个元素是否出现过的场景也应该第一时间想到哈希法!
二、LeetCode题序
242 (简单)有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
class Solution {
public boolean isAnagram(String s, String t) {
int[] count=new int[26];
for(int i=0;i<s.length();i++){
count[s.charAt(i)-'a']++;
}
for(int i=0;i<t.length();i++){
count[t.charAt(i)-'a']--;
}
for(int i=0;i<count.length;i++){
if(count[i]!=0) return false;
}
return true;
}
}
1002 (简单)查找常用字符
给你一个字符串数组 words ,请你找出所有在 words 的每个字符串中都出现的共用字符( 包括重复字符),并以数组形式返回。你可以按 任意顺序 返回答案。
- 输入:words = [“bella”,“label”,“roller”] 输出:[“e”,“l”,“l”]
- 由小写英文字母组成
class Solution {
public List<String> commonChars(String[] words) {
int[] count=new int[26];
int[] buf=new int[26];
List<String> list=new ArrayList();
boolean isOne=true;
for(String str:words){
if(isOne) {
for(int i=0;i<str.length();i++){
count[str.charAt(i)-'a']++;
}
isOne=false;
continue;
}
for(int i=0;i<str.length();i++){
buf[str.charAt(i)-'a']++;
}
for(int i=0;i<26;i++){
count[i]=Math.min(count[i],buf[i]);
buf[i]=0;
}
}
for(int i=0;i<26;i++){
for(int j=0;j<count[i];j++){
list.add(String.valueOf((char)(i+'a')));
}
}
return list;
}
}
349 (简单)两个数组的交集
给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> set=new HashSet();
Set<Integer> result=new HashSet();
for(int data:nums1){
set.add(data);
}
for(int data:nums2){
if(set.contains(data)) result.add(data);
}
return result.stream().mapToInt(x->x).toArray();
}
}
202 (简单)快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」 定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。
- 如果 n 是 快乐数 就返回 true ;不是,则返回 false 。
class Solution {
public boolean isHappy(int n) {
Set<Integer> sums=new HashSet();
while(n!=1 && n>=0){
sums.add(n);
n=sum(n);
if(sums.contains(n)) return false;
}
return n==1?true:false;
}
public int sum(int n){
int sum=0;
while(true){
sum=sum+(n%10)*(n%10);
n=n/10;
if(n==0) break;
}
return sum;
}
}
1 (简单)两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] result=new int[2];
if(nums==null || nums.length==0) return result;
Map<Integer,Integer> map=new HashMap();
for(int i=0;i<nums.length;i++){
int need=target-nums[i];
if(map.containsKey(need)){
result[0]=map.get(need);
result[1]=i;
}
map.put(nums[i],i);
}
return result;
}
}
454 (中等)四数相加II
给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:
- 0 <= i, j, k, l < n
- nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
Map<Integer,Integer> map=new HashMap();
int sum=0;
for(int v1:nums1){
for(int v2:nums2){
sum=v1+v2;
Integer value=null;
if((value=map.get(sum))!=null) {
map.put(sum,value+1);
}else{
map.put(sum,1);
}
}
}
int result=0;
for(int v3:nums3){
for(int v4:nums4){
sum=v3+v4;
int need=0-sum;
Integer value=null;
if((value=map.get(need))!=null) {
result+=value;
}
}
}
return result;
}
}
383 (简单)赎金信
给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int[] count=new int[26];
for(int i=0;i<ransomNote.length();i++){
count[ransomNote.charAt(i)-'a']++;
}
for(int i=0;i<magazine.length();i++){
count[magazine.charAt(i)-'a']--;
}
for(int i=0;i<26;i++){
if(count[i]>0) return false;
}
return true;
}
}
15 (中等)三数之和
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result=new ArrayList();
Arrays.sort(nums);
for(int i=0;i<nums.length-2;i++){
if (nums[i] > 0) return result;
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) {
result.add(Arrays.asList(nums[i],nums[left],nums[right]));
while(left<right && nums[left]==nums[left+1]) left++;
while(left<right && nums[right]==nums[right-1]) right--;
left++;
right--;
}else if(sum<0){
left++;
}else if(sum>0){
right--;
}
}
}
return result;
}
}
18 (中等)四数之和
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):【1,2,3,4】与【4,3,2,1】重复
- 0 <= a, b, c, d < n
- a、b、c 和 d 互不相同
- nums[a] + nums[b] + nums[c] + nums[d] == target
- 你可以按 任意顺序 返回答案 。
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> result=new ArrayList();
Arrays.sort(nums);
for(int i=0;i<nums.length-3;i++){
if(nums[i] >0 && nums[i]-target>0) return result;
if(i>0 && nums[i-1] == nums[i]) continue;
for(int j=i+1;j<nums.length-2;j++){
if(j>i+1 && nums[j-1]==nums[j]) continue;
int left=j+1;
int right=nums.length-1;
while(left<right){
int sum=nums[i]+nums[j]+nums[left]+nums[right];
if(sum==target) {
result.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
while(left<right && nums[left]==nums[left+1]) left++;
while(left<right && nums[right]==nums[right-1]) right--;
left++;
right--;
}else if(sum<target){
left++;
}else if(sum>target){
right--;
}
}
}
}
return result;
}
}
|