1、两数之和
思路:使用哈希表,将值作为key,下标作为value存入,因为是两数之和,所以另一个数一定是目标-某个数,如果另一个数在哈希表里即可返回下标。
public int[] twoSum(int[] nums, int target) {
HashMap<Integer,Integer> hashMap = new HashMap();
for(int i = 0 ; i < nums.length ; i++){
int other = target - nums[i];
if(hashMap.containsKey(other)){
return new int[]{hashMap.get(other), i};
}
//值作为哈希key 下标作为value
hashMap.put(nums[i],i);
}
return new int[0];
}
2、只出现一次的数字
思路一:使用哈希表将每个数字出现的次数作为value,数字为key存入哈希表,再次循环哈希表,判断如果频率为1则找出
public static int singleNumber(int[] nums) {
HashMap<Integer,Integer> hashMap = new HashMap<>();
for(int i = 0 ; i < nums.length ; i++){
if(hashMap.containsKey(nums[i])){
Integer count = hashMap.get(nums[i]);
hashMap.put(nums[i],++count);
}else{
hashMap.put(nums[i],1);
}
}
for (Integer key : hashMap.keySet()) {
if(hashMap.get(key)==1){
return key;
}
}
return 0;
}
思路二:抑或运算
1、因为任意数和0进行异或运算都等于其自身
2、任意数和自己做抑或都为零
3、最后剩下的那个数肯定和0进行抑或等于自身
class Solution {
public int singleNumber(int[] nums) {
int single = 0;
for(int num : nums){
single ^= num;
}
return single;
}
}
3、前K个高频元素
思路一:将数字和频率作为key和value存入哈希表,再次循环做一个下标为频率的list哈希表,list存入对应频率的数字,下标>=k的数字即是答案
public static int[] topKFrequent(int[] nums, int k) {
ArrayList<Integer> restList = new ArrayList<>();
HashMap<Integer,Integer> hashMap = new HashMap<>();
int max = 1;
for(int num : nums){
if(hashMap.containsKey(num)){
Integer count = hashMap.get(num);
max = count+1 > max ? count+1 : max; //最高频率做下面数组的size
hashMap.put(num,++count);
}else{
hashMap.put(num,1);
}
}
List<Integer>[] list = new List[max+1];
for (Integer key : hashMap.keySet()) {
int index = hashMap.get(key);
if(list[index] == null){
list[index] = new ArrayList<>();
}
list[index].add(key);
}
for(int i = list.length-1 ; i >= k; i--){
List<Integer> integers = list[i];
if(integers != null){
for(int num : integers){
restList.add(num);
}
}
}
int[] resArr = new int[restList.size()];
for(int i = 0 ; i < resArr.length ; i++){
resArr[i] = restList.get(i);
}
return resArr;
}
思路二:以数字-频率为key和value做哈希表,在利用小顶堆,根据频率大小存入数字,因为是队列二叉树,频率最小的数字会放在根节点,每次存入的时候先和根节点进行比较再决定放不放入。
因为k
的取值范围是 [1, 数组中不相同的元素的个数],所以小顶堆的最大容量就是k,根据频率放入的数量就是要求的k
public static int[] topKFrequent2(int[] nums, int k) {
HashMap<Integer,Integer> hashMap = new HashMap<>();
for(int num : nums){
if(hashMap.containsKey(num)){
Integer count = hashMap.get(num);
hashMap.put(num,++count);
}else{
hashMap.put(num,1);
}
}
//小顶堆
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
//频率小的往上放
return hashMap.get(o1) - hashMap.get(o2);
}
});
for (Integer key : hashMap.keySet()) {
if(priorityQueue.size() < k){
priorityQueue.offer(key);
//对比根节点的频率大小决定是否放入
}else if(hashMap.get(key) > hashMap.get(priorityQueue.peek())){
priorityQueue.poll();
priorityQueue.offer(key);
}
}
int [] res = new int [k];
int ind = 0;
while(!priorityQueue.isEmpty()){
res[ind++] = priorityQueue.poll();
}
return res;
}
4、无重复字符的最长字符串
思路一:用哈希表来确定是否重复字符,记录下标,字符串长度等于重复的下标-最开始的下标,最开始的下标用滑动窗口确定
public static int lengthOfLongestSubstring(String s) {
HashMap<Character,Integer> hashMap = new HashMap<>();
int max = 0;
int left = 0;
//abcaa
for(int i = 0 ; i <s.length(); i++){
if(hashMap.containsKey(s.charAt(i))){
//为什么要加max,因为abba这样 a重复的时候不能回到一开始
left = Math.max(left,hashMap.get(s.charAt(i))+1);
}
hashMap.put(s.charAt(i),i);
max = Math.max(max,i-left+1);
}
return max;
}