ArticleVoteService
unknown
java
23 days ago
3.5 kB
4
Indexable
import java.util.*;
public class ArticleVoteService {
private int nextArticleId = 1;
private Map<Integer, String> articles = new HashMap<>();
// userId -> (articleId -> vote: 1=UP, -1=DOWN)
private Map<Integer, Map<Integer, Integer>> userVotes = new HashMap<>();
// userId -> recently flipped articleIds (insertion order, max 3)
private Map<Integer, LinkedHashSet<Integer>> userFlips = new HashMap<>();
// articleId -> score
private Map<Integer, Integer> articleScores = new HashMap<>();
// score -> set of articleIds
private TreeMap<Integer, Set<Integer>> scoreIndex = new TreeMap<>();
public int addArticle(String title) {
int id = nextArticleId++;
articles.put(id, title);
return id;
}
public void upvoteArticle(int articleId, int userId) {
vote(articleId, userId, 1);
}
public void downvoteArticle(int articleId, int userId) {
vote(articleId, userId, -1);
}
private void vote(int articleId, int userId, int newVote) {
userVotes.putIfAbsent(userId, new HashMap<>());
Map<Integer, Integer> voteMap = userVotes.get(userId);
Integer oldVote = voteMap.get(articleId);
// calculate score delta
int delta = 0;
if (oldVote == null) {
delta = newVote;
} else if (oldVote != newVote) {
delta = newVote - oldVote; // flip: +2 or -2;
} else {
return; // same vote, do nothing
}
// update flip tracking
if (oldVote != null && oldVote != newVote) {
userFlips.putIfAbsent(userId, new LinkedHashSet<>());
LinkedHashSet<Integer> flips = userFlips.get(userId);
flips.remove(articleId);
flips.add(articleId);
if (flips.size() > 3) {
Iterator<Integer> it = flips.iterator();
it.next();
it.remove();
}
}
// calculate new score
int oldScore = articleScores.getOrDefault(articleId, 0);
int newScore = oldScore + delta;
// remove from old score
if (scoreIndex.containsKey(oldScore)) {
scoreIndex.get(oldScore).remove(articleId);
if (scoreIndex.get(oldScore).isEmpty()) {
scoreIndex.remove(oldScore);
}
}
// add to new score
scoreIndex.putIfAbsent(newScore, new HashSet<>());
scoreIndex.get(newScore).add(articleId);
articleScores.put(articleId, newScore);
voteMap.put(articleId, newVote);
}
public List<String> printLastThreeFlips(int userId) {
List<String> result = new ArrayList<>();
LinkedHashSet<Integer> flips = userFlips.get(userId);
if (flips == null) return result;
List<Integer> flipList = new ArrayList<>(flips);
for (int i = flipList.size() - 1; i >= 0; i--) {
result.add(articles.get(flipList.get(i)));
}
return result;
}
// Time Complexity normal case O(K), worst case O(N)
public List<String> getTopK(int k) {
List<String> result = new ArrayList<>();
// TreeMap is asending, so iterate from tail
for (int score : scoreIndex.descendingKeySet()) {
for (int articleId : scoreIndex.get(score)) {
result.add(articles.get(articleId));
if (result.size() == k) {
return result;
}
}
}
return result;
}
}Editor is loading...
Leave a Comment