leetcode 335.设计推特
分析一下这道题,设计这种问题,首先要具备有面向对象的思想,首先我们把"推特"看作是一个类,那么其中就会包含有人,文章等属性(我们的设计模式是只有人),而人的属性又有ID,关注列表,发布的文章等等(人作为内部类存在),而每次的推送我们只需要在当前所需人的关注列表中查询关注的人的发布的文章即可,利用堆(优先级队列)来存储十个元素(推送),我们的文章也是一个对象(内部类),文章实现了Compareable接口(也可以用比较器),为了在入队列的时候有比较条件,至于发布文章的时间如何计算,我们采用了一个时间戳,就是每次发布文章的时候让我们的时间戳向后面走一步即可
代码实现如下
/**
* 设计推特类
*/
class Twitter {
//文章的属性不应该只有文章的id,还有文章的发送时间点
static class Article implements Comparable<Article>{
public int articlaID;
public int time;
public Article(int articlaID, int time) {
this.articlaID = articlaID;
this.time = time;
}
@Override//这种默认创建的就是一个小根堆,而且是一个按照时间的大小顺序排出来的小根堆(想要获得time最大的前10个,那就要用小根堆)
public int compareTo(Article o) {
return this.time - o.time;
}
}
//推特里面也是由人组成的
public static class Person{
public int personID;
public List<Integer> watchlist;
public List<Article> article;
//人的构造方法
public Person(int personID) {
this.personID = personID;
this.watchlist = new ArrayList<Integer>();
this.article = new ArrayList<Article>();
}
}
//微博的属性就是人
public List<Person> people;
//这个起到一个计时器的作用
public int countTime = 0;
public Twitter() {
people = new LinkedList<>();
}
public void postTweet(int userId, int tweetId) {
int index = findPerson(userId);
if(index != -1){
people.get(index).article.add(new Article(tweetId,countTime));
countTime++;
}else{
Person person = new Person(userId);
person.article.add(new Article(tweetId,countTime));
person.watchlist.add(userId);
countTime++;
people.add(person);
}
}
private int findPerson(int userID){
int size = people.size();
for(int i = 0; i < size; ++i){
if(people.get(i).personID == userID){
return i;
}
}
return -1;
}
public List<Integer> getNewsFeed(int userId) {
int index = findPerson(userId);
if(index == -1){
return new ArrayList<>();
}else{
Person person = people.get(index);
int size = person.watchlist.size();
PriorityQueue<Article> priorityQueue = new PriorityQueue<Article>();
for(int i = 0; i < size; ++i){
int watchPersonID = person.watchlist.get(i);
int watchPersonIndex = findPerson(watchPersonID);
Person watchPerson = people.get(watchPersonIndex);
for(int j = 0; j < watchPerson.article.size(); ++j){
if(priorityQueue.size() < 10){
priorityQueue.offer(watchPerson.article.get(j));
}else{
if(priorityQueue.peek().time < watchPerson.article.get(j).time){
priorityQueue.poll();
priorityQueue.offer(watchPerson.article.get(j));
}
}
}
}
LinkedList<Integer> ans = new LinkedList<>();
while(!priorityQueue.isEmpty()){
Article article = priorityQueue.poll();
ans.addFirst(article.articlaID);
}
return ans;
}
}
public void follow(int followerId, int followeeId) {
int indexer = findPerson(followerId);
Person follower = null;
if(indexer == -1){
follower = new Person(followerId);
follower.watchlist.add(followerId);
people.add(follower);
}else{
follower = people.get(indexer);
}
int indexee = findPerson(followeeId);
Person followee = null;
if(indexee == -1){
followee = new Person(followeeId);
followee.watchlist.add(followeeId);
people.add(followee);
}else{
followee = people.get(indexee);
}
for(int i = 0; i < follower.watchlist.size(); ++i){
int ID = follower.watchlist.get(i);
if(ID == followeeId){
return;
}
}
follower.watchlist.add(followee.personID);
}
public void unfollow(int followerId, int followeeId) {
int indexer = findPerson(followerId);
Person personer = people.get(indexer);
personer.watchlist.remove(Integer.valueOf(followeeId));
}
}
leetcode 347.前K个高频元素
典型的topK问题,topK问题经常用于这种返回k个极值的问题,比如上面的推送问题,这里的topK我们计数的时候设计了一个类专门用来储存我们的数据,因为(Hash表我们还没学)我们在hash计数的时候,在遇到负数的情况的时候,我们就采用了两个hash来映射计数,一个映射正数,一个映射负数,代码实现如下
class Solution {
static class Hash implements Comparable<Hash> {
int key;
int val;
public Hash(int key, int val) {
this.key = key;
this.val = val;
}
public int compareTo(Hash o) {
return o.val - this.val;
}
}
public int[] topKFrequent(int[] nums, int k) {
if(nums == null || k <= 0){
return new int[0];
}
//创建hash表(遇到负数怎么办呢,我们尝试使用两个hash来计数,一个是正数hash,一个是负数hash)
int[] hashz = new int[100001];
int[] hashf = new int[100001];
for(int i = 0; i < nums.length; ++i){
if(nums[i] >= 0){
hashz[nums[i]]++;
}else{
int temp = -nums[i];
hashf[temp]++;
}
}
//hash表创建完成 --> 遍历hash表入优先级队列
PriorityQueue<Hash> priorityQueue = new PriorityQueue<>();
for(int i = 0; i < hashz.length; ++i){
if(hashz[i] != 0){
Hash ele = new Hash(i,hashz[i]);
priorityQueue.offer(ele);
}
if(hashf[i] != 0){
Hash ele = new Hash(-i,hashf[i]);
priorityQueue.offer(ele);
}
}
//按照K的标准进行储值
int[] ans = new int[k];
for(int i = 0; i < k; ++i){
Hash ele = priorityQueue.poll();
ans[i] = ele.key;
}
return ans;
}
}
leetcode 692.前K个高频单词
同样的,我们依然选择自己写一个类来模拟hash表的作用,代码实现如下
class Solution {
List<String> ans = new LinkedList<>();
static class Hash implements Comparable<Hash>{
String s;
int key;
int val;
public Hash(String s,int key,int val){
this.s = s;
this.key = key;
this.val = val;
}
@Override
public int compareTo(Hash o) {
if(this.val != o.val){
return o.val - this.val;
}
return this.s.compareTo(o.s);
}
}
public List<String> topKFrequent(String[] words, int k) {
if(words == null || words.length == 0 || k <= 0){
return ans;
}
//遍历数组用来记录字符串的种类
List<String> strings = new LinkedList<>();
for(int i = 0; i < words.length; ++i){
if(strings.indexOf(words[i]) == -1){
strings.add(words[i]);
}
}
//创建一个hash数组用来计数
int sz = strings.size();
int[] hash = new int[sz];
for (int i = 0; i < words.length; i++) {
int index = strings.indexOf(words[i]);
hash[index]++;
}
//遍历list创建Hash类的列表
List<Hash> hashes = new LinkedList<>();
for(int i = 0; i < sz; ++i){
Hash elem = new Hash(strings.get(i),i,hash[i]);
hashes.add(elem);
}
//创建好了一个包含字符串,下标,还有计数的一个集合类
PriorityQueue<Hash> priorityQueue = new PriorityQueue<>(hashes);
for(int i = 0; i < k; ++i){
ans.add(priorityQueue.poll().s);
}
return ans;
}
}