在稳定排序相等的情况下使用优先队列保留插入顺序的最佳实践
Best practice in preserving insertion order with priority queue in case of equality for stable sorting
更新
给定一组客户对不同酒店的评论和一个包含“Good Words”的字符串,您需要根据“Goodness Value”(较高的goodness value 在前)对评论进行降序排序。我们将一个字符串的“Goodness Value”定义为该字符串中“Good Words”的数量。
注意:排序应该是稳定的。如果评论 i 和评论 j 具有相同的“Goodness Value”,那么它们的原始顺序将被保留。
问题
使用 priority queue
排列上述顺序并不稳定,因为轮询堆数组不会以相同的顺序返回相同的值。
同时,我查看了这个博客:https://lemire.me/blog/2017/03/13/stable-priority-queues/。
有没有更好的方法来稳定优先级队列排序?或者其他更好的DS
?我能想到的一种方法是将它放在 arrays
和 sorting
中。 Treemap
没有太大用处,因为 key
涉及重复条目或类似的多个单词。
问题:
https://www.interviewbit.com/problems/hotel-reviews/
这个有效
输入:
S = "cool_ice_wifi"
R = ["water_is_cool"、"cold_ice_drink"、"cool_wifi_speed"]
输出:
ans = [2, 0, 1]
这里,排序的评论是["cool_wifi_speed"、"water_is_cool"、"cold_ice_drink"]
这个测试用例不工作。
一个:"a_b_c "
B : [ "a_b", "b_c", "a_c" ]
public class Solution {
private static final int ALPHA_SIZE = 26;
public static class Reviews implements Comparable<Reviews> {
private int pos;
private int score;
@Override
public boolean equals(Object o) {
if(this == o) return true;
if(o == null || this.getClass()!=o.getClass()) return false;
Reviews r = (Reviews)o;
if(r.score!=this.score) return false;
return true;
}
@Override
public int compareTo(Reviews r) {
return this.score - r.score;
}
}
public static class TrieNode {
TrieNode[] letter;
boolean isTail;
public TrieNode() {
isTail = false;
letter = new TrieNode[ALPHA_SIZE];
for(int i = 0; i < ALPHA_SIZE; i++) {
letter[i] = null;
}
}
}
static TrieNode root;
public static void add(String word) {
TrieNode curr = root;
for(char ch : word.toCharArray()) {
if(curr.letter[ch-'a']==null) curr.letter[ch-'a'] = new TrieNode();
curr = curr.letter[ch-'a'];
}
curr.isTail = true;
}
public void addAll(String[] words) {
for(String word : words) {
this.add(word);
}
}
public static boolean contains(String word) {
TrieNode curr = root;
for(char ch : word.toCharArray()) {
if(curr.letter[ch-'a']!=null) {
curr = curr.letter[ch-'a'];
} else {
return false;
}
}
return curr.isTail;
}
public ArrayList<Integer> solve(String A, ArrayList<String> B) {
root = new TrieNode();
String[] words = A.split("_");
addAll(words);
ArrayList<Integer> res = new ArrayList<>();
Reviews cur;
Queue<Reviews> q = new PriorityQueue<>(Collections.reverseOrder());
for(int i = 0; i < B.size(); i++) {
cur = new Reviews();
cur.score = countGW(B.get(i));
cur.pos = i;
q.add(cur);
}
while(!q.isEmpty()) {
cur = q.poll();
res.add(cur.pos);
}
return res;
}
public int countGW(String x) {
String[] xs = x.split("_");
int res = 0;
for(String y : xs) {
if(contains(y)) {
res++;
}
}
return res;
}
}
Why PriorityQueue
is not working as a stable sorting this case?
因为PriorityQueue
没有提供稳定的排序。请参阅 Javadoc。
编辑 现在你已经完全改变了你的问题:
Best practice ...
只有一种做法。将插入顺序字段添加到您的对象并将其用作次键。
正如其他人所指出的,您不能依赖 PriorityQueue
进行稳定排序。原因是PriorityQueue
是用二叉堆实现的,而二叉堆并没有产生稳定的排序。
但是您可以在您的情况下使用PriorityQueue
。您想要按 score
排序,并按 pos
值的顺序返回相同的分数。所以如果你有:
pos score
1 1
2 3
3 2
4 1
那么你想要的结果是:
pos score
2 3
3 2
1 1
4 1
你所要做的就是修改你的 compareTo
方法,这样如果 score
相等,它就比较 pos
,像这样:
@Override
public int compareTo(Reviews r) {
int result = this.score.compareTo(r.score);
if (result != 0) return result;
result = this.pos.compareTo(r.pos);
}
一般来说,用this.score - r.score
做比较是个坏主意。它适用于正数,但如果混合使用正数和负数,整数溢出会产生错误。有关详细信息,请参阅我的博客 post、Subtraction is not the same as comparison。
更新
给定一组客户对不同酒店的评论和一个包含“Good Words”的字符串,您需要根据“Goodness Value”(较高的goodness value 在前)对评论进行降序排序。我们将一个字符串的“Goodness Value”定义为该字符串中“Good Words”的数量。
注意:排序应该是稳定的。如果评论 i 和评论 j 具有相同的“Goodness Value”,那么它们的原始顺序将被保留。
问题
使用 priority queue
排列上述顺序并不稳定,因为轮询堆数组不会以相同的顺序返回相同的值。
同时,我查看了这个博客:https://lemire.me/blog/2017/03/13/stable-priority-queues/。
有没有更好的方法来稳定优先级队列排序?或者其他更好的DS
?我能想到的一种方法是将它放在 arrays
和 sorting
中。 Treemap
没有太大用处,因为 key
涉及重复条目或类似的多个单词。
问题: https://www.interviewbit.com/problems/hotel-reviews/
这个有效
输入: S = "cool_ice_wifi" R = ["water_is_cool"、"cold_ice_drink"、"cool_wifi_speed"]
输出: ans = [2, 0, 1]
这里,排序的评论是["cool_wifi_speed"、"water_is_cool"、"cold_ice_drink"]
这个测试用例不工作。
一个:"a_b_c "
B : [ "a_b", "b_c", "a_c" ]
public class Solution {
private static final int ALPHA_SIZE = 26;
public static class Reviews implements Comparable<Reviews> {
private int pos;
private int score;
@Override
public boolean equals(Object o) {
if(this == o) return true;
if(o == null || this.getClass()!=o.getClass()) return false;
Reviews r = (Reviews)o;
if(r.score!=this.score) return false;
return true;
}
@Override
public int compareTo(Reviews r) {
return this.score - r.score;
}
}
public static class TrieNode {
TrieNode[] letter;
boolean isTail;
public TrieNode() {
isTail = false;
letter = new TrieNode[ALPHA_SIZE];
for(int i = 0; i < ALPHA_SIZE; i++) {
letter[i] = null;
}
}
}
static TrieNode root;
public static void add(String word) {
TrieNode curr = root;
for(char ch : word.toCharArray()) {
if(curr.letter[ch-'a']==null) curr.letter[ch-'a'] = new TrieNode();
curr = curr.letter[ch-'a'];
}
curr.isTail = true;
}
public void addAll(String[] words) {
for(String word : words) {
this.add(word);
}
}
public static boolean contains(String word) {
TrieNode curr = root;
for(char ch : word.toCharArray()) {
if(curr.letter[ch-'a']!=null) {
curr = curr.letter[ch-'a'];
} else {
return false;
}
}
return curr.isTail;
}
public ArrayList<Integer> solve(String A, ArrayList<String> B) {
root = new TrieNode();
String[] words = A.split("_");
addAll(words);
ArrayList<Integer> res = new ArrayList<>();
Reviews cur;
Queue<Reviews> q = new PriorityQueue<>(Collections.reverseOrder());
for(int i = 0; i < B.size(); i++) {
cur = new Reviews();
cur.score = countGW(B.get(i));
cur.pos = i;
q.add(cur);
}
while(!q.isEmpty()) {
cur = q.poll();
res.add(cur.pos);
}
return res;
}
public int countGW(String x) {
String[] xs = x.split("_");
int res = 0;
for(String y : xs) {
if(contains(y)) {
res++;
}
}
return res;
}
}
Why
PriorityQueue
is not working as a stable sorting this case?
因为PriorityQueue
没有提供稳定的排序。请参阅 Javadoc。
编辑 现在你已经完全改变了你的问题:
Best practice ...
只有一种做法。将插入顺序字段添加到您的对象并将其用作次键。
正如其他人所指出的,您不能依赖 PriorityQueue
进行稳定排序。原因是PriorityQueue
是用二叉堆实现的,而二叉堆并没有产生稳定的排序。
但是您可以在您的情况下使用PriorityQueue
。您想要按 score
排序,并按 pos
值的顺序返回相同的分数。所以如果你有:
pos score
1 1
2 3
3 2
4 1
那么你想要的结果是:
pos score
2 3
3 2
1 1
4 1
你所要做的就是修改你的 compareTo
方法,这样如果 score
相等,它就比较 pos
,像这样:
@Override
public int compareTo(Reviews r) {
int result = this.score.compareTo(r.score);
if (result != 0) return result;
result = this.pos.compareTo(r.pos);
}
一般来说,用this.score - r.score
做比较是个坏主意。它适用于正数,但如果混合使用正数和负数,整数溢出会产生错误。有关详细信息,请参阅我的博客 post、Subtraction is not the same as comparison。