您需要做的就是检查最多有一个字符出现奇数次。这是一个 Java 示例:
private static boolean canMakePalindrom(String s) {
Map<Character, Integer> countChars = new HashMap<>();
// Count the occurrences of each character
for (char c : s.toCharArray()) {
Integer count = countChars.get(c);
if (count == null) {
count = Integer.valueOf(1);
} else {
count = count + 1;
}
countChars.put(c, count);
}
boolean hasOdd = false;
for (int count : countChars.values()) {
if (count % 2 == 1) {
if (hasOdd) {
// Found two chars with odd counts - return false;
return false;
} else {
// Found the first char with odd count
hasOdd = true;
}
}
}
// Haven't found more than one char with an odd count
return true;
}
EDIT4(是的 - 这些排序是有意义的,但按时间顺序编号):
上面的实现有一个内置的低效率。我不认为可以避免对字符串的第一次迭代,但是没有真正的理由来记录所有出现的次数——只跟踪那些奇数的次数就足够了。对于这个用例,跟踪我们遇到的每个字符(例如,Set)就足够了,并在我们再次遇到它时将其删除。在最坏的情况下,字符串中的所有字符都不同,性能是相当的,但在每个字符出现多次的常见情况下,这种实现提高了第二个循环的时间和内存复杂度(即现在简化为单一条件):
private static boolean canMakePalindrom(String s) {
Set<Character> oddChars = new HashSet<>();
// Go over the characters
for (char c : s.toCharArray()) {
// Record the encountered character:
if (!oddChars.add(c)) {
// If the char was already encountered, remove it -
// this is an even time we encounter it
oddChars.remove(c);
}
}
// Check the number of characters with odd counts:
return oddChars.size() <= 1;
}
EDIT3(是的 - 这些排序是有意义的,但按时间顺序编号):
Java 8 提供了一个流畅的流式 API,可用于创建类似于以下 Python 单行代码的实现:
private static boolean canMakePalindrom(String s) {
return s.chars()
.boxed()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.counting()))
.values()
.stream()
.filter(p -> p % 2 == 1)
.count() <= 1;
}
编辑:
Python 的内置函数和理解能力使得它太有吸引力了,以至于不发布这个单一的解决方案。它可能比前面提到的 Java 效率低,但非常优雅:
from collections import Counter
def canMakePalindrom(s):
return len([v for v in Counter(s).values() if v % 2 == 1]) <= 1
EDIT2:
或者,@DSM 在 cmets 中提出的更清洁的方法:
from collections import Counter
def canMakePalindrom(s):
return sum(v % 2 == 1 for v in Counter(s).values()) <= 1