哈希表
哈希表 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台
设计哈希集合
解法1
class MyHashSet {
private final int MAX_LEN = 100000; // the amount of buckets
private List<Integer>[] set; // hash set implemented by array
/** Returns the corresponding bucket index. */
private int getIndex(int key) {
return key % MAX_LEN;
}
/** Search the key in a specific bucket. Returns -1 if the key does not existed. */
private int getPos(int key, int index) {
// Each bucket contains a list.
List<Integer> temp = set[index];
if (temp == null) {
return -1;
}
// Iterate all the elements in the bucket to find the target key.
for (int i = 0; i < temp.size(); ++i) {
if (temp.get(i) == key) {
return i;
}
}
return -1;
}
/** Initialize your data structure here. */
public MyHashSet() {
set = (List<Integer>[])new ArrayList[MAX_LEN];
}
public void add(int key) {
int index = getIndex(key);
int pos = getPos(key, index);
if (pos < 0) {
// Add new key if key does not exist.
if (set[index] == null) {
set[index] = new ArrayList<Integer>();
}
set[index].add(key);
}
}
public void remove(int key) {
int index = getIndex(key);
int pos = getPos(key, index);
if (pos >= 0) {
// Remove the key if key exists.
set[index].remove(pos);
}
}
/** Returns true if this set did not already contain the specified element */
public boolean contains(int key) {
int index = getIndex(key);
int pos = getPos(key, index);
return pos >= 0;
}
}
/**
* Your MyHashSet object will be instantiated and called as such:
* MyHashSet obj = new MyHashSet();
* obj.add(key);
* obj.remove(key);
* boolean param_3 = obj.contains(key);
*/
设计哈希映射
解法1
class MyHashMap {
private final int MAX_LEN = 100000; // the amount of buckets
private List<Pair<Integer, Integer>>[] map; // hash map implemented by array
/** Returns the corresponding bucket index. */
private int getIndex(int key) {
return key % MAX_LEN;
}
/** Search the key in a specific bucket. Returns -1 if the key does not existed. */
private int getPos(int key, int index) {
// Each bucket contains a list.
List<Pair<Integer, Integer>> temp = map[index];
if (temp == null) {
return -1;
}
// Iterate all the elements in the bucket to find the target key.
for (int i = 0; i < temp.size(); ++i) {
if (temp.get(i).getKey() == key) {
return i;
}
}
return -1;
}
/** Initialize your data structure here. */
public MyHashMap() {
map = (List<Pair<Integer, Integer>>[])new ArrayList[MAX_LEN];
}
/** value will always be positive. */
public void put(int key, int value) {
int index = getIndex(key);
int pos = getPos(key, index);
if (pos < 0) {
// Add new (key, value) pair if key is not existed.
if (map[index] == null) {
map[index] = new ArrayList<Pair<Integer, Integer>>();
}
map[index].add(new Pair(key, value));
} else {
// Update the value if key is existed.
map[index].set(pos, new Pair(key, value));
}
}
/** Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key */
public int get(int key) {
int index = getIndex(key);
int pos = getPos(key, index);
if (pos < 0) {
return -1;
} else {
return map[index].get(pos).getValue();
}
}
/** Removes the mapping of the specified value key if this map contains a mapping for the key */
public void remove(int key) {
int index = getIndex(key);
int pos = getPos(key, index);
if (pos >= 0) {
map[index].remove(pos);
}
}
}
/**
* Your MyHashMap object will be instantiated and called as such:
* MyHashMap obj = new MyHashMap();
* obj.put(key,value);
* int param_2 = obj.get(key);
* obj.remove(key);
*/
存在重复元素
解法1
- 使用HashSet存放遍历过的元素
- 如果碰到元素已经放入HashSet中,返回true,否则返回false
class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
if (set.contains(nums[i])) {
return true;
}
set.add(nums[i]);
}
return false;
}
}
解法2
解法1的基础上优化
- 不使用contains方法,而用add方法返回值是否成功来进行判断
class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
if (!set.add(nums[i])) {
return true;
}
}
return false;
}
}
只出现一次的数字
解法1
- new一个HashMap用来存放出现过的数字和出现次数的映射
- 遍历一遍后map中存放了所有数字及出现次数
- 取出出现次数为1的key返回
class Solution {
public int singleNumber(int[] nums) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (map.get(nums[i]) == null) {
map.put(nums[i], 1);
continue;
}
map.put(nums[i], map.get(nums[i]) + 1);
}
for (int i = 0; i < nums.length; i++) {
if (map.get(nums[i]) == 1) {
return nums[i];
}
}
return 0;
}
}
解法2
- 由于每个元素都出现两次,使用HashSet
- 第一次遇到该元素add,第二次remove
- 最后剩余的元素就是只出现一次的数字
class Solution {
public int singleNumber(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
if (!set.add(nums[i])) {
set.remove(nums[i]);
}
}
return set.iterator().next();
}
}
解法3
- 位运算
- 所有数字都出现两次,则除了只出现一次的数,其他的相加%2应该等于0
- 对数字进行位运算,所有数字每一位都加在一起
- 对每一位%2,得出的结果即为只出现一次的数字
class Solution {
public int singleNumber(int[] nums) {
int[] bit = new int[32];
for (int num: nums) {
for (int i = 0; i < 32; i ++) {
bit[i] += (num >> (31-i)) & 1;
}
}
int result = 0;
for (int i = 0; i < 32; i++) {
result = (result << 1) + bit[i] % 2;
}
return result;
}
}
解法4
按位异或
- 由于其他元素都出现了两次,按位异或后抵消,则可以直接按位异或所有元素
- 最后的异或结果即为只出现一次的数字
class Solution {
public int singleNumber(int[] nums) {
int result = 0;
for (int num : nums) {
result ^= num;
}
return result;
}
}
两个数组的交集
解法1
- new两个hashset,第一个hashset存放第一个数组
- 第二个数组存放进第二个hashset,放入之前判断是否在第一个hashset中存在(hashset不可重复)
- 将第二个hashset放入数组返回
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> set1 = new HashSet<>();
Set<Integer> set2 = new HashSet<>();
for (Integer number : nums1) {
set1.add(number);
}
for (Integer number : nums2) {
if (set1.contains(number)) {
set2.add(number);
}
}
int[] result = new int[set2.size()];
int count = 0;
for (Integer number : set2) {
result[count] = number;
count++;
}
return result;
}
}
快乐数
解法1
暴力循环
class Solution {
int count = 0;
public boolean isHappy(int n) {
int result = 0;
for (int i = 0; i < 30; i++) {
while (n != 0) {
int num = n % 10;
result += num * num;
n = n / 10;
}
if (result == 1) {
return true;
}
n = result;
result = 0;
count++;
}
return false;
}
}
解法2(思路)
解法1的优化,把每次循环出的结果放到一个hashset中,如果有重复就可以提前return,出现重复就形成循环了,不会快乐了
例子的问题,居然没有暴力循环快,这是没想到的
class Solution {
public boolean isHappy(int n) {
HashSet<Integer> set = new HashSet<Integer>();
while(n != 1){
set.add(n);// 把每次得到 新数字插存入set中
int tmp = n, sum = 0;// sum为新数字
// 计算新数字
while(tmp != 0){
sum += (tmp % 10) * (tmp % 10);
tmp /= 10;
}
if (set.contains(sum)) return false; // 新数字与原来的数字相等 会陷入死循环,即 不为快乐数字
n = sum;
}
return true;
}
}
两数之和
解法1
暴力循环
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] result = new int[2];
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
if(nums[i] + nums[j] == target) {
result[0] = i;
result[1] = j;
return result;
}
}
}
return result;
}
}
解法2
- 使用HashMap遍历一遍数组(map的key为元素值,value为元素下标)
- 每一次遍历都求出当前元素和target的差,如果该值在map中存在,则直接返回这两个值
- 否则将当前元素加入到map中
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] result = new int[2];
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int number = target - nums[i];
if (map.containsKey(number)) {
result[0] = i;
result[1] = map.get(number);
return result;
}
map.put(nums[i], i);
}
return result;
}
}
解法3
在解法2的基础上优化一丢丢
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (map.containsKey(target - nums[i])) {
return new int[]{i, map.get(target - nums[i])};
}
map.put(nums[i], i);
}
return new int[0];
}
}
同构字符串
解法1
- 用两个map存放两个字符串的互相映射
- 遍历字符串
- 如果遍历到某个元素存在映射但是和当前另一个元素不匹配则返回false
- 遍历结束则返回true
class Solution {
public boolean isIsomorphic(String s, String t) {
Map<Character, Character> map = new HashMap<>();
Map<Character, Character> map2 = new HashMap<>();
char[] ss = s.toCharArray();
char[] tt = t.toCharArray();
for (int i = 0; i < ss.length; i++) {
if (map.containsKey(ss[i])) {
if (map.get(ss[i]) != tt[i]) {
return false;
}
}
if (map2.containsKey(tt[i])) {
if (map2.get(tt[i]) != ss[i]) {
return false;
}
}
map.put(ss[i], tt[i]);
map2.put(tt[i], ss[i]);
}
return true;
}
}
解法2
- 用两个数组来做map进行优化
class Solution {
public boolean isIsomorphic(String s, String t) {
char[] char_s = s.toCharArray();
char[] char_t = t.toCharArray();
HashMap<Character, Character> map = new HashMap<>();
for (int i = 0; i < char_s.length; i++) {
if (map.containsKey(char_s[i])) {
if (map.get(char_s[i]) != char_t[i]) {
return false;
}
} else if (map.containsValue(char_t[i])) {
return false;
} else {
map.put(char_s[i], char_t[i]);
}
}
return true;
}
}
两个列表的最小索引总和
解法1
- 将list1的元素和下标放入一个map中
- 遍历list2,找出最小的元素放到list1的开头,覆盖掉list1的元素,并定义一个index记录下标
- 如果碰到更小的元素,就将index重置
- 定义一个新的String数组,长度为index,将list1的前index个元素放进来返回
class Solution {
public String[] findRestaurant(String[] list1, String[] list2) {
Map<String, Integer> map = new HashMap();
for (int i = 0; i < list1.length; i++) {
map.put(list1[i], i);
}
int index = 0;
int min = 99999999;
for (int i = 0; i < list2.length; i++) {
if (map.get(list2[i]) != null) {
int road = map.get(list2[i]) + i;
if (road < min) {
min = road;
index = 0;
}
if (road <= min) {
list1[index++] = list2[i];
}
}
}
String[] result = new String[index];
for (int i = 0; i < index; i++) {
result[i] = list1[i];
}
return result;
}
}
解法2
解法1的优化,思路一致
class Solution {
public String[] findRestaurant(String[] list1, String[] list2) {
Map<String, Integer> map = new HashMap();
for (int i = 0; i < list1.length; i++) {
map.put(list1[i], i);
}
int index = 0;
int min = Integer.MAX_VALUE;
for (int i = 0; i < list2.length; i++) {
Integer number = map.get(list2[i]);
if (number != null) {
int road = number + i;
if (road < min) {
min = road;
index = 0;
}
if (road <= min) {
list1[index++] = list2[i];
}
}
}
String[] result = new String[index];
for (int i = 0; i < index; i++) {
result[i] = list1[i];
}
return result;
}
}
字符串中的第一个唯一字符
解法1
- 将字符串转为char数组,新建一个hashmap用于存放char和对应的下标
- 遍历数组,将每一个char和对应的下标放入到hashmap
- 如果当前char在hashmap中存在,则将下标置为-1
- 遍历hashmap,取出下标不为1的最小值返回
class Solution {
public int firstUniqChar(String s) {
char[] ss = s.toCharArray();
Map<Character, Integer> map = new HashMap<>();
for (int i =0; i < ss.length; i++) {
if (map.containsKey(ss[i])) {
map.put(ss[i], -1);
continue;
}
map.put(ss[i], i);
}
int index = 99999;
for (Character key : map.keySet()) {
if (map.get(key) != -1) {
if (map.get(key) < index) {
index = map.get(key);
}
}
}
if (index == 99999) {
return -1;
}
return index;
}
}
解法2
- 用一个长度为26的数组list来表示26个字母
- 将字符串转换为char数组
- 遍历char数组,将每个字母对应的ASCII码-97对应的list下标自增1
- 遍历char数组,当遇到第一个对应下标值为1的char时,返回当前元素下标
- 否则返回-1
class Solution {
public int firstUniqChar(String s) {
int[] list = new int[26];
char[] ss = s.toCharArray();
for (char c : ss) {
list[c - 97]++;
}
for (int i = 0; i < ss.length; i++) {
if (list[ss[i] - 97] == 1) {
return i;
}
}
return -1;
}
}
两个数组的交集Ⅱ
解法1
暴力循环
class Solution {
public int[] intersect(int[] nums1, int[] nums2) {
int index = 0;
for (int i = 0; i < nums1.length; i++) {
for (int j = 0; j < nums2.length; j++){
if (nums1[i] == nums2[j]) {
nums1[index] = nums1[i];
nums2[j] = -1;
index++;
break;
}
}
}
int[] result = new int[index];
for (int i = 0; i < index; i++) {
result[i] = nums1[i];
}
return result;
}
}
解法2
- 新建一个数组
- 遍历list1,对于list1中的每个元素,都在新数组中对应下标自增1
- 新建一个result数组用于存放结果
- 遍历list2,对于list2中每个元素,对应新数组中的下标不为0的元素存放入result数组,并把新数组中元素自减1
- 用Arrays的copyOfRange方法返回结果效率较高
class Solution {
public int[] intersect(int[] nums1, int[] nums2) {
int[] account = new int[1001];
for (int i = 0; i < nums1.length; i++) {
account[nums1[i]]++;
}
int[] result = new int[Math.min(nums1.length, nums2.length)];
int index = 0;
for (int i = 0; i < nums2.length; i++) {
int val = nums2[i];
if(account[val] > 0) {
account[val]--;
result[index] = val;
index++;
}
}
return Arrays.copyOfRange(result, 0, index);
}
}
存在重复元素Ⅱ
解法1
暴力循环,写着玩的(虽然也能跑出来,but不可取)
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < Math.min((i + k + 1), nums.length); j++) {
if (nums[i] == nums[j]) {
return true;
}
}
}
return false;
}
}
解法2
用HashMap
- new一个HashMap用来存放元素和下标
- 遍历数组,每一个元素都去HashMap中get一下value
- 如果没get到,就将元素和下标作为(key,value)put进map中
- 如果get到了,判断是否小于等于k
- 如果小于等于k则返回
- 否则put进map中覆盖原来的k,v
- 遍历结束返回false
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (map.get(nums[i]) == null) {
map.put(nums[i], i);
continue;
}
if (i - map.get(nums[i]) <= k) {
return true;
}
map.put(nums[i], i);
}
return false;
}
}
字母异位词分组
解法1
- 将每个字符串排序后放入一个新的字符串数组,与原数组对应
- 遍历原数组
- 如果对应的排序后的数组对应值存在在map中,则将原数组的元素添加到map的value(List)里
- 如果不存在,则将原数组元素作为key,新数组元素作为value(放入list),put进map
- 遍历map取出所有value放入result(List)返回
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
String[] newstr = new String[strs.length];
List<List<String>> result = new ArrayList<>();
Map<String, List<String>> map = new HashMap<>();
for (int i = 0; i < strs.length; i++) {
char[] ss = strs[i].toCharArray();
Arrays.sort(ss);
newstr[i] = String.valueOf(ss);
}
for (int i = 0; i < strs.length; i++) {
if (map.containsKey(newstr[i])) {
map.get(newstr[i]).add(strs[i]);
continue;
}
List<String> list = new ArrayList<>();
list.add(strs[i]);
map.put(newstr[i], list);
}
// Iterator iterator = map.keySet().iterator();
for (Map.Entry<String, List<String>> entry : map.entrySet()) {
result.add(entry.getValue());
}
return result;
}
}
解法2
- 遍历字符串数组
- 将元素排序,并在map中get元素的value
- 如果value为null,则将字符串和对应的ArrayList(空的)放入map中,并将ArrayList放入result中
- 向ArrayList中添加元素
- 返回result
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
List<List<String>> result = new ArrayList<>();
Map<String, ArrayList<String>> map = new HashMap<>();
char[] ccc;
String sss;
ArrayList<String> temp = null;
for (String str : strs) {
ccc = str.toCharArray();
Arrays.sort(ccc);
sss = String.valueOf(ccc);
temp = map.get(sss);
if (temp == null) {
temp = new ArrayList<>();
map.put(sss, temp);
result.add(temp);
}
temp.add(str);
}
return result;
}
}
有效的数独
解法1
- 对行、列、3*3方格,分别new一个HashMap数组
- 每个数组有9个HashMap对应9行、9列、9个box
- 遍历数组,将每一个元素与每一个map中的key作比较,如果出现重复,则返回false
- 否则返回true
class Solution {
public boolean isValidSudoku(char[][] board) {
Map<Integer, Integer>[] line = new HashMap[9];
Map<Integer, Integer>[] row = new HashMap[9];
Map<Integer, Integer>[] box = new HashMap[9];
for (int i = 0; i < 9; i++) {
line[i] = new HashMap<>();
row[i] = new HashMap<>();
box[i] = new HashMap<>();
}
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
char gt = board[i][j];
if (gt != '.') {
int n = (int)gt;
int box_index = (i / 3) * 3 + j / 3;
row[i].put(n, row[i].getOrDefault(n, 0) + 1);
line[j].put(n, line[j].getOrDefault(n, 0) + 1);
box[box_index].put(n, box[box_index].getOrDefault(n, 0) + 1);
if (row[i].get(n) > 1 || line[j].get(n) > 1 || box[box_index].get(n) > 1) {
return false;
}
}
}
}
return true;
}
}
解法2 位运算
位运算
class Solution {
public boolean isValidSudoku(char[][] board) {
int[] row = new int[10];
int[] line = new int[10];
int[] box = new int[10];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
char c = board[i][j];
if (c == '.') {
continue;
}
int n = c - '0';
int box_index = (i / 3) * 3 + j / 3;
if ((((row[i] >> n) & 1) == 1) || (((line[j] >> n) & 1) == 1) || (((box[box_index] >> n) & 1) == 1)) {
return false;
}
row[i] |= (1<<n);
line[j] |= (1<<n);
box[box_index] |= (1<<n);
}
}
return true;
}
}
寻找重复的子树
解法1
官解:寻找重复的子树 - 寻找重复的子树 - 力扣(LeetCode)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
Map<String, Pair<TreeNode, Integer>> seen = new HashMap<String, Pair<TreeNode, Integer>>();
Set<TreeNode> repeat = new HashSet<TreeNode>();
int idx = 0;
public List<TreeNode> findDuplicateSubtrees(TreeNode root) {
dfs(root);
return new ArrayList<TreeNode>(repeat);
}
public int dfs(TreeNode node) {
if (node == null) {
return 0;
}
int[] tri = {node.val, dfs(node.left), dfs(node.right)};
String hash = Arrays.toString(tri);
if (seen.containsKey(hash)) {
Pair<TreeNode, Integer> pair = seen.get(hash);
repeat.add(pair.getKey());
return pair.getValue();
} else {
seen.put(hash, new Pair<TreeNode, Integer>(node, ++idx));
return idx;
}
}
}
宝石与石头
解法1
暴力循环
class Solution {
public int numJewelsInStones(String jewels, String stones) {
char[] bulingbuling = jewels.toCharArray();
char[] shitou = stones.toCharArray();
int count = 0;
for (int i = 0; i < bulingbuling.length; i++) {
for (int j = 0; j < shitou.length; j++) {
if (bulingbuling[i] == shitou[j]) {
count++;
}
}
}
return count;
}
}
解法2
- HashMap存放宝石
- 遍历石头,key存在计数器自增1
- 返回计数器
class Solution {
public int numJewelsInStones(String jewels, String stones) {
char[] bulingbuling = jewels.toCharArray();
char[] shitou = stones.toCharArray();
Map<Character, Integer> map = new HashMap<>();
int count = 0;
for (int i = 0; i < bulingbuling.length ;i++) {
map.put(bulingbuling[i], 1);
}
for (int i = 0; i < shitou.length; i++) {
if (map.containsKey(shitou[i])) {
count++;
}
}
return count;
}
}
无重复字符的最长子串
解法1
- 使用HashMap和快慢指针
- 遍历字符串,将每一个字符都放入HashMap中,并计算当前最长子串,如果大于记录,则替换
- 返回记录的最大值
class Solution {
public int lengthOfLongestSubstring(String s) {
int slow = 0;
int fast;
int max = 0;
HashMap<Character, Integer> map = new HashMap<>();
for (fast = 0; fast < s.length() ;fast++) {
if (map.containsKey(s.charAt(fast))) {
slow = Math.max(slow, map.get(s.charAt(fast)));
}
max = Math.max(max, fast - slow + 1);
map.put(s.charAt(fast), fast + 1);
}
return max;
}
}
解法2
用char+128把char转换为正整数,每一个元素都对应ints的一位
太妙了!太妙了!!!
class Solution {
public int lengthOfLongestSubstring(String s) {
int[] ints = new int[256];
int max = 0;
int nowLen = 0;
int itemValue;
int start = 0;
char[] chars = s.toCharArray();
for (int i = 0; i < chars.length; i++) {
itemValue = chars[i]+128;
if (ints[itemValue]!=0) {
if (nowLen > max){
max = nowLen;
}
for (int i1 = start; i1 <= ints[itemValue] - 1; i1++) {
ints[chars[i1]+128] = 0;
nowLen--;
start++;
}
}
ints[itemValue] = i+1;
nowLen++;
}
return nowLen > max?nowLen:max;
}
}
四数相加Ⅱ
解法1
- 四个数组分为两组
- 将AB的和及出现的次数放入到HashMap中
- 计算CD的和*(-1)如果在HashMap中出现则计数结果自增对应的value值
- 返回计数结果
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
int count = 0;
Map<Integer, Integer> map = new HashMap<>();
int sumAB;
int sumCD;
for (int i = 0; i < nums1.length; i++) {
for (int j = 0; j < nums2.length; j++) {
sumAB = nums1[i] + nums2[j];
if (map.containsKey(sumAB)) {
map.put(sumAB, map.get(sumAB) + 1);
continue;
}
map.put(sumAB, 1);
}
}
for (int i = 0; i < nums3.length; i++) {
for (int j = 0; j < nums4.length; j++) {
sumCD = (nums3[i] + nums4[j]) * (-1);
if (map.containsKey(sumCD)) {
count += map.get(sumCD);
}
}
}
return count;
}
}
前K个高频元素
解法1
- 用一个HashMap存放每个元素及出现次数
- 用一个优先级队列来存放前k个高频元素(小顶堆)
- 遍历map,当队列满之后每次都判断从map中取出的元素出现次数和队首的元素出现此数
- 保留其中较高的那一个
- 循环结束,依次出队,即为前k个高频元素
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
PriorityQueue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>() {
public int compare(int[] m, int[] n) {
return m[1] - n[1];
}
});
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
int key = entry.getKey();
int value = entry.getValue();
if (queue.size() == k) {
if (queue.peek()[1] < value) {
queue.poll();
queue.offer(new int[]{key, value});
}
} else {
queue.offer(new int[]{key, value});
}
}
int[] result = new int[k];
for (int i = 0; i < k; i++) {
result[i] = queue.poll()[0];
}
return result;
}
}
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
PriorityQueue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>() {
public int compare(int[] m, int[] n) {
return m[1] - n[1];
}
});
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
int[] kv = new int[2];
kv[0] = entry.getKey();
kv[1] = entry.getValue();
if (queue.size() == k) {
if (queue.peek()[1] < kv[1]) {
queue.poll();
queue.offer(kv);
}
} else {
queue.offer(kv);
}
}
int[] result = new int[k];
for (int i = 0; i < k; i++) {
result[i] = queue.poll()[0];
}
return result;
}
}
常数时间插入、删除和获取随机元素
解法1
官解
class RandomizedSet {
List<Integer> nums;
Map<Integer, Integer> indices;
Random random;
public RandomizedSet() {
nums = new ArrayList<Integer>();
indices = new HashMap<Integer, Integer>();
random = new Random();
}
public boolean insert(int val) {
if (indices.containsKey(val)) {
return false;
}
int index = nums.size();
nums.add(val);
indices.put(val, index);
return true;
}
public boolean remove(int val) {
if (!indices.containsKey(val)) {
return false;
}
int index = indices.get(val);
int last = nums.get(nums.size() - 1);
nums.set(index, last);
indices.put(last, index);
nums.remove(nums.size() - 1);
indices.remove(val);
return true;
}
public int getRandom() {
int randomIndex = random.nextInt(nums.size());
return nums.get(randomIndex);
}
}
/**
* Your RandomizedSet object will be instantiated and called as such:
* RandomizedSet obj = new RandomizedSet();
* boolean param_1 = obj.insert(val);
* boolean param_2 = obj.remove(val);
* int param_3 = obj.getRandom();
*/