确实Java集合这个容器的函数使用还不是很熟练,有些函数都不知道有没有,更不用说咋用了,只能说多刷题,把常见的都掌握了,一般手里都要拿一个jdk的API文档。
哈希表(散列表):可以用来快速判断一个元素是否出现在一个集合里,将要存储的值映射在哈希表上涉及到哈希函数(Hash Function),index=hashFunction(name),hashFunction=hashCode(name)%tableSize,hashCode是通过特定编码方式,可以将其他数据格式转化为不同的数值,这样就可以将想要存储的数据映射为哈希表上的索引数字。如果将多个数据映射到哈希表同一个索引上,这就是哈希碰撞,解决方案:1.拉链法,相同索引了在后面成链表,拉链法要选择适当的哈希表大小,这样既不会因为数组空值而浪费大量内存,也不会因为链表太长而在查找上浪费太长时间。2.线性探测法:要保证tableSize>dataSize,依靠哈希表中的空位来解决碰撞问题,冲突了,就向下找一个空的位置放置数据。
三种哈希结构:数组,set(集合),map(映射)
牺牲空间换取时间。
242
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']++;
}
for(int i=0;i<t.length();i++){
record[t.charAt(i)-'a']--;
}
for(int i=0;i<26;i++){
if(record[i]!=0){
return false;
}
}
return true;
}
函数:charAt(index),返回指定索引处的char值
349
题目中说输出结果去重且不考虑输出顺序。使用set实现哈希表。
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> reset = new HashSet<>();
for(int i=0;i<nums1.length;i++){
set1.add(nums1[i]);
}
for(int i:nums2){
if(set1.contains(i)){
reset.add(i);
}
}
int[] arr = new int[reset.size()];
int j=0;
for(int i:reset){
arr[j++]=i;
}
return arr;
//return reset.stream().mapToInt(x->x).toArray();//将结果集合转为数组
}
350
这道题在力扣上还有进阶的思考题,说要是磁盘内存不能一次性读入所有数据,就要采用哈希的方法去解决。
题解:返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致
排序+双指针
public int[] intersect(int[] nums1, int[] nums2) {
Arrays.sort(nums1);
Arrays.sort(nums2);
int length1=nums1.length,length2=nums2.length;
int[] res=new int[Math.min(length1,length2)];
int index1=0,index2=0,index=0;
while(index1<length1&&index2<length2){
if(nums1[index1]<nums2[index2]){
index1++;
}else if(nums1[index1]>nums2[index2]){
index2++;
}else{
res[index]=nums1[index1];
index++;
index1++;
index2++;
}
}
return Arrays.copyOfRange(res,0,index);
}
哈希:要同时记录出现的元素和出现的次数,不能用Set,可以数组或者Map。
public int[] intersect(int[] nums1, int[] nums2) {
if(nums1.length>nums2.length){
return intersect(nums2,nums1);
}
Map<Integer,Integer> map=new HashMap<>();
for(int i:nums1){
int count = map.getOrDefault(i,0)+1;
map.put(i,count);
}
int[] res=new int[nums1.length];
int index=0;
for(int num:nums2){
int count = map.getOrDefault(num,0);
if(count>0){
res[index++]=num;
count--;
if(count>0){
map.put(num,count);
}else{
map.remove(num);
}
}
}
return Arrays.copyOfRange(res,0,index);
}
202:注意怎么找到下一个数。
public boolean isHappy(int n) {
Set<Integer> set1=new HashSet<>();
while(n!=1&&!set1.contains(n)){
set1.add(n);
n=getnextnumber(n);
}
return n==1;
}
public int getnextnumber(int n){
int res=0;
while(n>0){
int temp=n%10;
res=temp*temp+res;
n=n/10;
}
return res;
}
1:
第三遍了还是没什么思路,要返回索引,就要同时知道索引和对应的值。
使用Key-Value结构,用map来实现哈希表。
那么判断元素是否出现,这个元素就要作为key,所以数组中的元素作为key,有key对应的就是value,value用来存下标。
map目的用来存放我们访问过的元素,因为遍历数组的时候,需要记录我们之前遍历过哪些元素和对应的下标,这样才能找到与当前元素相匹配的。
public int[] twoSum(int[] nums, int target) {
int[] res = new int[2];
// if(nums==null||nums.length==0){
// return res;
// }
Map<Integer,Integer> map=new HashMap<>();
for(int i = 0;i<nums.length;i++){
int temp=target-nums[i];
if(map.containsKey(temp)){
res[1]=i;
res[0]=map.get(temp);
break;
}
map.put(nums[i],i);
}
return res;
}
四个点:1.看到两数之和,就想到可以有一个临时值来代表和与遍历到数字的差值,这个临时值出现就能退出程序,用哈希表2.题目中要求返回目标位置的索引,就表示既要知道值又要知道索引,得采用Map结构。
3.本题的map用来存储遍历过的数,用一个临时值表示目标和和当前遍历数的差值,看map(已经遍历过的数值里)集合有没有这个临时值,有的话取出map的值和当前遍历的值一起存进最终要返回的数组里,没有的话把当前值加入map集合里。
4.本题中map的key用来存数据值,value用来存索引,map.get(key)可以返回value值。