OJ题地址:
136. 只出现一次的数字
138. 复制带随机指针的链表
771. 宝石与石头
牛客:旧键盘打字
692. 前K个高频单词
目录
只出现一次的数字
题意:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
思路:
1.利用HashSet,遍历数组,如果HashSet中未包含该元素则进行添加,若包含该元素就进行移除
2.利用异或运算(^),相同为0,不同为1,这样就找出只出现一次的元素
思路2的实现:
//思路2:利用异或^,时间复杂度O(N),空间复杂度O(1)
class Solution {
public int singleNumber(int[] nums) {
int temp = 0;
for(int num : nums){
temp ^= num;
}
return temp;
}
}
思路1的实现:
//思路1:相同add,不同remove,迭代器输出
class Solution {
public int singleNumber(int[] nums) {
HashSet<Integer> set = new HashSet<>();
for(int num : nums){
if(!set.contains(num)){
set.add(num);
}
else
{
set.remove(num);
}
}
Iterator it = set.iterator();
return (int)it.next();
}
}
复制带随机指针的链表
题意:给你一个长度为
n
的链表,每个节点包含一个额外增加的随机指针random
,该指针可以指向链表中的任何节点或空节点。构造这个链表的深拷贝。
思路:利用HashMap<已有节点的地址,新生成节点的地址>,接着利用已有节点的指向来操作新节点。
class Solution {
public Node copyRandomList(Node head) {
//利用HashMap<已有节点的地址,生成的新节点的地址>
HashMap<Node,Node> hashMap = new HashMap<>();
Node cur = head;
//设置每个已有节点和新节点之间key-value关系
while(cur != null){
Node temp = new Node(cur.val);//val域
hashMap.put(cur,temp);//设置key-value
cur = cur.next; //cur继续向后走
}
cur = head;//指向首节点
while(cur != null){
//进行连接
hashMap.get(cur).next = hashMap.get(cur.next);
hashMap.get(cur).random = hashMap.get(cur.random);
cur = cur.next;
}
//返回新链表的首位置
return hashMap.get(head);
}
}
宝石与石头
题意:给你一个字符串 jewels 代表石头中宝石的类型,另有一个字符串 stones 代表你拥有的石头。 stones 中每个字符代表了一种你拥有的石头的类型,你想知道你拥有的石头中有多少是宝石。字母区分大小写,因此 "a" 和 "A" 是不同类型的石头。
简单来说:就是在一堆石头里面找宝石的个数....
思路:利用HashSet存储宝石的种类,遍历每一个石头去寻找宝石,如果找到宝石,那宝石的个数加1
class Solution {
public int numJewelsInStones(String jewels, String stones) {
Set<Character> set = new HashSet<>();
//存储宝石
for(char ch : jewels.toCharArray()){
set.add(ch);
}
int count = 0;
//在石头中找宝石
for(char ch : stones.toCharArray()){
if(set.contains(ch)){
count++;
}
}
return count;
}
}
旧键盘打字
题意:旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现。现在给出应该输入的一段文字、以及实际被输入的文字,请你列出
肯定坏掉的那些键。
思路:利用HashSet存储真实(real)文字的每一个字符,接着去遍历应该(ideal)输入的文字,如果Set中不包含该字符,则进行输出(但是该字符可能会有多个,会重复输出,因此需要去判断)
import java.util.*;
public class Main{
public static void func(String ideal , String real){
//set1存储真实的文字字符
Set<Character> set1 = new HashSet<>();
for(char ch : real.toUpperCase().toCharArray()){
set1.add(ch);
}
//set2存储坏了的键盘字符
Set<Character> set2 = new HashSet<>();
for(char ch : ideal.toUpperCase().toCharArray()){
//ideal中可能会有重复的,重复输出
if(!set1.contains(ch)&&!set2.contains(ch)){
System.out.print(ch);
set2.add(ch);
}
//为啥不直接拿set2去接收去重?
//是因为全部接收输出顺序就会发生改变
}
}
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
//应该输入的文字(ideal)
String ideal = scanner.nextLine();
//现实输入的文字
String real = scanner.nextLine();
func(ideal,real);
}
}
前k个高频单词
题意:给定一个单词列表 words 和一个整数 k ,返回前 k 个出现次数最多的单词。
返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序 排序。
思路:首先利用HashMap<String,Integer>记录每个字符串出现的次数,接着再利用优先队列建立k小堆,最终逆序输出结果。
class Solution {
public List<String> topKFrequent(String[] words, int k) {
//1.利用HashMap去统计
HashMap<String,Integer> hashMap = new HashMap<>();
for(String str : words){
if(!hashMap.containsKey(str)){
hashMap.put(str,1);
}
else{
hashMap.put(str,hashMap.get(str)+1);
}
}
//2.利用优先队列进行排序
//出现问题了:此时优先队列无法比较(这是个Entry类),利用匿名类实现compre()
PriorityQueue<Map.Entry<String,Integer>> priorityQueue =
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() - o2.getValue() == 0){
return o2.getKey().compareTo(o1.getKey());
}
//==的情况需要判断字典序
return o1.getValue() - o2.getValue();
}
});
//hashMap.entrySet()的返回类型是Set<Map.Entry<K, V>>
for(Map.Entry<String,Integer> entry : hashMap.entrySet()){
//建立小堆
if(priorityQueue.size() < k){
priorityQueue.offer(entry);
}
else{
//num存放的是堆顶
Map.Entry<String,Integer> num = priorityQueue.peek();
//比较元素大小
if(num.getValue() < entry.getValue()){
priorityQueue.poll();
priorityQueue.offer(entry);
}//比较字典序
else if(num.getValue() == entry.getValue()){
if(num.getKey().compareTo(entry.getKey()) > 0){
priorityQueue.poll();
priorityQueue.offer(entry);
}
}
}
}
// 3.放入ArrayList里面,然后逆序就结束了
ArrayList<String> arrayList = new ArrayList<>();
while(priorityQueue.size() != 0){
Map.Entry<String,Integer> entry = priorityQueue.poll();
arrayList.add(entry.getKey());//从小到大排序了
}
//arrayList里面没有逆序方法,需要用Collections(工具类)类中的reverse()方法
Collections.reverse(arrayList);
return arrayList;
}
}