leetcode-探索哈希表

1.存在重复元素
/*
执行用时:9 ms, 在所有 Java 提交中击败了50.41%的用户
内存消耗:44.2 MB, 在所有 Java 提交中击败了66.45%的用户
*/
class Solution {
    public boolean containsDuplicate(int[] nums) {
        Set<Integer> judge = new HashSet();
        for(Integer num:nums){
            if(judge.contains(num)){
                return true;
            }
            judge.add(num);
        }
        return false;
    }
}
2.只出现一次的数字
/*
执行用时:8 ms, 在所有 Java 提交中击败了19.22%的用户
内存消耗:39.9 MB, 在所有 Java 提交中击败了98.52%的用户
*/
class Solution {
    public int singleNumber(int[] nums) {
        Set<Integer> judge = new HashSet();
        for(Integer num:nums){
        	//当添加数字不成功时,说明哈希表中有该数字
            if(!judge.add(num)){
            	//将该数字从表中移除
                 judge.remove(num);
            }
        }
        //剩下的数字便是单独的那个数字
        return judge.iterator().next();
    }
}


/*
运用异或计算,相同为0.题目中相同的数字个数都为两个,则异或后的值为那个单独值。
任何数和0做异或运算,结果仍然是原来的数。
任何数和其自身做异或运算,结果是0。
异或运算满足交换律和结合律。
执行用时:4 ms, 在所有 Java 提交中击败了27.78%的用户
内存消耗:40.9 MB, 在所有 Java 提交中击败了38.99%的用户
*/
class Solution {
    public int singleNumber(int[] nums) {
        int sum = 0;
        for(Integer num: nums){
            sum = sum^num;
        }
        return sum;
    }
}
3.两个数组的交集
/*
retainAll
执行用时:3 ms, 在所有 Java 提交中击败了97.23%的用户
内存消耗:40.3 MB, 在所有 Java 提交中击败了5.42%的用户
*/
class Solution {
  public int[] intersection(int[] nums1, int[] nums2) {
    HashSet<Integer> set1 = new HashSet<Integer>();
    for (Integer n : nums1) set1.add(n);
    HashSet<Integer> set2 = new HashSet<Integer>();
    for (Integer n : nums2) set2.add(n);

    set1.retainAll(set2);

    int [] output = new int[set1.size()];
    int idx = 0;
    for (int s : set1) output[idx++] = s;
    return output;
  }
}
4.快乐数
/*

执行用时:1 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:36.9 MB, 在所有 Java 提交中击败了47.77%的用户
*/
class Solution {
    public boolean isHappy(int n) {
        Set<Integer> judge = new HashSet<>();
        int sum =0;
        while (true){
            // 得到每个位置上的数字的平方和
            while (n>0){
                int temp = n%10;
                sum += temp*temp;
                n = n/10;
            }
            // 当平方和为1时,即为快乐数
            if (sum==1) return true;
            // 当哈希表中不含有平方和时,将其添加
            if (!judge.contains(sum)){
                judge.add(sum);
            }
            // // 当哈希表中含有该平方和时,即可判定此数不为快乐数,会出现死循环。
            else return false;
            // 将n替换成每个位置上的数字的平方和
            n = sum;
            sum = 0;
        }
    }
}
5.同构字符串
/*
将(ss[i],tt[i]),(tt[i],ss[i])分别存入到hashMap中
执行用时:13 ms, 在所有 Java 提交中击败了46.07%的用户
内存消耗:40.1 MB, 在所有 Java 提交中击败了26.04%的用户
*/
class Solution {
    public boolean isIsomorphic(String s, String t) {
        Map<Character,Character> que = new HashMap<>();
        Map<Character,Character> antiQue = new HashMap<>();
        char[] ss = s.toCharArray();
        char[] tt = t.toCharArray();
        for (int i = 0;i<ss.length;i++){
            // 当前元素在que中时
            if (que.containsKey(ss[i])){
                // 如果antiQue不含有对应的元素时,返回false
                if (!antiQue.containsKey(tt[i])){
                    return false;
                }else {
                    // 如果antiQue中对应的键值对和que中的不匹配时,返回false
                    if (antiQue.get(tt[i])!=ss[i]) return false;
                }
            }else{
                // 当前元素不在que中,而对应的元素在antiQue中时,返回false
                if (antiQue.containsKey(tt[i])){
                    return false;
                }
                // 将元素加入hashMap中
                else {
                   que.put(ss[i],tt[i]);
                    antiQue.put(tt[i],ss[i]);
                }
                
            }
        }
        return true;
    }
}
6.字符串中的第一个唯一字符
/*
龟速解题
执行用时:56 ms, 在所有 Java 提交中击败了6.60%的用户
内存消耗:40.7 MB, 在所有 Java 提交中击败了8.74%的用户
*/
答题思路:首先将每个字符出现及其出现的次数存入hashMap,然后遍历hashMap,将其次数为1的字符存入到set中,然后遍历字符数组,按照顺序查看当前字符是否在set中,从而查找第一个出现次数为1的字符。
class Solution {
    public int firstUniqChar(String s) {
        char[] temp = s.toCharArray();
        Map<Character,Integer> hashMap = new HashMap<>();
        Set<Character> set = new HashSet<>();
        // 将每个字符出现及其出现的次数存入hashMap
        for (int i = 0;i<s.length();i++){
            if (hashMap.containsKey(temp[i])){
                int num = hashMap.get(temp[i]);
                hashMap.put(temp[i],num+1 );
            }else {
                hashMap.put(temp[i],1);
            }
        }
        // 遍历hashMap,将其次数为1的字符存入到set中
        for (Map.Entry<Character,Integer> entry:hashMap.entrySet()){
            if (entry.getValue()==1) {
                set.add(entry.getKey());
            }

        }
        return set.size()==0?-1:find(temp, set);
    }
	// 遍历字符数组,按照顺序查看当前字符是否在set中,从而查找第一个出现次数为1的字符
    private int find(char[] temp, Set<Character> key) {
        for (int i =0;i<temp.length;i++){
            if (key.contains(temp[i])){
                return i;
            }
        }
        return 0;
    }
}



/*
利用getOrDefault
执行用时:33 ms, 在所有 Java 提交中击败了50.88%的用户
内存消耗:40.5 MB, 在所有 Java 提交中击败了21.80%的用户
*/
class Solution {
    public int firstUniqChar(String s) {
        char[] temp = s.toCharArray();
        Map<Character, Integer> hashMap = new HashMap<>();
        for (int i = 0; i < s.length(); i++) {
            hashMap.put(temp[i],hashMap.getOrDefault(temp[i],0)+1);
        }
        // 根据temp的顺序查找时候有value值为1的
        for (int i =0 ; i<s.length();i++){
            if (hashMap.get(temp[i])==1) return i;
        }
        return -1;
    }
}
7.存在重复元素 II
/*
执行用时:9 ms, 在所有 Java 提交中击败了92.90%的用户
内存消耗:44.5 MB, 在所有 Java 提交中击败了25.55%的用户
*/
解题思路:hashMap中存入数字及其在数组中最后出现的索引,当前数字在hashMap中时,判断当前索引值与上一次该数字的索引值的差值与k的大小关系,小于等于k则返回true,否则更新索引值,循环结束时返回false
    
class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        HashMap<Integer,Integer> hashMap = new HashMap<>();
        for (int i = 0;i<nums.length;i++){
            if (hashMap.containsKey(nums[i])){
                if (k>=i-hashMap.get(nums[i])) return true;
            }
            hashMap.put(nums[i],i );
        }
        return false;
    }
}
8.两个数组的交集 II
/*
执行用时:4 ms, 在所有 Java 提交中击败了61.70%的用户
内存消耗:39 MB, 在所有 Java 提交中击败了47.93%的用户
*/
解题思路:将一个数组中的数字按照<数字,频率>键值对的形式存入hashMap,然后遍历数组2,如果当前数字存在于hashMap且对应的频率大于等于1,则说明该数字在数组12中都存在,且个数符合要求。
    
class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        HashMap<Integer,Integer> hashMap = new HashMap<>();
        for (int i =0 ;i<nums1.length;i++){
            hashMap.put(nums1[i],hashMap.getOrDefault(nums1[i],0)+1);
        }
        
        ArrayList<Integer> res = new ArrayList<>();
        for (int i = 0;i<nums2.length;i++){
            if (hashMap.containsKey(nums2[i])&&hashMap.get(nums2[i])-1>=0){
                hashMap.put(nums2[i],hashMap.get(nums2[i])-1);
                res.add(nums2[i]);
            }
        }
        int[] ans = new int[res.size()];
        int sum = 0;
        for (int i:res){
            ans[sum++] = i;
        }
        return ans;
    }
}
9.两个列表的最小索引总和
/*
执行用时:12 ms, 在所有 Java 提交中击败了54.86%的用户
内存消耗:39.5 MB, 在所有 Java 提交中击败了35.06%的用户
*/
解题思路:使用hashMap1存储字符数组list1,遍历字符数组list2,利用containKey函数来判断list2数组中的值是否在list2中,并利用minsum不断更新索引之和的最小值,并将其存入hashMap2中,然后根据最终的minsum值,去hashmap寻找相应的地点。
   
class Solution {
    public String[] findRestaurant(String[] list1, String[] list2) {
        HashMap<String, Integer> s1 = new HashMap<>();
        HashMap<String, Integer> ss = new HashMap<>();

        for (int i = 0; i < list1.length; i++) {
            s1.put(list1[i], i);
        }
        int minsum = Integer.MAX_VALUE;
        
        // 利用minsum不断更新索引之和的最小值
        for (int i = 0; i < list2.length; i++) {
            if (s1.containsKey(list2[i]) && s1.get(list2[i]) + i <= minsum) {
                minsum = s1.get(list2[i]) + i;
                ss.put(list2[i],minsum);

            }
        }
        
        // 将符合条件的地点存到ArrayList中,方便转换成String[]
        ArrayList<String> temp = new ArrayList<>();
        for (Map.Entry<String, Integer> entry:ss.entrySet()){
            if (entry.getValue()==minsum){
                temp.add(entry.getKey());
            }
        }

        if (temp.size()==0) return null;

        String[] ans = new String[temp.size()];
        int count = 0;
        for (String s:temp){
            ans[count++] = s;
        }
        return ans;
    }
}
10.字母异位词分组
/*
执行用时:9 ms, 在所有 Java 提交中击败了75.61%的用户
内存消耗:41.8 MB, 在所有 Java 提交中击败了50.25%的用户
*/
解题思路:遍历字符数组strs,对其中的每一个元素排序,然后将排序后一样的元素存在同一key值中。

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        Map<String,List<String>> temp = new HashMap<>();
        List<List<String>> ans = new LinkedList<>();
        for (int i =0 ; i<strs.length;i++){
            char[] res = strs[i].toCharArray();
            Arrays.sort(res);
            String s = new String(res, 0, res.length);
            if (temp.containsKey(s)){
                List<String> strings = temp.get(s);
                strings.add(strs[i]);
                temp.put(s,strings);
            }else {
                List<String> strings = new LinkedList<>();
                strings.add(strs[i]);
                temp.put(s,strings);
            }
        }
        ans.addAll(temp.values());
        return ans;
    }
}
11.有效的数独
/*
执行用时:5 ms, 在所有 Java 提交中击败了13.48%的用户
内存消耗:39.8 MB, 在所有 Java 提交中击败了5.14%的用户
*/
解题思路:有一说一太菜了。
判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
那就分别创建三个哈希表,存储相应相应的行、列、子格及其相应的出现的数字,当有重复的数字时,即为无效数独。
    
class Solution {
    public boolean isValidSudoku(char[][] board) {
        HashMap<Integer, List<Integer>> col = new HashMap<>();
        HashMap<Integer, List<Integer>> row = new HashMap<>();
        HashMap<Integer, List<Integer>> block = new HashMap<>();
        //创建空列表
        List<Integer> temp = new LinkedList<>();
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (board[i][j] != '.') {
                    
                    //数字从char直接转换成int,会变成对应的ASCII数字码,而不是原来的数值。解决方法就是当前char数字减'0':用两个char数字的ASCII码相减,差值就是原来char数值直接对应的int数值。
                    int num = board[i][j] - '0';
                    
                    //得到当前位置的数字所属的子块序号
                    int blockNum = i / 3 * 3 + j / 3;
                    
                    //利用getOrDefault方法来确保不会出现空异常
                    if (col.getOrDefault(i, temp).contains(num) || row.getOrDefault(j, temp).contains(num) || block.getOrDefault(blockNum, temp).contains(num)) {
                        return false;
                    }
                    //当前行、列、子格没有值时,添加值。
                    if (col.get(i) == null) {
                        List<Integer> list = new LinkedList<>();
                        list.add(num);
                        col.put(i, list);
                    }
                    if (row.get(j) == null) {
                        List<Integer> list = new LinkedList<>();
                        list.add(num);
                        row.put(j, list);
                    }
                    if (block.get(blockNum) == null) {
                        List<Integer> list = new LinkedList<>();
                        list.add(num);
                        block.put(blockNum, list);
                    }
                    //更新行、列、子格状态
                    col.get(i).add(num);
                    row.get(j).add(num);
                    block.get(blockNum).add(num);
                }
            }
        }

        return true;
    }
}



/*
大佬做法
执行用时:2 ms, 在所有 Java 提交中击败了96.62%的用户
内存消耗:39.1 MB, 在所有 Java 提交中击败了20.21%的用户
*/
class Solution {
    public boolean isValidSudoku(char[][] board) {
        // 记录某行,某位数字是否已经被摆放
        boolean[][] row = new boolean[9][9];
        // 记录某列,某位数字是否已经被摆放
        boolean[][] col = new boolean[9][9];
        // 记录某 3x3 宫格内,某位数字是否已经被摆放
        boolean[][] block = new boolean[9][9];

        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (board[i][j] != '.') {
                    //序号 0-8,而数1-9,所以减1
                    int num = board[i][j] - '1';
                    int blockIndex = i / 3 * 3 + j / 3;
                    if (row[i][num] || col[j][num] || block[blockIndex][num]) {
                        return false;
                    } else {
                        row[i][num] = true;
                        col[j][num] = true;
                        block[blockIndex][num] = true;
                    }
                }
            }
        }
        return true;
    }
}
12.寻找重复的子树
/*
执行用时:31 ms, 在所有 Java 提交中击败了30.14%的用户
内存消耗:50.4 MB, 在所有 Java 提交中击败了10.20%的用户
*/
解题思路:将二叉树序列化,依次存入到hashMap中,如果有重复的,则加入到ans中。注意:只需要加入一次,所以要设置加入条件temp.containsKey(s)&&temp.get(s)==1class Solution {
    public List<TreeNode> findDuplicateSubtrees(TreeNode root) {
        List<TreeNode> ans = new LinkedList<>();
        HashMap<String,Integer>  temp = new HashMap<>();
        Serialization(root,temp,ans);
        return ans;
    }

    private String Serialization(TreeNode root, HashMap<String, Integer> temp, List<TreeNode> ans) {
        if (root==null) return" ";
        String s = root.val+"{"+ Serialization(root.left, temp, ans)+"}"+
                "{"+ Serialization(root.right, temp, ans)+"}";
        if (temp.containsKey(s)&&temp.get(s)==1){
            ans.add(root);
        }
        temp.put(s, temp.getOrDefault(s, 0)+1);
        return s;
    }
}
13.宝石与石头
/*
执行用时:2 ms, 在所有 Java 提交中击败了50.06%的用户
内存消耗:37.3 MB, 在所有 Java 提交中击败了45.72%的用户
*/
解题思路:遍历S,经其中的石头类型和次数存入HashMap中,然后遍历J,取出宝石的次数。
    
class Solution {
    public int numJewelsInStones(String J, String S) {
        HashMap<Character,Integer> res = new HashMap<>();
        int ans = 0;
        for (int i =0;i<S.length();i++){
            res.put(S.charAt(i), res.getOrDefault(S.charAt(i), 0)+1);
        }
        for (int i = 0;i<J.length();i++){
            ans+=res.getOrDefault(J.charAt(i), 0);
        }
        return ans;
    }
}
14.最小覆盖子串
/*
执行用时:17 ms, 在所有 Java 提交中击败了55.16%的用户
内存消耗:39.5 MB, 在所有 Java 提交中击败了48.61%的用户
*/
解题思路:滑动窗口,用两个HashMap分别存储t中字符出现的次数和窗口中字符出现的次数
注意:Integer的比较需要使用equals
    
class Solution {
    public String minWindow(String s, String t) {
        HashMap<Character,Integer> needs = new HashMap<>();
        HashMap<Character,Integer> window = new HashMap<>();
        for (int i =0;i<t.length();i++){
            needs.put(t.charAt(i), needs.getOrDefault(t.charAt(i), 0)+1);
        }
        int left = 0, right = 0,valid = 0;
        int begin = 0,len=Integer.MAX_VALUE,end = 0;
        while (right<s.length()){
            Character c = s.charAt(right);
            right++;
            if (needs.containsKey(c)){
                window.put(c, window.getOrDefault(c, 0)+1);
                if (needs.get(c).equals(window.get(c))){
                    valid++;
                }
            }

            while (valid==needs.size()){
                if (right-left<len){
                    begin=left;
                    len = right-left;
                    end = right;
                }
                Character d = s.charAt(left);
                left++;
                if (needs.containsKey(d)){
                    if (needs.get(d).equals(window.get(d))){
                        valid--;
                    }
                    window.put(d, window.get(d)-1);
                }
            }
        }

        return len==Integer.MAX_VALUE?"":s.substring(begin, end);
    }
}
15.字符串的排列
/*
执行用时:25 ms, 在所有 Java 提交中击败了51.71%的用户
内存消耗:39.3 MB, 在所有 Java 提交中击败了21.43%的用户
*/
解题思路:滑动窗口,用两个HashMap分别存储t中字符出现的次数和窗口中字符出现的次数
    
class Solution {
    public boolean checkInclusion(String s1, String s2) {
        HashMap<Character,Integer> needs = new HashMap<>();
        HashMap<Character,Integer> window = new HashMap<>();
        for (int i = 0;i<s1.length();i++){
            needs.put(s1.charAt(i), needs.getOrDefault(s1.charAt(i), 0)+1);
        }
        int left = 0,right = 0,valid = 0;
        while (right<s2.length()){
            Character c =  s2.charAt(right);
            right++;
            if (needs.containsKey(c)){
                window.put(c, window.getOrDefault(c, 0)+1);
                if (window.get(c).equals(needs.get(c))){
                    valid++;
                }
            }
            while (right-left>=s1.length()){
                if (valid==needs.size()){
                    return true;
                }
                Character d = s2.charAt(left);
                left++;
                if (needs.containsKey(d)){
                    if (window.get(d).equals(needs.get(d))){
                        valid--;
                    }
                    window.put(d, window.get(d)-1);
                }
            }
        }
        return false;
    }
}
16.找到字符串中所有字母异位词
/*
执行用时:30 ms, 在所有 Java 提交中击败了48.54%的用户
内存消耗:40.3 MB, 在所有 Java 提交中击败了17.93%的用户
*/
解题思路:滑动窗口,用两个HashMap分别存储t中字符出现的次数和窗口中字符出现的次数
    
class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        HashMap<Character,Integer> needs =  new HashMap<>();
        HashMap<Character,Integer> window = new HashMap<>();
        for (int i = 0;i<p.length();i++){
            needs.put(p.charAt(i),needs.getOrDefault(p.charAt(i), 0)+1);
        }
        int left = 0,right = 0,valid = 0;
        List<Integer> ans = new LinkedList<>();
        while (right<s.length()){
            Character c = s.charAt(right);
            right++;
            if (needs.containsKey(c)){
                window.put(c, window.getOrDefault(c,0 )+1);
                if (window.get(c).equals(needs.get(c))){
                    valid++;
                }
            }
            while (right-left>=p.length()){
                if (valid==needs.size()){
                    ans.add(left);
                }
                Character d = s.charAt(left);
                left++;
                if (needs.containsKey(d)){
                    if (window.get(d).equals(needs.get(d))){
                        valid--;
                    }
                    window.put(d, window.get(d)-1);
                }
                
            }
        }
        return ans;
    }
}    
17.无重复字符的最长子串
/*
执行用时:12 ms, 在所有 Java 提交中击败了28.36%的用户
内存消耗:39.3 MB, 在所有 Java 提交中击败了29.60%的用户
*/
    
class Solution {
    public int lengthOfLongestSubstring(String s) {
        HashMap<Character,Integer> window = new HashMap<>();
        int left = 0,right = 0;
        int ans = 0;
        while (right<s.length()){
            Character c = s.charAt(right);
            right++;
            window.put(c, window.getOrDefault(c, 0)+1);
            while (window.get(c)>1){
                Character d = s.charAt(left);
                left++;
                window.put(d, window.get(d)-1);
            }
            ans = Integer.max(ans, right-left);
        }
        return ans;
    }
}
18.四数相加 II
/*
执行用时:77 ms, 在所有 Java 提交中击败了75.72%的用户
内存消耗:57.6 MB, 在所有 Java 提交中击败了62.65%的用户
*/
解题思路:相加为0,则将两个数组的所有数字组合之和存入HashMap中,然后遍历c,d,寻找是否有他们的相反数,并取出相应的值。
class Solution {
    public int fourSumCount(int[] A, int[] B, int[] C, int[] D) {
        HashMap<Integer,Integer> ans = new HashMap<>();
        int res= 0;
        for (int a:A){
            for (int b:B){
                ans.put(a+b,ans.getOrDefault(a+b,0)+1);
            }
        }

        for (int c:C){
            for (int d:D){
                if (ans.containsKey(-(c+d))){
                   res += ans.get(-(c+d));
                }
            }
        }
        return res;
    }
}
19.前 K 个高频元素
//贴的评论区大佬的做法,关键对于排序那一块不大熟悉。
/*
执行用时:17 ms, 在所有 Java 提交中击败了59.18%的用户
内存消耗:41.6 MB, 在所有 Java 提交中击败了21.46%的用户
*/

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        HashMap<Integer,Integer> ans = new HashMap<>();
        int[] temp = new int[k];
        for (int i =0;i<nums.length;i++){
            ans.put(nums[i],ans.getOrDefault(nums[i],0)+1);
        }
        ArrayList<Map.Entry<Integer,Integer>> res = new ArrayList<>(ans.entrySet());
        //根据出现的key值对res进行排序
        res.sort(((o1, o2) -> o2.getValue()-o1.getValue()));
        for (int i=0;i<k;i++){
            temp[i] = res.get(i).getKey();
        }
        return temp;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值