我正在解决下面的问题并发布了我的代码。我的问题是,我目前的实现是在Python中使用排序 - sorted(sorted_freq, reverse=True)
。我提到了一些使用最大堆(http://www.geeksforgeeks.org/rearrange-a-string-so-that-all-same-characters-become-at-least-d-distance-away/)的其他实现。我认为它们具有相同的时间复杂度O(n*log n)
(如果我计算错误,请随意纠正)。所以我想知道除了排序之外使用堆的性能是否有任何好处?
我的代码是用Python 2.7编写的。
问题:
给定一个字符串和一个正整数 d 。某些字符可能在给定的字符串中重复。重新排列给定字符串的字符,使相同的字符彼此远离 d 。请注意,可能有许多可能的重新排列,输出应该是可能的重新排列之一。如果没有这样的安排,也应该报告。 预期的时间复杂度为 O(n),其中 n 是输入字符串的长度。
示例:
Input: "abb", d = 2
Output: "bab"
Input: "aacbbc", d = 3
Output: "abcabc"
Input: "geeksforgeeks", d = 3
Output: egkegkesfesor
Input: "aaa", d = 2
Output: Cannot be rearranged
源代码:
from collections import defaultdict
def rearrange(source, distance):
freq = defaultdict(int)
for c in source:
freq[c] += 1
sorted_freq = []
for k,v in freq.items():
sorted_freq.append((v,k))
sorted_freq = sorted(sorted_freq, reverse=True)
result = [0] * len(source)
for i, (v,k) in enumerate(sorted_freq):
index = i
while index < len(result) and result[index] != 0:
index += 1
if index == len(result):
return None
count = v
while count > 0:
result[index] = k
index += distance
count -= 1
if index >= len(source) and count > 0:
return None
return result
if __name__ == "__main__":
print rearrange('abb', 2)
print rearrange('aacbbc', 3)
print rearrange('geeksforgeeks', 3)
print rearrange('aaa', 2)
答案 0 :(得分:3)
链接上显示的最佳算法的时间复杂度为 O(n + m log m),其中 m 是输入字符串中唯一字符的数量。如上所述,因为 m 总是少于字母表中的字母总数(这是一个固定的常数),如果 m 小于 n < / em>时间复杂度可以被认为是 O(n)。当 O(m log m)排序算法用于对频率而不是堆进行排序时,时间复杂度没有区别。
请注意,由于您在每个循环中使用index
初始化i
,因此您的实现具有时间复杂度 O(nm)。以下是使用Counter
代替defaultdict
的替代实现,其中修复了问题并简要比较了退化情况下的性能:
from collections import Counter
def rearrange2(s, dist):
start = 0
result = [None] * len(s)
for char, count in Counter(s).most_common():
while result[start]:
start += 1
end = start + dist * (count - 1) + 1
if end > len(s):
return None
for i in xrange(start, end, dist):
result[i] = char
return ''.join(result)
def rearrange3(s, dist):
start = 0
result = [None] * len(s)
for char, count in sorted(Counter(s).items(), key=lambda x: x[1], reverse=True):
while result[start]:
start += 1
end = start + dist * (count - 1) + 1
if end > len(s):
return None
for i in xrange(start, end, dist):
result[i] = char
return ''.join(result)
if __name__ == '__main__':
import timeit
print timeit.timeit("rearrange(src,2)", setup="from __main__ import rearrange; src='a'*10000 + 'b'*10000 + 'cdefghijk'", number=100)
print timeit.timeit("rearrange2(src,2)", setup="from __main__ import rearrange2; src='a'*10000 + 'b'*10000 + 'cdefghijk'", number=100)
print timeit.timeit("rearrange3(src,2)", setup="from __main__ import rearrange3; src='a'*10000 + 'b'*10000 + 'cdefghijk'", number=100)
输出:
3.23630073078
0.756645293244
0.753287190129
更新: most_common
使用heapq.nlargest
under the hood等于heapsort,以防n
为给定可迭代的长度。从上面的结果可以看出,没有真正的区别。结果当然取决于数据的大小和唯一字符的数量。