Expected output
'abc' = ['abc', 'bac', 'bca', 'acb', 'cab', 'cba']Solution 1
Try a few input and output samples manually.
P('a') = ['a']
P('ab') = ['ab', 'ba']
P('abc') = ['cab', 'acb', 'abc', 'cba', 'bca', 'bac']Notice that to generate P('abc'), we take the output of P('ab') = ['ab', 'ba'] and try to append 'c' at each index/position 'ab' (begin, middle, end).

It seems like if we know the previous output P(n-1), we can generate the current output P(n). This sounds like a recursive solution.
def generate_permutations(text): # validation if text is None: return None # base, this is required as seeding value if len(text) == 0: return [""] # one empty element is required ensure the words loop run once # else, we can seed with the following as well ''' # if len(text) == 0: # base 0 # return [] if len(text) == 1: # base 1 return [text] ''' results = [] first = text[0] remainder = text[1:] words = generate_permutations(remainder) # print(first, remainder, words) for word in words: for i in range(len(word)+1): # insert first char at each index/position of word s = word[:i] + first + word[i:] results.append(s) return resultsSolution 2
P(a,b) = ab, ba
P(b,c) = bc, cb
P(a,c) = ac, caTo generate P(a,b,c)
{ a +P(b,c) } + { b + P(a,c) } + { c + P(a,b) }Observe that we need to try each character + P(remaining character).
def generate_permutations(text): size = len(text) results = [] # seed if size == 0: results.append("") return results # or ''' # if size == 0: # return [] if size == 1: return [text] ''' for i in range(size): # loop each character # generate str without current character (remaining character) remainder = text[0:i] + text[i+1:] # if text[i] = 'a', remainder = 'bc' partials = generate_permutations(remainder) # append current char to P(remaining character) for s in partials: results.append(text[i] + s) return resultsBig O Time:
How many time generate_permutation is called.
partials = generate_permutations(remainder)
For P('abc'), it is 3 * 2 * 1 = 3!, so it is O(n!) (since there is no caching/memoization, and n = n-1 = n)
for i in range(size)
We need to loop through each char in 'abc', so it is O(n * n!).
Based on Cracking the Coding Interview: 189 Programming Questions and Solutions by Gayle Laakmann McDowell.
Since we are calling permutation 0(n * n!) times (as an upper bound), and each one takes 0(n) time, the total runtime will not exceed O (n^2 * n!).
PS: It seems like I got O(n * n!) right, but the author also take into account string concatenation remainder = text[0:i] + text[i+1:] and print/append of result results.append(text[i] + s), which require O(n) in each node.
Solution 3
Observer the following diagram

Level 0:
- Iterate a, b, c
- Swap char[first] with char[first], char[second], char[third]: a->a, a->b, a->c
- Fist character is done/fixed
Level 1:
- Iterate: it could be abc, bac or cba
- First character is done/fixed
- Swap char[second] with char[second], char[third]
Continuedef generate_permutation(text): # convert string to list of char to allow swapping _generate_permutation(list(text), 0, len(text)-1)def _generate_permutation(text, start, end): # base if start == end: print(''.join(text)) return for i in range(start, end+1): text[start], text[i] = text[i], text[start] _generate_permutation(text, start+1, end) # backtrack like a tree, to restore previous state text[start], text[i] = text[i], text[start]Reference: https://www.geeksforgeeks.org/write-a-c-program-to-print-all-permutations-of-a-given-string/