Leetcode数组哈希表242/赎金383/异位词分组49/两个数组的交集349

本文解析了LeetCode中四个经典的哈希表题目,包括有效字母异位词、字母异位词分组、找到字符串中所有字母异位词及两个数组的交集。通过多种解法展示如何运用哈希表解决实际问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

哈希表理论知识点总结:

  1. 暂未总结

一、242题(有效的字母异位词)

题目描述
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
示例 1: 输入: s = “anagram”, t = “nagaram” 输出: true
示例 2: 输入: s = “rat”, t = “car” 输出: false
说明: 你可以假设字符串只包含小写字母。

题解

mine:击败82.81%的用户。看了一下都是这个解法

class Solution {
    public boolean isAnagram(String s, String t) {
        int[] nums = new int[26];
        int i=0;
        if(s.length()!=t.length()) return false;
        while(i<s.length()){
            nums[s.charAt(i)-'a']++;
            i++;
        }
        i=0;
        while(i<t.length()){
            nums[t.charAt(i)-'a']--;
            i++;
        }
        for(i=0;i<26;i++){
            if(nums[i]!=0){
                return false;
            }
        }
        return true;
    }
}

算法思路:用nums数组记录,s里出现的元素++,t出现的元素–,如果最后nums数组全为0,就返回true。
:①数组写法不能是int nums[26] = new int[26];//int nums[] = new int[26]②字符串长度是length()方法
基本相同题目:383(简单,不多做说明)

二、49题(字母异位词分组)

题目描述
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的所有字母得到的一个新单词。
示例 1:
输入: strs = [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”]
输出: [[“bat”],[“nat”,“tan”],[“ate”,“eat”,“tea”]]

题解1(数组哈希)

mine:超过时间限制了,通过了111/126个测试用例
原因:这个题放在数组哈希题的后面,误导了我~~~~应该用map来求解,不然每个都比较一遍nums特别费时

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        // List<Integer.> order = new ArrayList<Integer.>();
        // order.add(matrix[x][y])
        List<List<String>> ans = new ArrayList<List<String>>();
        int[] vis = new int[strs.length];
        int i=0;
        while(i<strs.length){
            if(vis[i]==0){
                vis[i]=1;
                List<String> list = new ArrayList<String>();
                list.add(strs[i]);
                int nums[] = new int[26];
                for(int k=0;k<strs[i].length();k++){
                    nums[strs[i].charAt(k)-'a']++;
                }
                for(int j=i+1;j<strs.length;j++){
                    // 先拷贝nums
                    int[] nums2 = nums.clone();
                    if(vis[j]==0&&strs[j].length()==strs[i].length()){
                        for(int k=0;k<strs[j].length();k++){
                            nums2[strs[j].charAt(k)-'a']--;
                        }
                        boolean flag=true;
                        for(int k=0;k<26;k++){
                            if(nums2[k]!=0){
                                flag=false;
                            }
                        }
                        if(flag){
                            vis[j]=1;
                            list.add(strs[j]);
                        }
                    }
                }
                ans.add(list);
            }
            i++;
        } 
        return ans;
    }
}

算法思路:一个个遍历比较,并且引入vis[]数组记录是否已经加入过list。
备注:还是基础不牢固,List的声明补充

①
List<List<String>> ans = new ArrayList<List<String>>();
//而不是List<List<String>> ans = new ArrayList<ArrayList<String>>();
②
List<String> list = new ArrayList<String>();

解法2 (map哈希)

题解

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
    	HashMap<String,ArrayList> result  = new HashMap<>();
    	for(String s:strs) {
    		int[] nums = new int[26];
    		for(char c: s.toCharArray()) {
    			nums[c-'a']++;
    		}
    		//由于数组是不可哈希的,我们将其转化成String(该类型可哈希)
    		// 因为array1[]={1,2,3}和array2[]={1,2,3}如果set.add(array1/array2)后size是2,表示这两个哈希值不同。而string1="1,2,3"
    		StringBuilder sb = new StringBuilder();
    		for(int count:count_table) {
    			sb.append("#");
    			sb.append(count);
    		}
    		String key = sb.toString();
    		if(!result.containsKey(key)) {
    			result.put(key, new ArrayList<>());
    		}
    		result.get(key).add(s);
    	}
    	return new ArrayList(result.values());
    }
}

算法思路:用nums[26]记录每个字母出现的次数,由于array不可哈希,无法作为key,将其转化为String,转化方法为在每个nums[i]前添加’#',因为可能出现1,0,12和1,0,1,2相同的情况解释一下:我一开始觉得[1,0,12]和[1,0,1,2]还是可以区分的呀,那就是10120和1012。但其实是不对的,反例:[1,0,1,2,0,13,0,0]和[1,0,1,2,0,0,13,0],所以还是要用#号将数字隔开。这样就可以将转化后的String表示的nums数组作为key,从而有了对应的value。最后values就是本题的答案。

解法3(排序法)

题解

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
    	HashMap<String,ArrayList> result  = new HashMap<>();
    	for(String s: strs) {
    		//sort string
    		char[] temp = s.toCharArray();
    		Arrays.sort(temp);
    		String key = new String(temp);
    		if( !result.containsKey(key)) {
    			result.put(key,new ArrayList<>());
    		}
    		result.get(key).add(s);
    	}
    	return new ArrayList(result.values());
    }
}

算法思路:由于同一组的单词,每个经过排序后,都会变成相同的单词,所以可以把该排序后的单词作为key,寻找对应的value集合。最后输出的values即为本题答案。

三、438题(找到字符串中所有字母异位词)

题目描述
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

题解1

mine:偷懒了,结果稀碎了..打败了5.02%的用户😀

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        // String sub = a.substring(index1, index2);[index1,index2)
        List<Integer> list = new ArrayList<Integer>();
        if(s.length()<p.length()) return list;//不是return null
        int num = s.length()-p.length()+1;
        String strs[] = new String[num];
        for(int i=0;i<num;i++){
            strs[i] = s.substring(i,i+p.length());
        }
        char[] chars = p.toCharArray();
        Arrays.sort(chars);
        String key = new String(chars);
        char[] str;
        String strchar;
        for(int i=0;i<num;i++){
            str = strs[i].toCharArray();
            Arrays.sort(str);
            strchar = new String(str);
            if(strchar.equals(key)){
                list.add(i);
            }
        }
        return list;
    }
}

算法思路:排序法。

四、349题(两个数组的交集)

题目描述
给定两个数组 nums1 和 nums2 ,返回它们的交集。我们可以不考虑输出结果的顺序 。

题解1

import java.util.HashSet;
import java.util.Set;

class Solution {
    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> resSet = new HashSet<>();
        //遍历数组1
        for (int i : nums1) {
            set1.add(i);
        }
        //遍历数组2的过程中判断哈希表中是否存在该元素
        for (int i : nums2) {
            if (set1.contains(i)) {
                resSet.add(i);
            }
        }
        int[] arr = new int[resSet.size()];
        int j = 0;
        for(int i : resSet){
            arr[j++] = i;
        }
        
        return arr;
    }
}

注意点:①返回new int[0] ②HashSet的应用,contains()和size()和add()
③也可以用retainAll方法。

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        if (nums1.length == 0|| nums2.length == 0) {
            return new int[0];
        }
        Set<Integer> set1 = new HashSet<>();
        Set<Integer> set2 = new HashSet<>();
        //遍历数组1
        for (int i : nums1) {
            set1.add(i);
        }
        for (int i : nums2) {
            set2.add(i);
        }
        // 调用retainAll方法:会保留set1中存在于set2中的元素
        // 注意该方法是操作set1,返回bool值
        set1.retainAll(set2);
        int[] arr = new int[set1.size()];
        int j = 0;
        for(int i : set1){
            arr[j++] = i;
        }
        return arr;
    }
}

注意set不能用set2=set1,这是浅拷贝。只能用set2.addAll(set1);

题解2(Hash数组法)

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        int[] hash1 = new int[1002];
        int[] hash2 = new int[1002];
        for(int i=0;i<nums1.length;i++){
            hash1[nums1[i]]++;
        }
        for(int i=0;i<nums2.length;i++){
            hash2[nums2[i]]++;
        }
        // 如果遇到hash1[i]和hash2[i]均不为0,则加入结果数组中
        // 因此,如果使用固定数组,需要先判断有多个这样的,所以可以使用
        // 变化数组 ArrayList
        List<Integer> list = new ArrayList<>();
        for(int i = 0; i < 1002; i++)
            if(hash1[i] > 0 && hash2[i] > 0)
                list.add(i);
        // 然后把ans变成数组
        int[] ans = new int[list.size()];
        int index=0;
        for(int i:list){
            ans[index++]=i;
        }
        return ans;
    }
}

注意点:使用了ArrayList,不能直接转为int[],只能根据arraylist的size一个个拷贝到int数组里,没有现成的方法函数可以使用。

总结

242很简单。49要用到hashmap,中等难度。438和49差不多。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值