函数结果因 运行 而异
Function result varies on each run
我有以下函数通过删除和重新排序字符生成最长的 palindrome 字符串:
from collections import Counter
def find_longest_palindrome(s):
count = Counter(s)
chars = list(set(s))
beg, mid, end = '', '', ''
for i in range(len(chars)):
if count[chars[i]] % 2 != 0:
mid = chars[i]
count[chars[i - 1]] -= 1
else:
for j in range(0, int(count[chars[i]] / 2)):
beg += chars[i]
end = beg
end = ''.join(list(reversed(end)))
return beg + mid + end
out = find_longest_palindrome('aacggg')
print(out)
我通过 'translating' this example 从 C++
得到了这个函数
每当我 运行 我的函数时,我似乎随机得到以下输出之一:
a
aca
agcga
本例中正确的是 'agcga'
,因为这是输入字符串 'aacggg'
.
的最长回文
任何人都可以建议为什么会发生这种情况以及如何使函数可靠地 return 最长回文?
P.S。 C++代码没有这个问题。
您的代码取决于 list(set(s))
的顺序。
但是集合是无序的。
在 CPython 3.4-3.7 中,字符串集的特定顺序取决于字符串的哈希值,这些值在启动时明确随机化,因此您每个 运行.
得到不同的结果
你在 C++ 中看不到这个的原因是 C++ set
class 模板不是无序集,而是有序集(基于二叉搜索树,而不是一个散列 table),所以你总是在每个 运行.
中得到相同的顺序
您可以在 Python 中通过在集合上调用 sorted
来获得相同的行为,而不是仅仅按照它的顺序将其复制到列表中。
但是代码还是不对;它恰好适用于某些示例,因为排序顺序恰好为您提供了重复次数最多的字符。但这显然不是一般情况,所以你需要重新考虑你的逻辑。
您的翻译中引入的最明显的区别是:
count[ch--]--;
... 或者,由于您是通过索引而不是直接遍历字符,所以更像是:
count[chars[i--]]--;
无论哪种方式,这都会减少当前字符的计数,然后减少当前字符,以便循环将在下一次通过时重新检查相同的字符。你已经把它变成了完全不同的东西:
count[chars[i - 1]] -= 1
这只是减少前一个字符的计数。
在 for-each 循环中,您不能仅更改循环变量并对循环产生任何影响。要完全复制 C++ 行为,您需要切换到 while
循环,或者在 for
循环内放置一个 while True:
循环以获得相同的 "repeat the same character" 效果.
当然,您必须减少当前字符的计数,而不是减少您永远不会再看到的前一个字符的计数。
for i in range(len(chars)):
while True:
if count[chars[i]] % 2 != 0:
mid = chars[i]
count[chars[i]] -= 1
else:
for j in range(0, int(count[chars[i]] / 2)):
beg += chars[i]
break
当然你可以简化这个——从循环 for ch in chars:
开始,但是如果你考虑两个循环如何协同工作的逻辑,你应该能够看到如何删除整个关卡这里的缩进。但这似乎是对您的代码所做的最小更改。
请注意,如果您进行此更改,而没有 sorted
更改,则当正确答案不明确时会随机选择答案——例如,您的示例将给出 agcga
一次,然后 aggga
下次
添加 sorted
将使该选择保持一致,但同样具有任意性。
我有以下函数通过删除和重新排序字符生成最长的 palindrome 字符串:
from collections import Counter
def find_longest_palindrome(s):
count = Counter(s)
chars = list(set(s))
beg, mid, end = '', '', ''
for i in range(len(chars)):
if count[chars[i]] % 2 != 0:
mid = chars[i]
count[chars[i - 1]] -= 1
else:
for j in range(0, int(count[chars[i]] / 2)):
beg += chars[i]
end = beg
end = ''.join(list(reversed(end)))
return beg + mid + end
out = find_longest_palindrome('aacggg')
print(out)
我通过 'translating' this example 从 C++
得到了这个函数每当我 运行 我的函数时,我似乎随机得到以下输出之一:
a
aca
agcga
本例中正确的是 'agcga'
,因为这是输入字符串 'aacggg'
.
任何人都可以建议为什么会发生这种情况以及如何使函数可靠地 return 最长回文?
P.S。 C++代码没有这个问题。
您的代码取决于 list(set(s))
的顺序。
但是集合是无序的。
在 CPython 3.4-3.7 中,字符串集的特定顺序取决于字符串的哈希值,这些值在启动时明确随机化,因此您每个 运行.
得到不同的结果你在 C++ 中看不到这个的原因是 C++ set
class 模板不是无序集,而是有序集(基于二叉搜索树,而不是一个散列 table),所以你总是在每个 运行.
您可以在 Python 中通过在集合上调用 sorted
来获得相同的行为,而不是仅仅按照它的顺序将其复制到列表中。
但是代码还是不对;它恰好适用于某些示例,因为排序顺序恰好为您提供了重复次数最多的字符。但这显然不是一般情况,所以你需要重新考虑你的逻辑。
您的翻译中引入的最明显的区别是:
count[ch--]--;
... 或者,由于您是通过索引而不是直接遍历字符,所以更像是:
count[chars[i--]]--;
无论哪种方式,这都会减少当前字符的计数,然后减少当前字符,以便循环将在下一次通过时重新检查相同的字符。你已经把它变成了完全不同的东西:
count[chars[i - 1]] -= 1
这只是减少前一个字符的计数。
在 for-each 循环中,您不能仅更改循环变量并对循环产生任何影响。要完全复制 C++ 行为,您需要切换到 while
循环,或者在 for
循环内放置一个 while True:
循环以获得相同的 "repeat the same character" 效果.
当然,您必须减少当前字符的计数,而不是减少您永远不会再看到的前一个字符的计数。
for i in range(len(chars)):
while True:
if count[chars[i]] % 2 != 0:
mid = chars[i]
count[chars[i]] -= 1
else:
for j in range(0, int(count[chars[i]] / 2)):
beg += chars[i]
break
当然你可以简化这个——从循环 for ch in chars:
开始,但是如果你考虑两个循环如何协同工作的逻辑,你应该能够看到如何删除整个关卡这里的缩进。但这似乎是对您的代码所做的最小更改。
请注意,如果您进行此更改,而没有 sorted
更改,则当正确答案不明确时会随机选择答案——例如,您的示例将给出 agcga
一次,然后 aggga
下次
添加 sorted
将使该选择保持一致,但同样具有任意性。