leetcode-探索哈希表

    科技2024-07-05  69

    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; } }
    Processed: 0.009, SQL: 8