北京工厂网站建设wordpress 游客留言
哈希算法
public class HashTable {// 定义一个内部类 Entry,用于存储键值对及其哈希码static class Entry {int hash; // 哈希码Object key; // 键Object value; // 值Entry next; // 指向下一个节点的指针,用于处理哈希冲突public Entry(int hash, Object key, Object value) {this.hash = hash;this.key = key;this.value = value;}}// 存储 Entry 对象的数组,即哈希表的实际存储结构Entry[] table = new Entry[16];// 当前哈希表中存储的元素数量int size = 0;// 负载因子,默认值为 0.75float loadFactor = 0.75f;// 扩容阈值,当 size 超过该值时触发扩容操作int threshold = (int) (loadFactor * table.length);/*** 根据哈希码和键获取对应的值。** @param hash 哈希码* @param key 键* @return 对应的值,如果找不到则返回 null*/public Object get(int hash, Object key) {int idx = hash & (table.length - 1); // 计算索引位置if (table[idx] == null) {return null; // 如果该位置为空,则返回 null}Entry p = table[idx];while (p != null) { // 遍历链表if (p.key.equals(key)) {return p.value; // 找到匹配的键,返回对应的值}p = p.next; // 继续遍历链表中的下一个节点}return null; // 如果没有找到匹配的键,返回 null}/*** 将键值对插入哈希表中。** @param hash 哈希码* @param key 键* @param value 值*/public void put(int hash, Object key, Object value) {int idx = hash & (table.length - 1); // 计算索引位置if (table[idx] == null) {table[idx] = new Entry(hash, key, value); // 如果该位置为空,直接插入新节点} else {Entry p = table[idx];while (true) {if (p.key.equals(key)) {p.value = value; // 如果找到相同的键,更新其值return;}if (p.next == null) {break; // 如果到达链表末尾,跳出循环}p = p.next; // 继续遍历链表中的下一个节点}p.next = new Entry(hash, key, value); // 在链表末尾插入新节点}size++; // 更新元素数量if (size > threshold) {resize(); // 如果超过阈值,进行扩容操作}}/*** 扩容操作,将哈希表的容量扩大一倍,并重新分配所有元素。*/private void resize() {Entry[] newTable = new Entry[table.length << 1]; // 创建新的数组,长度为原来的两倍for (int i = 0; i < table.length; i++) {Entry p = table[i];if (p != null) {Entry a = null;Entry b = null;Entry aHead = null;Entry bHead = null;// 遍历当前桶中的链表,并根据新的哈希值重新分配到两个不同的链表中while (p != null) {if ((p.hash & table.length) == 0) {if (a != null) {a.next = p;} else {aHead = p;}a = p;} else {if (b != null) {b.next = p;} else {bHead = p;}b = p;}p = p.next;}// 将重新分配后的链表插入到新的哈希表中if (a != null) {a.next = null;newTable[i] = aHead;}if (b != null) {b.next = null;newTable[i + table.length] = bHead;}}}table = newTable; // 更新哈希表为新的数组threshold = (int) (loadFactor * table.length); // 更新扩容阈值}/*** 根据哈希码和键删除对应的键值对。** @param hash 哈希码* @param key 键* @return 被删除的值,如果找不到则返回 null*/public Object remove(int hash, Object key) {int idx = hash & (table.length - 1); // 计算索引位置if (table[idx] == null) {return null; // 如果该位置为空,则返回 null}Entry p = table[idx];Entry prev = null; // 用于记录前一个节点while (p != null) {if (p.key.equals(key)) {if (prev == null) {table[idx] = p.next; // 如果要删除的是第一个节点,直接更新头节点} else {prev.next = p.next; // 否则更新前一个节点的 next 指针}size--; // 更新元素数量return p.value; // 返回被删除的值}prev = p; // 更新前一个节点p = p.next; // 继续遍历链表中的下一个节点}return null; // 如果没有找到匹配的键,返回 null}
}
两数之和-Leetcode 1
给定一个整数数组
nums
和一个整数目标值target
,请你在该数组中找出 和为目标值target
的那 两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9 输出:[0,1] 解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。示例 2:
输入:nums = [3,2,4], target = 6 输出:[1,2]示例 3:
输入:nums = [3,3], target = 6 输出:[0,1]
public int[] twoSum(int[] nums, int target) {HashMap<Integer, Integer> map=new HashMap<Integer, Integer>();for (int i = 0; i < nums.length; i++) {int k=target-nums[i];if(map.containsKey(k)) {return new int[] {map.get(k),i};}map.put(nums[i], i);}return null;}
无重复字符的最长字串-Leetcode 3
给定一个字符串
s
,请你找出其中不含有重复字符的 最长子串
的长度。示例 1:
输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是"abc"
,所以其长度为 3。示例 2:
输入: s = "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是"b"
,所以其长度为 1。示例 3:
输入: s = "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是"wke"
,所以其长度为 3。请注意,你的答案必须是 子串 的长度,"pwke"
是一个子序列,不是子串。
方法一:
public int lengthOfLongestSubstring(String s) {HashMap<Character, Integer> map=new HashMap<Character, Integer>();int begin=0;int maxLength=0;for (int end = 0; end < s.length(); end++) {char ch=s.charAt(end);if(map.containsKey(ch)) {begin=Math.max(begin, map.get(ch)+1);map.put(ch, end);}else{map.put(ch, end);}maxLength=Math.max(maxLength, end-begin+1);}return maxLength;}
方法二:
public int lengthOfLongestSubstring(String s) {int[] map=new int[128];Arrays.fill(map, -1);int begin = 0;int maxLength = 0;for (int end = 0; end < s.length(); end++) {char ch = s.charAt(end);if(map[ch]!=-1) {begin=Math.max(begin, map[ch]+1);map[ch]=end;}else {map[ch]=end;}maxLength = Math.max(maxLength, end - begin + 1);}return maxLength;}
字母异位词分组-Leetcode 49
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的所有字母得到的一个新单词。
示例 1:
输入: strs =["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]示例 2:
输入: strs =[""]
输出: [[""]]示例 3:
输入: strs =["a"]
输出: [["a"]]
方法一:
public List<List<String>> groupAnagrams(String[] strs) {HashMap<String, List<String>> map=new HashMap<String, List<String>>();for(String str :strs) {char[] chars=str.toCharArray();Arrays.sort(chars);String key=new String(chars);List<String> strings=map.computeIfAbsent(key, k -> new ArrayList<>());strings.add(str);}return new ArrayList<>(map.values());}
方法二:
static class ArrayKey {int[] key = new int[26];public ArrayKey(String str) {for (int i = 0; i < str.length(); i++) {char ch = str.charAt(i);key[ch - 'a']++;}}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;ArrayKey arrayKey = (ArrayKey) o;return Arrays.equals(key, arrayKey.key);}@Overridepublic int hashCode() {return Arrays.hashCode(key);}
}public List<List<String>> groupAnagrams(String[] strs) {HashMap<ArrayKey, List<String>> map = new HashMap<>();for (String str : strs) {List<String> strings = map.computeIfAbsent(new ArrayKey(str), k -> new ArrayList<>());strings.add(str);}return new ArrayList<>(map.values());
}
找出出现一次的数字-Leetcode 136
给你一个 非空 整数数组
nums
,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。
示例 1 :
输入:nums = [2,2,1]
输出:1
示例 2 :
输入:nums = [4,1,2,1,2]
输出:4
示例 3 :
输入:nums = [1]
输出:1
方法一:
public int singleNumber(int[] nums) {HashSet<Integer> set = new HashSet<>();for (int num : nums) {if (!set.add(num)) {set.remove(num);}}return set.toArray(new Integer[0])[0];
}
方法二:
public int singleNumber(int[] nums) {int num = nums[0];for (int i = 1; i < nums.length; i++) {num = num ^ nums[i];}return num;
}
判断字母异位词-Leetcode 242
给定两个字符串
s
和t
,编写一个函数来判断t
是否是s
的字母异位词
。示例 1:
输入: s = "anagram", t = "nagaram" 输出: true示例 2:
输入: s = "rat", t = "car" 输出: false
public boolean isAnagram(String s, String t) {return Arrays.equals(getKey(s), getKey(t));
}private static int[] getKey(String s) {int[] array = new int[26];char[] chars = s.toCharArray();for (char ch : chars) {array[ch - 97]++;}return array;}
第一个不重复字符-Leetcode 387
给定一个字符串
s
,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回-1
。示例 1:
输入: s = "leetcode" 输出: 0示例 2:
输入: s = "loveleetcode" 输出: 2示例 3:
输入: s = "aabb" 输出: -1
public int firstUniqChar(String s) {int[] array=new int[26];char[] chars=s.toCharArray();for(char ch:chars) {array[ch-97]++;}for (int i = 0; i < chars.length; i++) {char ch=chars[i];if(array[ch-97]==1) {return i;}}return -1;}
出现次数最多的单词-Leetcode 819
给你一个字符串
paragraph
和一个表示禁用词的字符串数组banned
,返回出现频率最高的非禁用词。题目数据 保证 至少存在一个非禁用词,且答案 唯一 。
paragraph
中的单词 不区分大小写 ,答案应以 小写 形式返回。示例 1:
输入:paragraph = "Bob hit a ball, the hit BALL flew far after it was hit.", banned = ["hit"] 输出:"ball" 解释: "hit" 出现了 3 次,但它是禁用词。 "ball" 出现了两次(没有其他单词出现这么多次),因此它是段落中出现频率最高的非禁用词。 请注意,段落中的单词不区分大小写, 标点符号会被忽略(即使它们紧挨着单词,如 "ball,"), 并且尽管 "hit" 出现的次数更多,但它不能作为答案,因为它是禁用词。示例 2:
输入:paragraph = "a.", banned = [] 输出:"a"
public String mostCommonWord(String paragraph, String[] banned) {Set<String> banSet=Set.of(banned);String[] split=paragraph.toLowerCase().split("[^A-Za-z]+");HashMap<String, Integer> map=new HashMap<String, Integer>();for(String key:split) {if(banSet.contains(key)) {continue;}map.compute(key, (k,v)-> v==null?1:v+1);}Integer max=0;String maxkey=null;for(Map.Entry<String, Integer> e:map.entrySet()) {Integer value=e.getValue();if(value>max) {max=value;maxkey=e.getKey();}}return maxkey;}