哈希表的常用方法和示例:用于判断某元素是否存在于集合中
目录
哈希表/数组 (选择):
哈希表适用于快速判断某个、些元素是否存在在集合中,以空间换时间,记录各数据的出现次数
- 哈希表用于特别分散、跨度非常大的数据
- 数组用于有数量限制,有数值范围的数据,eg:字母
常用解法:
- 剪枝法:寻找继续进行操作的界值,判断,当不满足该条件时,后续操作无意义,return
- 滑动窗口法:当寻找满足某条件的固定长度(a)序列时,快指针先行a步,判断是否符合条件;然后快慢指针同行,形成滑动窗口,判断是否符合条件
- 快慢双指针法:当存在循环或重复等状态时,快指针2步,慢指针1步,同时移动,如何二者相遇(即当前数据是都已存在),则存在重复/循环,否则两者相距越来越远,快指针会最先到达结束条件。
- 相对双指针法:适用于有序数据,或者对数据进行排序后处理,避免重复操作和便于确定指针移动方向。
- (双指针法 的作用: 减低时间复杂度,降低一个量级 eg:O(n^2)-> O(n) )
Collection接口/list/set常用方法:
增:add(Object obj),addAll(Collection coll)
删:remove(Object obj), removeAll(Collection coll),clear()清空集合元素;
查:contains(Object obj),containsAll(Collection coll),retainsAll(Collection coll)求交集删:
List 改:Object set(int index, Object ele)
LIst 查:get(int index)
List 插:add(int index, Object ele)
equals(Object obj)元素是否相同,size()集合内元素数,hasCode()返回对象哈希值,
集合转化成数组: toArray()
数组转化集合: Arrays.asList(数组)
Map常用方法:
添加:Object put(Object key,Object value) / void putAll(Map m) 添加所有
删除:Object remove(Object key) / clear():清空map数据,将map.size=0 != map=Null
修改:put(Object key,Object value)
查询:Object get(Object key)
/ boolean containsKey(Object key) /boolean containsValue(Object value) :是否包含该元素
长度:int size()
遍历:Set keySet() / Collection values()
/ Set entrySet()+entry.getKey()+entry.getValue() 强转后才可调用子类方法
map无序 -> 无插入操作
元素遍历方式:3种
① Iterator迭代器方式
Iterator iterator = list.iterator();
while(iterator.hasNext()){ //hasNext():判断是否还下一个元素
System.out.println(iterator.next());//iterator.next():指针下移
}
② 增强for循环(foreach循环)
for(Object obj:list){
System.out.println(obj);
}
for(集合元素的类型 局部变量 : 集合对象) {对obj操作}
将集合对象的值赋给obj(局部变量),对obj的操作不影响原集合,内部仍然调用了迭代器。
③ 普通的循环 用get()方法
for(int i=0; i<list.size(); i++){
System.out.println(list.get(i));
}
LeetCode示例:
242. 有效的字母异位词:判断字符串s 和 t 中每个字符出现的次数是否相同
438. 找到字符串中所有字母异位词:给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。
202. 快乐数:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1(快乐数),也可能是 无限循环 但始终变不到 1。
15. 三数之和:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
242. 有效的字母异位词:判断字符串s
和 t
中每个字符出现的次数是否相同
数组快,hashmap慢但适用于unicode 字符
两字符串长度相等,一个遍历加,一个遍历减,出现负数则不同。
class Solution {
public boolean isAnagram(String s, String t) {
if(s.length() != t.length()){
return false;
}
//数组
// int[] record = new int[26];
for (char c : s.toCharArray()) {
record[c - 'a'] += 1;
}
for (char c : t.toCharArray()) {
record[c - 'a'] -= 1;
}
for (int i : record) {
if (i != 0) {
return false;
}
}
return true;
//哈希表
Map<Character,Integer> maps = new HashMap<>();
Map<Character,Integer> mapt = new HashMap<>();
//getOrDefault(key,default)
//作用:如果存在相应的key则返回其对应的value,否则返回给定的默认值。
for(int i = 0; i<s.length(); i++){
Character ch = s.charAt(i);
int num = maps.getOrDefault(ch,0);
maps.put(ch, num + 1);
}
for(int i = 0; i<t.length(); i++){
Character ch = t.charAt(i);
int num = maps.getOrDefault(ch,0);
if(num == 0){
return false;
}else{
maps.put(ch,num-1);
}
}
return true;
}
}
438. 找到字符串中所有字母异位词:给定两个字符串 s
和 p
,找到 s
中所有 p
的 异位词 的子串,返回这些子串的起始索引。
class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> res = new ArrayList<>();
int plen = p.length();
int slen = s.length();
if( p == null || s == null || plen> slen ){
return res;
}
int[] pcnt = new int[26];
int[] scnt = new int[26];
for(int i = 0; i<plen; i++){
pcnt[p.charAt(i)-'a']++;
scnt[s.charAt(i)-'a']++;
}
if(Arrays.equals(pcnt, scnt)){
res.add(0);
}
// 滑动窗口法:两指针间为固定长度a,快指针先行a步,然后快慢同时移动
for(int i = 0; i < slen-plen; i++){
scnt[s.charAt(i)-'a']--;
scnt[s.charAt(i+plen)-'a']++;
if(Arrays.equals(pcnt, scnt)){
res.add(i+1);
}
}
return res;
}
}
202. 快乐数:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1(快乐数),也可能是 无限循环 但始终变不到 1。
方法一:哈希表
方法二:快慢双指针:
1如果 n
是一个快乐数,即没有循环,那么快跑者最终会比慢跑者先到达数字 1。
如果 n
不是一个快乐的数字,那么最终快跑者(2步)和慢跑者(1步)将在同一个数字上相遇。
class Solution {
public boolean isHappy(int n) {
Set<Integer> sum = new HashSet<>();
while(!sum.contains(n)){
sum.add(n);
if(n == 1){
return true;
}
n = getNextSum(n);
}
return false;
}
public int getNextSum(int n){
int sum = 0;
while(n != 0){
sum += (n%10)*(n%10);
n = n/10;
}
return sum;
}
}
相对双指针法:数组有序,避免重复数据
15. 三数之和:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
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){ //剪枝法,i处是寻找的起始点(最小值),之后的数据均不能满足要求
return res;
}
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{
res.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--;
}
}
}
return res;
}
}
18. 四数之和:给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]]
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++){
//剪枝法,注意数据类型数值范围
//-10^9 <= nums[i] <= 10^9 -10^9 <= target <= 10^9, nums相加会超出int
if ((long) nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) {
break;
}
if(j > i+1 && nums[j] == nums[j-1]){
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){
right--;
}else if(sum < target){
left++;
}else{
res.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--;
}
}
}
}
return res;
}
}