-
Notifications
You must be signed in to change notification settings - Fork 264
/
060 Permutation Sequence.py
164 lines (131 loc) · 4.4 KB
/
060 Permutation Sequence.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
"""
The set [1,2,3,...,n] contains a total of n! unique permutations.
By listing and labeling all of the permutations in order,
We get the following sequence (ie, for n = 3):
"123"
"132"
"213"
"231"
"312"
"321"
Given n and k, return the kth permutation sequence.
Note: Given n will be between 1 and 9 inclusive.
"""
import math
__author__ = 'Danyang'
class Solution(object):
def getPermutation(self, n, k):
k -= 1
array = range(1, n+1)
k %= math.factorial(n)
ret = []
for i in xrange(n-1, -1, -1):
idx, k = divmod(k, math.factorial(i))
ret.append(array.pop(idx))
return "".join(map(str, ret))
def getPermutation(self, n, k):
"""
Reverse Cantor Expansion
equation: sum a_i * i! = k
:param n: integer
:param k: integer
:return: String
"""
# factorial
fac = [1 for _ in xrange(n)]
for i in xrange(1, n):
fac[i] = fac[i-1]*i
# solve equation
k -= 1 # index starting from 0
a = [0 for _ in xrange(n)]
for i in xrange(n-1, -1, -1):
a[n-1-i] = k/fac[i] # a[i] = k/fac[i]
k %= fac[i]
# post-process
candidate = range(1, n+1) # sorted
visited = [False for _ in xrange(n)]
for ind, val in enumerate(a):
i = 0 # pointer
cnt = 0 # counter
while True:
if visited[i]:
i += 1
else:
if cnt == val: break
cnt += 1
i += 1
a[ind] = candidate[i]
visited[i] = True
return "".join(map(str, a))
def getPermutation_complicated(self, n, k):
"""
Mathematics
Reversed Cantor Expansion
A = [1, 2, ..., n], where A's index starts from 0
Suppose for n element, the k-th permutation is:
[a0, a1, a2, ..., an-1]
since [a1, a3, ..., an-1] has (n-1)! permutations,
if k < (n-1)!, a0 = A[0] (first element in array), else a0 = A[k/(n-1)!] (subsequent items)
recursively, (or iteratively)
a0 = A[k0/(n-1)!], where k0 = k
a1 = A[k1/(n-2)!], where k1 = k0%(n-1)! in the remaining array
a2 = A[k2/(n-3)!], where k2 = k1%(n-2)! in the remaining array
...
:param n: integer
:param k: integer
:return: String
"""
k -= 1 # index starting from 0
factorial = 1 # (n-1)!
for i in xrange(1, n):
factorial *= i
result = []
array = range(1, n+1)
for i in reversed(xrange(1, n)):
index = k/factorial
result.append(array[index])
array = array[:index]+array[index+1:]
k = k%factorial
factorial /= i
# case when factorial=0!
result.append(array[0])
return "".join(str(element) for element in result)
class Solution_TLE:
"""
Time Limit Expected
"""
def __init__(self):
self.counter = 0
def getPermutation(self, n, k):
"""
dfs, iterate all possibilities
:param n: integer
:param k: integer
:return: String
"""
if not n:
return
sequence = range(1, n+1)
result = self.get_kth_permutation_dfs(sequence, k, [])
return "".join(str(element) for element in result)
def get_kth_permutation_dfs(self, remaining_seq, k, cur):
"""
dfs until find kth permutation, return that permutation, otherwise return None
:param remaining_seq:
:param k:
:param cur:
:return:
"""
if not remaining_seq:
self.counter += 1
if self.counter == k:
return cur
for ind, val in enumerate(remaining_seq):
result = self.get_kth_permutation_dfs(remaining_seq[:ind]+remaining_seq[ind+1:], k, cur+[val])
if result: return result
if __name__ == "__main__":
assert Solution().getPermutation(4, 6) == "1432"
assert Solution().getPermutation(2, 2) == "21"
assert Solution().getPermutation(3, 1) == "123"
assert Solution().getPermutation(3, 5) == "312"
print Solution().getPermutation(9, 171669)