哈希前置知识
哈希:快速判断一个元素是否出现集合里(牺牲空间换取时间)
● 哈希函数:把传入的key映射到符号表的索引上
● 哈希碰撞:多个key映射到相同索引上(处理碰撞方式:拉链法和线性探测法)
数据结构:
● 数组:大小有限(空间大但哈希值少)
● set (集合):不允许重复元素的集合(用数组造成空间浪费时考虑set)
● map(映射):键值对的几何
有效的字母异位词
//数组是简单哈希表,题中字符串只有小写字符,则定义一个数组记录字符串s里字符出现的次数。
class Solution {
public boolean isAnagram(String s, String t) {
if(s.length()!=t.length()){
return false;
}
int[] z=new int[26];
for(int i=0;i<s.length();i++){
z[s.charAt(i)-'a']++;
}
for(int i=0;i<t.length();i++){
z[t.charAt(i)-'a']--;
if(z[t.charAt(i)-'a']<0){
return false;
}
}
return true;
}
}
两个数组的交集
//nums1放set1,然后遍历nums2将交集添加到set2,最后把set2转成int数组
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> set1=new HashSet<>();
Set<Integer> set2=new HashSet<>();
for(int num:nums1){
set1.add(num);
}
for(int num:nums2){
if(set1.contains(num)){
set2.add(num);
}
}
return set2.stream().mapToInt(x -> x).toArray();
}
}
快乐数
//用哈希法判断sum是否重复,重复是false, 否则一直找到sum为1为止。
class Solution {
private int getNext(int n){
int sum=0;
while(n>0){
int d=n%10;
n=n/10;
sum+=d*d;
}
return sum;
}
public boolean isHappy(int n) {
Set<Integer>set=new HashSet<>();
while(n!=1&&!set.contains(n)){
set.add(n);
n=getNext(n);
}
return n==1;
}
}
两数之和
//返回下标,因此用到map
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer,Integer> h=new HashMap<>();
for(int i=0;i<nums.length;i++){
if(h.containsKey(target-nums[i])){
return new int[]{h.get(target-nums[i]),i};
}
h.put(nums[i],i);
}
return new int[0];
}
}
四数相加II
//(a+b)+(c+d)=0,key为ab两数之和,value为两数之和出现的次数
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
Map<Integer,Integer>h=new HashMap<>();
for(int i:nums1){
for(int j:nums2){
int sum=i+j;
h.put(sum,h.getOrDefault(sum,0)+1);
}
}
int r=0;
for(int i:nums3){
for(int j:nums4){
r+=h.getOrDefault(-i-j,0);
}
}
return r;
}
}
赎金信
//类似字母异位词,但不能重复
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int cnt[]=new int[26];
if(ransomNote.length()>magazine.length()){
return false;
}
for(char c:magazine.toCharArray()){
cnt[c-'a']++;
}
for(char c:ransomNote.toCharArray()){
cnt[c-'a']--;
if(cnt[c-'a']<0){
return false;
}
}
return true;
}
}
三数之和
//双指针:for按住一个动另两个(ij剪枝在前lr去重在找到三元后)
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res= new ArrayList<>();
Arrays.sort(nums);
for(int i=0;i<nums.length;i++){
if(nums[i]>0){
return res;
}
if(i>0&&nums[i]==nums[i-1]){
continue;
}
int l=i+1,r=nums.length-1;
while(l<r){
int sum=nums[i]+nums[l]+nums[r];
if(sum<0){
l++;
}
else if(sum>0){
r--;
}
else{
res.add(Arrays.asList(nums[i],nums[l],nums[r]));
while(l<r&&nums[l]==nums[l+1])l++;
while(l<r&&nums[r]==nums[r-1])r--;
l++;
r--;
}
}
}
return res;
}
}
四数之和
//类似三数之和sum设为long防溢出
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res=new ArrayList<>();
Arrays.sort(nums);
for(int i=0;i<nums.length-3;i++){
if(i>0&&nums[i]==nums[i-1])continue;
for(int j=i+1;j<nums.length-2;j++){
if(j>i+1&&nums[j]==nums[j-1])continue;
int l=j+1,r=nums.length-1;
while(l<r){
long sum=(long)nums[i]+nums[j]+nums[l]+nums[r];
if(sum<target){
l++;
}
else if(sum>target){
r--;
}
else{
res.add(Arrays.asList(nums[i],nums[j],nums[l],nums[r]));
while(l<r&&nums[l]==nums[l+1])l++;
while(l<r&&nums[r]==nums[r-1])r--;
l++;
r--;
}
}
}
}
return res;
}
}