Java 字典最小排列,使得所有相邻字母都是不同的
这是一个额外的学校任务,我们还没有得到任何教学,我也没有寻找一个完整的代码,但一些开始的提示将非常酷。回到家后,我将发布我在Java中迄今为止所做的事情,但这里有一些我已经做过的事情 因此,我们必须做一个排序算法,例如将“AAABBB”排序到ABABAB。最大输入大小为10^6,并且必须在1秒内完成。如果有多个答案,按字母顺序排列的第一个答案就是正确的答案。我开始测试不同的算法,甚至在没有字母顺序要求的情况下对它们进行排序,只是为了看看结果如何 第一版: 将ascii码保存到整数数组中,其中索引是ascii码,值是该字符在字符数组中出现的数量。 然后我选择了两个最高的数字,并开始将它们依次发送到新的字符数组,直到某个数字更高,然后我交换到它。它工作得很好,但当然顺序不对 第二版:Java 字典最小排列,使得所有相邻字母都是不同的,java,arrays,algorithm,sorting,Java,Arrays,Algorithm,Sorting,这是一个额外的学校任务,我们还没有得到任何教学,我也没有寻找一个完整的代码,但一些开始的提示将非常酷。回到家后,我将发布我在Java中迄今为止所做的事情,但这里有一些我已经做过的事情 因此,我们必须做一个排序算法,例如将“AAABBB”排序到ABABAB。最大输入大小为10^6,并且必须在1秒内完成。如果有多个答案,按字母顺序排列的第一个答案就是正确的答案。我开始测试不同的算法,甚至在没有字母顺序要求的情况下对它们进行排序,只是为了看看结果如何 第一版: 将ascii码保存到整数数组中,其中索引
遵循相同的想法,但停止选择出现次数最多的数字,而是按照索引在数组中的顺序选择索引。在输入类似于CBAYYY之前,工作正常。算法将其排序为abcyy而不是AYBYCY。当然,我可以试着为那些Y's找到一些空闲的位置,但是在那一点上,它开始花费太长的时间 一个有趣的问题,有一个有趣的调整。是的,这是一种排列或重新排列,而不是一种排序。不,引用的问题不是重复的 算法
请注意,有一种特殊情况,其中字符数为奇数,一个字符的频率从(半加1)开始。在这种情况下,您需要从算法中的步骤4开始,依次交替输出所有一个字符 还要注意的是,如果一个字符包含超过一半的输入,那么在这种特殊情况下,就不可能有解决方案。这种情况可以通过检查频率提前检测到,或者在尾部由所有一个字符组成的执行过程中检测到。检测这个病例不是规范的一部分
由于不需要排序,复杂性为O(n)。每个字符检查两次:一次是计数,一次是添加到输出中。其他所有内容都将摊销。首先计算数组中的每个字母数: 例如,你有3-A,2-B,1-C,4-Y,1-Z 1) 然后你每次把最低的一个(它是一个),你可以把 因此,你可以从以下几点开始: A 那么你不能再放A了,所以你放B: AB 然后: 阿巴巴茨 如果你仍然有至少两种角色,这些方法就有效了。但在这里你仍然有3个Y 2) 要把最后几个字符放进去,你只需从第一个Y开始,按开头的方向在2上插入一个(我不知道这是否是用英语表达的好方法) 所以,abaybycyz 3) 然后取Y so YBYAYCY之间的子序列,对Y之间的字母进行排序: BAC=>ABC 然后你到达 Abayaybycz 这应该是你问题的解决办法 要完成所有这些工作,我认为
LinkedList
是最好的方法
我希望它能有所帮助:)我的想法如下。通过正确的实现,它几乎可以是线性的 首先建立一个函数来检查解决方案是否可行。应该很快。类似于最常见字母>所有字母的1/2,如果可以是第一个,则将其考虑在内
然后,在仍有字母剩余的情况下,取与前一个字母不同的按字母顺序排列的第一个字母,使进一步的解决方案成为可能。正确的算法如下:
复杂性是O(N*log(N))制作一个字符频率的双向表:
字符->计数
和计数->字符
。记录存储最后一个字符的可选
(或没有)。存储字符总数
如果(字符总数-1)While不是完全重复的,那么给出用尽可能少的相邻相等字母枚举所有置换的算法的部分可以调整为只返回最小值,因为它的最优性证明要求每个递归调用产生至少一个置换。测试代码之外的更改范围是按排序顺序尝试键,并在t之后中断
from collections import Counter
from itertools import permutations
from operator import itemgetter
from random import randrange
def get_mode(count):
return max(count.items(), key=itemgetter(1))[0]
def enum2(prefix, x, count, total, mode):
prefix.append(x)
count_x = count[x]
if count_x == 1:
del count[x]
else:
count[x] = count_x - 1
yield from enum1(prefix, count, total - 1, mode)
count[x] = count_x
del prefix[-1]
def enum1(prefix, count, total, mode):
if total == 0:
yield tuple(prefix)
return
if count[mode] * 2 - 1 >= total and [mode] != prefix[-1:]:
yield from enum2(prefix, mode, count, total, mode)
else:
defect_okay = not prefix or count[prefix[-1]] * 2 > total
mode = get_mode(count)
for x in sorted(count.keys()):
if defect_okay or [x] != prefix[-1:]:
yield from enum2(prefix, x, count, total, mode)
break
def enum(seq):
count = Counter(seq)
if count:
yield from enum1([], count, sum(count.values()), get_mode(count))
else:
yield ()
def defects(lst):
return sum(lst[i - 1] == lst[i] for i in range(1, len(lst)))
def test(lst):
perms = set(permutations(lst))
opt = min(map(defects, perms))
slow = min(perm for perm in perms if defects(perm) == opt)
fast = list(enum(lst))
assert len(fast) == 1
fast = min(fast)
print(lst, fast, slow)
assert slow == fast
for r in range(10000):
test([randrange(3) for i in range(randrange(6))])