Algorithm 如何根据祖先的共同程度对全名列表进行排序?
如果下面的每个字母都代表一个名称。根据祖先的共同程度对它们进行分类的最佳方法是什么Algorithm 如何根据祖先的共同程度对全名列表进行排序?,algorithm,Algorithm,如果下面的每个字母都代表一个名称。根据祖先的共同程度对它们进行分类的最佳方法是什么 A B C D E F G H I J K L M N C D O P C D Q R C D S T G H U V G H W J K L X J K L 结果应该是: I J K L # Three names is more important that two names W J K L X J K L A B C D # C D is repeated more than G H M N C D O
A B C D
E F G H
I J K L
M N C D
O P C D
Q R C D
S T G H
U V G H
W J K L
X J K L
结果应该是:
I J K L # Three names is more important that two names
W J K L
X J K L
A B C D # C D is repeated more than G H
M N C D
O P C D
Q R C D
E F G H
S T G H
U V G H
A B C D M
M N C D M
I J K L M
E F G H M
W J K L
X J K L
O P C D
Q R C D
S T G H
U V G H
编辑:
名称中可能包含空格()
考虑以下示例,其中每个字母代表一个单词:
A B C D M
E F G H M
I J K L M
M N C D M
O P C D
Q R C D
S T G H
U V G H
W J K L
X J K L
输出应为:
I J K L # Three names is more important that two names
W J K L
X J K L
A B C D # C D is repeated more than G H
M N C D
O P C D
Q R C D
E F G H
S T G H
U V G H
A B C D M
M N C D M
I J K L M
E F G H M
W J K L
X J K L
O P C D
Q R C D
S T G H
U V G H
首先计算每个链的出现次数。然后根据计数对每个名字进行排序。试试这个:
from collections import defaultdict
words = """A B C D
E F G H
I J K L
M N C D
O P C D
Q R C D
S T G H
U V G H
W J K L
X J K L"""
words = words.split('\n')
# Count ancestors
counters = defaultdict(lambda: defaultdict(lambda: 0))
for word in words:
parts = word.split()
while parts:
counters[len(parts)][tuple(parts)] += 1
parts.pop(0)
# Calculate tuple of ranks, used for sorting
ranks = {}
for word in words:
rank = []
parts = word.split()
while parts:
rank.append(counters[len(parts)][tuple(parts)])
parts.pop(0)
ranks[word] = tuple(rank)
# Sort by ancestor count, longest chain comes first
words.sort(key=lambda word: ranks[word], reverse=True)
print(words)
以下是如何在Java中实现这一点-基本上与@fafl的解决方案相同:
static List<Name> sortNames(String[] input)
{
List<Name> names = new ArrayList<>();
for (String name : input)
names.add(new Name(name));
Map<String, Integer> partCount = new HashMap<>();
for (Name name : names)
for (String part : name.parts)
partCount.merge(part, 1, Integer::sum);
for (Name name : names)
for (String part : name.parts)
name.counts.add(partCount.get(part));
Collections.sort(names, new Comparator<Name>()
{
public int compare(Name n1, Name n2)
{
for (int c, i = 0; i < n1.parts.size(); i++)
if ((c = Integer.compare(n2.counts.get(i), n1.counts.get(i))) != 0)
return c;
return 0;
}
});
return names;
}
static class Name
{
List<String> parts = new ArrayList<>();
List<Integer> counts = new ArrayList<>();
Name(String name)
{
List<String> s = Arrays.asList(name.split("\\s+"));
for (int i = 0; i < s.size(); i++)
parts.add(String.join(" ", s.subList(i, s.size())));
}
}
输出:
I J K L
W J K L
X J K L
A B C D
M N C D
O P C D
Q R C D
E F G H
S T G H
U V G H
如果我们希望元素在元组计数相等时按字典顺序排列,该怎么办?目前,如果您对输入中的3个“jkl”元素重新排序,使它们不再按字典顺序排列,那么它们将按相同的顺序输出。我假设它们应该按名字排序,但我承认OP没有说明这一点。我更喜欢排序函数只在必要时更改元素顺序,在相同的秩上,输入顺序应该是相同的preserved@SirRaffleBuffle单个名称中可能有空格。不强制按字母顺序排序。感谢您的澄清@fafl你是对的。我已经更新了Java解决方案,以便在出现平局时保持输入顺序。