有八個人去看電影。但是有一部分人只喜歡特殊的座位,大部分人不喜歡自己的座位。我們這要去抽象問題,a
和b
都喜歡c
的位置,而c
喜歡a
的位置。
現在我們開始思考這個問題。a
和b
都喜歡c
的位置,那麼我們要從a
和b
中挑選出乙個
好的,我們回顧這個過程,我們會發現問題所在。因為最初b
的位置沒有人喜歡,所以一開始去除b
是最好的做法。
好的,我們沿著這個思路繼續思考,我們先將b
和g
刪除。接著我們發現g
刪除後,g
所指向的h
就沒有被指向了,接著我們很自然地去刪除h
。刪除h
後,我們發現h
指向的e
又沒人指向了,所以這個時候我們就要刪除e
。刪除e
後,我們發現e
指向的d
又沒人指向了,所以這個時候我們就要刪除d
。最後,我們得到的結果就是a, c, f
。
接著我們要做的就是將上述過程抽象成**
'''
a:最後剩餘的座位
b:所有人喜歡的座位集合
c:沒有人喜歡的座位
'''def
*****_max_perm
(m, a=none):
if a is
none: # the elt. set not supplied?
a = set(range(len(m))) # a =
if len(a) == 1:
return a # base case -- single-elt. a
b = set(m[i] for i in a) # the "pointed to" elements
c = a - b # "not pointed to" elements
if c: # any useless elements?
a.remove(c.pop()) # remove one of them
return *****_max_perm(m, a) # solve remaining problem
return a # all useful -- return all
我們還有乙個更加高效的做法,我們通過對於所有人喜歡的座位集合
進行計數,例如a:1
、b:0
、c:2
,這種做法減少了上面方案中間過程中建立b
的開銷。
from collections import counter
defmax_perm
(m):
n = len(m) # how many elements?
a = set(range(n)) # a =
count = counter(m)
q = [i for i in a if count[i] == 0] # useless elements
while q: # while useless elts. left...
i = q.pop() # get one
a.remove(i) # remove it
j = m[i] # who's it pointing to?
count[j] -= 1
# not anymore...
if count[j] == 0: # is j useless now?
return a # return useful elts.
但是這種做法是如此的醜陋,遠沒有第一種做法美妙。 尋找下乙個最大排列
對於給定的排列a1 a2 a3.an依據字典順序來生成下乙個最大的排列。首先找到整數a j 和a j 1 使得a j a j 2 a n 即在這個排列中的最後一對相鄰的整數,使得這個對的第乙個整數小於第二個整數。然後,把 a j 1 a j 2 a n 中,在按照遞增排序j 1到n的數。這樣就得到了...
leetcode 尋找排列組合
題目描述 現在給定乙個只由字元 d 和 i 組成的 秘密簽名。d 表示兩個數字間的遞減關係,i 表示兩個數字間的遞增關係。並且 秘密簽名 是由乙個特定的整數陣列生成的,該陣列唯一地包含 1 到 n 中所有不同的數字 秘密簽名的長度加 1 等於 n 例如,秘密簽名 di 可以由陣列 2,1,3 或 3...
尋找最大子樹
問題描述 給乙個二叉樹,每個節點都是正或負整數,如何找到乙個子樹,它所有節點的和最大?思路 採用自底向上的計算。先計算左右子樹總和值,用左右子樹的總和加上當前節點值,如果當前總和大於最大值,則更新最大值,同時將最大子樹根節點更新為當前根。簡單說,就是後序遍歷。include include usin...