![](/img/trans.png)
[英]Method that returns all permutation given some maximum and minimum criteria
[英]Lexicographic minimum permutation such that all adjacent letters are distinct
這是一項額外的學校任務,我們還沒有得到任何教學,我也沒有在尋找完整的代碼,但是開始工作的一些技巧非常酷。 當我回到家時,將發布到目前為止我在Java中所做的事情,但這是我已經完成的事情。
因此,我們必須執行排序算法,例如將“ AAABBB”排序為ABABAB。 最大輸入大小為10 ^ 6,並且所有操作必須在1秒內完成。 如果答案不只一個,那么按字母順序排列的第一個答案就是正確的答案。 我開始測試不同的算法,甚至在不考慮字母順序要求的情況下對它們進行排序,只是為了看看結果如何。
第一版:
將ascii代碼保存到Integer數組中,其中index是ascii代碼,並且值是該字符在char數組中出現的數量。 然后,我選擇了2個最高的數字,並開始將它們互相發送垃圾郵件到新的字符數組中,直到某個數字更高為止,然后我將其交換了出去。 效果很好,但是當然順序不對。
第二版:
遵循相同的想法,但是停止選擇出現次數最多的數字,而只是按照它們在數組中的順序選擇了索引。 在輸入類似CBAYYY之類的內容之前,效果很好。 算法將其排序為ABCYYY而不是AYBYCY。 當然,我可以嘗試為這些Y查找一些空閑位置,但是到那時,它開始花費的時間太長了。
一個有趣的問題,還有一個有趣的調整。 是的,這是排列或重新排列,而不是排序。 不,引用的問題不是重復的問題。
算法。
需要采取一些措施來避免出現一對一的錯誤(輸入字符的奇數與偶數)。 否則,僅編寫代碼並使之正常工作是挑戰。
請注意,在一種特殊情況下,字符數為奇數,一個字符的頻率開始於(一半加1)。 在這種情況下,您需要從算法中的步驟4開始,依次輸出所有一個字符和每個其他字符。
還要注意,如果一個字符包含一半以上的輸入,然后分開輸入(對於這種特殊情況),則無法解決。 這種情況可以通過檢查頻率提前檢測出來,或者在執行過程中尾巴全部由一個字符組成時檢測出來。 檢測這種情況不屬於規范的一部分。
由於不需要排序,因此復雜度為O(n)。 每個字符都要檢查兩次:一次計數時,一次添加到輸出中時。 其他一切均攤銷。
首先計算數組中的每個字母數:
例如,您有3-A,2-B,1-C,4-Y,1-Z。
1)然后,您每次都放最低的(A)即可。
所以你開始:
一種
那你就不能再放A了,所以放了B:
AB
然后:
阿巴西
如果您仍然至少有2種字符,這些方法將起作用。 但是這里您仍然有3年。
2)要放置最后一個字符,您只需從第一個Y開始,然后在開始的方向上插入一個2(我不知道這些是否是用英語說的好方法)。
所以ABAYBYAYCYZ。
3)然后,取Y之間的子序列,即YBYAYCY,然后對Y之間的字母進行排序:
BAC => ABC
然后你到達
ABAYAYBYCYZ
這應該是您的問題的解決方案。
做所有這些事情,我認為LinkedList
是最好的方法
希望對您有所幫助:)
我的想法如下。 通過正確的實施,它幾乎可以是線性的。
首先建立一個功能來檢查解決方案是否可行。 應該很快。 像最常見的字母>所有字母的1/2之類的東西,如果可以放在首位,則要考慮。
然后,在仍然有剩余字母的情況下,請按字母順序排列第一個字母,該字母與之前的字母不同,從而可以進一步解決。
正確的算法如下:
PQ不為空時循環
如果輸出的大小==輸入的大小,則有可能,並且您有答案。 否則這是不可能的。
復雜度為O(N * log(N))
制作一個雙向的字符頻率表: character->count
和count->character
。 記錄一個optional<Character>
,該字符存儲最后一個字符(或者沒有字符)。 存儲字符總數。
如果(總字符數-1)<2 *(最高計數字符數),請使用最高計數字符數字符。 (否則將沒有解決方案)。 如果這是最后一個字符輸出,則失敗。
否則,請使用最早的字母,而不是最后一個字符輸出。
記錄最后的字符輸出,減少總字符數和已用字符數。
當我們還有字符時循環播放。
雖然這個問題不是一個重復的問題,但是我給出的算法的一部分可以用盡可能少的相鄰相等字母枚舉所有排列的算法,可以很容易地使其僅返回最小值,因為其最優性證明要求每個遞歸調用的產生至少一個排列。 測試代碼之外的更改范圍是按排序順序嘗試鍵,並在找到第一個匹配項后中斷。 下面的代碼的運行時間是多項式(如果我為更好的數據結構而煩惱,則為O(n)),因為它與其祖先不同,它並未列舉所有可能性。
david.pfx的答案暗示了這一邏輯:貪婪地取走並不能消除所有可能性的最小字母,但是,正如他指出的那樣,細節是微妙的。
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))])
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.