文章目录
- [1. 只出现一次的数字(LC136)](#1. 只出现一次的数字(LC136))
- [2. 随机链表的复制(LC138)](#2. 随机链表的复制(LC138))
- [3. 宝石与石头(LC771)](#3. 宝石与石头(LC771))
- [4. 坏键盘](#4. 坏键盘)
- [5. 前K个高频单词(LC692)](#5. 前K个高频单词(LC692))
1. 只出现一次的数字(LC136)
题目描述

解题思路
- 使用异或运算符,将数组中所有数字都异或。相同的数字异或为0,剩余的就是出现一个的数字。
- 利用Set,当set中包含这个数字就移除,不包含就添加。遍历数组后剩余的数字就是出现一次的数字。(效率低,只是练习用)
代码实现
- 解法一:
java
public int singleNumber(int[] nums) {
int ret = 0;
for(int i = 0;i<nums.length;i++){
ret = ret^nums[i];
}
return ret;
}
- 解法二:
java
public int singleNumber(int[] nums) {
Set <Integer> set = new HashSet<>();
for(int i = 0;i<nums.length;i++){
if(set.contains(nums[i]))
set.remove(nums[i]);
else
set.add(nums[i]);
}
for(int i = 0;i<nums.length;i++){
if(set.contains(nums[i]))
return nums[i];
}
return 0;
}
2. 随机链表的复制(LC138)
题目描述

解题思路
- 利用Map建立旧节点和新节点的映射关系
- 对应关系:
cur初始表示旧节点的头结点map.get(cur)表示对应的新节点;cur.next表示旧节点的下一个节点;map.get(cur.next)表示旧节点的下一个节点对应的新节点;map.get(cur).next表示旧节点对应新节点的下一个节点。
- next和random关系类似
代码实现
java
class Node {
int val;
Node next;
Node random;
public Node(int val) {
this.val = val;
this.next = null;
this.random = null;
}
}
public Node copyRandomList(Node head) {
Map<Node, Node> map = new HashMap<>();
Node cur = head;
//新建节点,建立映射关系
while (cur != null) {
Node node = new Node(cur.val);
map.put(cur, node);
cur = cur.next;
}
cur = head;
//新节点复制旧节点的next和random关系
while (cur != null) {
map.get(cur).next = map.get(cur.next);
map.get(cur).random = map.get(cur.random);
cur = cur.next;
}
return map.get(head);
}
3. 宝石与石头(LC771)
题目描述

解题思路
利用Set保存jewels中的字符;再利用计数器,遍历stones,如果set中包含该字符,则计数器自增。
代码实现
java
public int numJewelsInStones(String jewels, String stones) {
Set<Character> set = new HashSet<>();
int cnt = 0;
for(int i = 0;i<jewels.length();i++){
set.add(jewels.charAt(i));
}
for(int i = 0;i<stones.length();i++){
if(set.contains(stones.charAt(i)))
cnt++;
}
return cnt;
}
4. 坏键盘
题目描述

解题思路
- 先把两个字符串都转换为大写字母;
- 遍历输出的字符串,利用Set保存输出的所有字符;
- 遍历输入字符串,如果set不包含当前字符,则说明这个字符键盘是坏的。坏字符可能输入多次,所以使用brokenSet保存已检测的坏字符。
- 如果set和brokenSet都不包含该字符,则输出。
代码实现
java
public void func(String a,String b){
a = a.toUpperCase();
b = b.toUpperCase();
HashSet<Character> set = new HashSet<>();
for(int i = 0;i<b.length();i++){
set.add(b.charAt(i));
}
HashSet<Character> brokenSet = new HashSet<>();
for(int i =0;i<a.length();i++){
char ch = a.charAt(i);
if(!set.contains(ch) && !brokenSet.contains(ch)){
brokenSet.add(ch);
System.out.print(ch);
}
}
}
5. 前K个高频单词(LC692)
题目描述

解题思路
- 先利用
Map建立起单词和频次的映射关系 - 题目要求找频次大的单词,因此建立小根堆,重写比较器
- 每一次堆顶元素比较时,可以理解为"频次小的要出队,相同频次下序列靠后的要出队",因此频次小具有优先级,相同频次下,序列靠后具有优先级
- 遍历
map,入队- 堆元素小于K时,全部入队
- 堆元素大于等于K时:
- 频次大于堆顶元素则入队
- 频次与堆顶元素相同时,序列更小则入队
- 由于是小根堆,堆元素出队的顺序是频次由小到大,而题目要求由大到小,所以要调用
reverse方法,逆序存放。
代码实现
java
public List<String> topKFrequent(String[] words, int k) {
//1. 统计频率
Map<String,Integer> map = new HashMap<>();
for(String s:words){
if(map.containsKey(s))
map.put(s, map.get(s)+1);
else
map.put(s,1);
}
//2. 建立小根堆 (频次小的优先,相同频次下排序靠后的优先)
PriorityQueue<Map.Entry<String,Integer>> minHeap = new PriorityQueue<>(new Comparator<Map.Entry<String,Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
if(o1.getValue().equals(o2.getValue()))
return o2.getKey().compareTo(o1.getKey());
return o1.getValue()-o2.getValue();
}
});
//3. 遍历map
for(Map.Entry<String,Integer> entry :map.entrySet()){
//个数不足k时全部入队
if(minHeap.size()<k)
minHeap.offer(entry);
//元素大于等于K时,逐个与堆顶元素比较
else{
Map.Entry<String,Integer> top = minHeap.peek();
//频次大于堆顶元素则入队
if(top.getValue().compareTo(entry.getValue())<0){
minHeap.poll();
minHeap.offer(entry);
}
//频次相等时,序列靠前入队
else if(top.getValue().compareTo(entry.getValue())==0){
if(top.getKey().compareTo(entry.getKey())>0){
minHeap.poll();
minHeap.offer(entry);
}
}
}
}
//4. 把字符串放进List中
List<String> ret = new ArrayList<>();
while(!minHeap.isEmpty()){
ret.add(minHeap.poll().getKey());
}
//5. 出队的序列是频次由小到大,调用reverse方法逆序排放
Collections.reverse(ret);
return ret;
}