场景是我有以下地图:
[
a:[4,2,6,9,-1],
b:[2,6],
c:[1],
d:[9,9,9,4]
]
以及以下值列表:
[2,4,1]
我希望按排序列表中第一次出现的值对地图键进行排序:
result: [a,b,d,c] (because both a&b have a 2, d has a 4, and c has a 1)
目前我有以下内容但是在O(n ^ 3)。有没有更有效的方法来做这种事?
private static List<String> orderByList(Map<String, List<Integer>> numByString, List<String> sortingList) {
Map<String, List<String>> stringsByTags = new HashMap<String, List<String>>();
for (String string : numByString.keySet()) {
for (Integer num : numByString.get(string)) {
boolean foundTag = false;
// go through all elements until you find one that is is the sortingList
// add it to the stringsByTags
for (String tag : sortingList) {
if (string.equals(tag)) {
if (stringsByTags.containsKey(tag)) {
stringsByTags.get(tag).add(string);
} else {
List<String> newList = new ArrayList<String>();
newList.add(string);
stringsByTags.put(tag, newList);
}
foundTag = true;
break;
}
}
if (foundTag) {
break;
}
}
}
//combine the stringsByTags
List<String> ordered = new ArrayList<String>();
for (String tag : sortingList) {
if (stringsByTags.containsKey(tag)) {
ordered.addAll(stringsByTags.get(tag));
}
}
return ordered;
}
答案 0 :(得分:0)
第1步。计算地图中每个条目的分数
values = [2,4,1];
Integer score = 0;
for(int i=0;i < a.size();i++) {
if(values.binarySearch(a[i])) {
score ++;
}
}
运行时间为* O(a.size() log(values.size))。计算整个地图得分的总成本是O(map.size * entry.size * log(values.size))。简单来说,它将是 O(knlog(m))。
第2步。对ScoreObj
数组进行排序。费用为 O(klog(k)),其中k表示地图的大小。
class ScoreObj {
Integer score;
String key;
}
覆盖ScoreObj
的比较功能,以便ScoreObj
按score
排序。
它比 O(n ^ 3)稍好。
答案 1 :(得分:0)
如果我正确理解您的问题,您的算法会按照排序列表中找到的第一个值的索引对映射条目进行排序。我们将此索引称为sortingIndex
。
执行此操作的一种方法是首先创建Map<String, Integer>
,其中键保持不变,值为sortingIndex
:
Map<String, Integer> sortingMap = new HashMap<>();
numByString.forEach((k, v) -> {
Set<Integer> values = new HashSet<>(v);
int sortingIndex = IntStream.range(0, sortingList.size())
.filter(i -> values.contains(sortingList.get(i)))
.findFirst()
.orElse(Integer.MAX_VALUE);
sortingMap.put(k, sortingIndex);
});
现在,只需按值排序sortingMap
并获取密钥:
List<String> orderedKeys = sortingMap.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.collect(Collectors.toList());
答案 2 :(得分:0)
我有两种方法,它们都应该比你的小O小。我的第一种方法应该比第二种方法的O小,因为它在处理后也会删除地图条目。我的测试数据看起来像这样。我之所以选择LinkedHashMap
是因为它保持了顺序,这在这种情况下非常重要:
Map<String, List<String>> p = new HashMap<String, List<String>>();
p.put("a", Arrays.asList("4", "2", "6", "9", "-1"));
p.put("b", Arrays.asList("2", "6"));
p.put("c", Arrays.asList("1"));
p.put("d", Arrays.asList("9", "9", "9", "4"));
p.put("e", Arrays.asList("8", "7", "6"));
List<String> values = new ArrayList<String>(Arrays.asList("2", "4", "1"));
Map<String, List<String>> result = new LinkedHashMap<String, List<String>>();
List<String> sorted = new ArrayList<String>();
现在我的第一种方法是在排序后删除条目:
for (String s : values) {
for (Iterator<Entry<String, List<String>>> it = p.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, List<String>> x = it.next();
if (x.getValue().contains(s)) {
if (!result.containsKey(x.getKey())) {
result.put(x.getKey(), x.getValue());
sorted.add(x.getKey());
it.remove();
}
}
}
}
第二种方法看起来更容易理解,但同样有效:
for (String s : values) {
for (String st : p.keySet()) {
if (p.get(st).contains(s)) {
if (!result.containsKey(st)) {
result.put(st, p.get(st));
sorted.add(st);
}
}
}
}
如果我打印列表和地图,我的输出就是这两种情况:
[a, b, d, c]
[a, b, d, c]