代码随想录自刷3:哈希表

69 阅读2分钟

主旨:哈希表可以想象成一个数组,通常用来快速查询一个元素是否在集合中!通过将元素映射为哈希表上的索引,就可以通过索引快速定位该元素是否在集合中。

242. 有效的字母异位词

242. 有效的字母异位词

思路:题目仅包含小写字母,所以数组用26就够用了。

  • 第一次for循环,将每个元素转为数值放到数组上,进行累加计算出现的次数
  • 第二次for循环,将每个元素转为数值放到数组上,进行减法计算扣除出现的次数
  • 最终for循环比较数组元素是否都为0,如果是表示相等!
public boolean isAnagram(String s, String t) {
        int[] record=new int[26];
        for(char ch : s.toCharArray()){
            record[ch-'a']++;
        }
        for(char ch : t.toCharArray()){
            record[ch-'a']--;
        }
        for(int i=0;i<record.length;i++){
            if(record[i]!=0){
                return false;
            }
        }
        return true;
    }

相关题目:383. 赎金信

383. 赎金信

思路:基本一样,只是这里变成记录magazine中的字母次数

public boolean canConstruct(String ransomNote, String magazine) {
        int[] record=new int[26];
        for(char ch:magazine.toCharArray()){
            record[ch-'a']++;
        }
        for(char ch : ransomNote.toCharArray()){
            if(record[ch-'a']>0)
                record[ch-'a']--;
            else
                return false;
        }
        return true;
    }

相关题目:49. 字母异位词分组

49. 字母异位词分组

思路:

  • 用map先存放目前的集合!最后再转换一下
    • key为字符串重新排序后的样子,valueList集合。
    • 为什么map?因为key是不可重复的。
  • 遍历元素,将当前元素重新排序
  • 排序后的元素是否存在map中
    • 如果无则新建集合作为value,放入集合中
    • 如果有则取出值,把当前原本的元素放入集合中
public List<List<String>> groupAnagrams(String[] strs) {
        Map<String,List<String>> map=new HashMap<>();
        for(int i=0;i<strs.length;i++){
            char[] chs=strs[i].toCharArray();
            Arrays.sort(chs);
            String s=String.valueOf(chs);
            if(!map.containsKey(s)){
                map.put(s,new ArrayList<>());
            }
            map.get(s).add(strs[i]);
        }

        return new ArrayList<>(map.values()); 
    }

相关题目:438. 找到字符串中所有字母异位词

438. 找到字符串中所有字母异位词

思路:主要利用两个数组来实现,record记录p所有字母次数,window进行移动(它有点类似滑动窗口的概念)

  • left指针记录起始位置
  • 遍历元素,window记录当前元素
  • 当目前字符串长度(i-left+1)等于p长度时,进行检查
    • 如果两个数组相等则表示找到了加入到list
    • 不管有无,windowleft指针指向的元素次数减一,并且left指针要往前移动
public List<Integer> findAnagrams(String s, String p) {
        List<Integer> list=new ArrayList<>();
        int[] record=new int[26];
        for(char ch : p.toCharArray()){
            record[ch-'a']++;
        }
        int[] window=new int[26];
        int left=0;
        for(int i=0;i<s.length();i++){
            window[s.charAt(i)-'a']++;
            if(i-left+1==p.length()){
                if(Arrays.equals(record,window)){
                    list.add(left);
                }
                window[s.charAt(left)-'a']--;
                left++;
            }
        }
        return list;
    }

349. 两个数组的交集

349. 两个数组的交集

思路:答案不需要重复,所以可以用set先暂存结果,最后转为题目要的类型 使用java8特性的stream流,将集合转为另一个集合

  • StreammapToInt(ToIntFunction mapper)返回一个IntStream流
  • IntStreamtoArray()返回一个包含此流元素的数组
public int[] intersection(int[] nums1, int[] nums2) {
        if(nums1==null || nums1.length==0 || nums2==null || nums2.length==0)
            return new int[2];
        Set<Integer> set=new HashSet<>();
        Set<Integer> resSet=new HashSet<>();    //暂存结果
        for(int i: nums1){
            set.add(i);
        }
        for(int i:nums2){
            if(set.contains(i)){
                resSet.add(i);
            }
        }
    
        return resSet.stream()
                .mapToInt(x->x) //返回IntStream
                .toArray();        //IntStream.toArray()
    }

202. 快乐数

202. 快乐数

思路:用set记录计算过的数字,如果当前元素在set中存在,表示是曾经计算过的数字,则陷入循环无解。最后判断一下是否为1

public boolean isHappy(int n) {
        Set<Integer> set=new HashSet<>();   //记录出现过的数字
        while(n!=1 && !set.contains(n)){  
            set.add(n);
            n=nextNumber(n);
        }
        return n==1;
        
    }
    public int nextNumber(int n){
        int res=0;
        while(n>0){
            int tmp=n%10;
            res+=tmp*tmp;
            n=n/10;
        }
        return res;
    }

1. 两数之和

1. 两数之和

思路:要记住位置又要记住值,所以用map合适,值为key,下标为value。记得每次遍历都将当前元素放入集合中。

public int[] twoSum(int[] nums, int target) {
        Map<Integer,Integer> map=new HashMap<>();
        for(int i=0;i<nums.length;i++){
            int sum=target-nums[i];
            if(map.containsKey(sum)){
                int[] res=new int[]{map.get(sum),i};
                return res;
            }
            map.put(nums[i],i);
        }
        return new int[2];
    }

454. 四数相加 II

454. 四数相加 II

思路:分为abcd,现在要a+b+c+d=0,两个为一组,(a+b)+(c+d)=0推导得到(a+b)=0-(c+d)

  • 先把(a+b)放到map集合中,value记录等于该值的次数
  • 计算0-(c+d),如果集合中有符合的,则表示找到一组符合条件的四数相加,取出value累加
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        int res=0;
        Map<Integer,Integer> map=new HashMap<>();
        for(int a:nums1){
            for(int b:nums2){
                map.put(a+b,map.getOrDefault(a+b,0)+1);
            }
        }
        for(int c:nums3){
            for(int d:nums4){
                int sum=0-(c+d);
                if(map.containsKey(sum)){
                    res+=map.get(sum);
                }
            }
        }
        return res;
    }

15. 三数之和

15. 三数之和

思路: 不可以包含重复的三元组,所以数组要先进行排序,然后每次遍历都要进行判断当前元素之前是否出现过,有则跳过!

  • 找到第一个元素后,接下来用双向指针指向当前元素的下一个,和数组结尾元素
  • 记得找到符合的三元组后,指针都要移动,此时指针注意:
    • 不能超出移动范围
    • 并且要判断下一个元素是否重复(有则要跳过)
public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> list=new ArrayList<>();
        if(nums.length<3)
            return list;
        Arrays.sort(nums);
        for(int i=0;i<nums.length;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){
                    right--;
                }else if(sum<0){
                    left++;
                }
                else{
                    list.add(new ArrayList<>(Arrays.asList(nums[i],nums[left],nums[right])));
                    while(left<right && nums[left]==nums[left+1])
                        left++;
                    while(left<right && nums[right-1]==nums[right])
                        right--;
                    left++;
                    right--;
                }
            }
        }
        return list;
    }

18. 四数之和

18. 四数之和

思路:和上面的三数之和差不多,第二个选取的元素只要重复第一个选取的步骤即可

public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> list=new ArrayList<>();
        Arrays.sort(nums);
        for(int i=0;i<nums.length;i++){
            //找第一个元素
            if(i>0 && nums[i]==nums[i-1])
                continue;
            for(int j=i+1;j<nums.length;j++){
                //找第二个元素
                if(j>i+1 && nums[j]==nums[j-1])
                    continue;
                //找第三和四个元素
                int left=j+1;
                int right=nums.length-1;
                while(left<right){
                    long sum=(long)nums[i]+nums[j]+nums[left]+nums[right];
                    if(sum>target){
                        right--;
                    }else if(sum<target)
                        left++;
                    else{
                        list.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 list;
    }