Longest Increasing Cyclic Subsequence - python

I have a code for finding the longest increasing subsequence, but I'd like to extend this to allow wrap arounds. For example for the sequence (4,5,6,1,2,3) the longest increasing cyclic subsequence is (1,2,3,4,5,6) since once we reach 3, we can go back to the beginning of the sequence (we can only do this once.) Is anyone able to help me?
Here is the code:
def longest_increasing_subsequence(X):
N = len(X)
P = [0] * N
M = [0] * (N+1)
L = 0
for i in range(N):
lo = 1
hi = L
while lo <= hi:
mid = (lo+hi)//2
if (X[M[mid]] < X[i]):
lo = mid+1
else:
hi = mid-1
newL = lo
P[i] = M[newL-1]
M[newL] = i
if (newL > L):
L = newL
S = []
k = M[L]
for i in range(L-1, -1, -1):
S.append(X[k])
k = P[k]
return len(S[::-1])

Concatenate the sequence to the end of itself, then run your algorithm on it.

Just check the returned value from the function on each shift:
max_increasing=longest_increasing_subsequence(X)
for i in range(len(X)-1):
X=X.append(X.pop(0)) #shift X by 1
if longest_increasing_subsequence(X)>max_increasing:
max_increasing=longest_increasing_subsequence(X)

Related

Leetcode question '3Sum' algorithm exceeds time limit, looking for improvement

Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
class Solution:
def threeSum(self, nums):
data = []
i = j = k =0
length = len(nums)
for i in range(length):
for j in range(length):
if j == i:
continue
for k in range(length):
if k == j or k == i:
continue
sorted_num = sorted([nums[i],nums[j],nums[k]])
if nums[i]+nums[j]+nums[k] == 0 and sorted_num not in data:
data.append(sorted_num)
return data
My soulution is working well but it appears that it may be too slow.
Is there a way to improve my codes without changing it significantly?
This is a O(n^2) solution with some optimization tricks:
import itertools
class Solution:
def findsum(self, lookup: dict, target: int):
for u in lookup:
v = target - u
# reduce duplication, we may enforce v <= u
try:
m = lookup[v]
if u != v or m > 1:
yield u, v
except KeyError:
pass
def threeSum(self, nums: List[int]) -> List[List[int]]:
lookup = {}
triplets = set()
for x in nums:
for y, z in self.findsum(lookup, -x):
triplets.add(tuple(sorted([x, y, z])))
lookup[x] = lookup.get(x, 0) + 1
return [list(triplet) for triplet in triplets]
First, you need a hash lookup to reduce your O(n^3) algorithm to O(n^2). This is the whole idea, and the rest are micro-optimizations:
the lookup table is build along with the scan on the array, so it is one-pass
the lookup table index on the unique items that seen before, so it handles duplicates efficiently, and by using that, we keep the iteration count of the second-level loop to the minimal
This is an optimized version, will pass through:
from typing import List
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
unique_triplets = []
nums.sort()
for i in range(len(nums) - 2):
if i > 0 and nums[i] == nums[i - 1]:
continue
lo = i + 1
hi = len(nums) - 1
while lo < hi:
target_sum = nums[i] + nums[lo] + nums[hi]
if target_sum < 0:
lo += 1
if target_sum > 0:
hi -= 1
if target_sum == 0:
unique_triplets.append((nums[i], nums[lo], nums[hi]))
while lo < hi and nums[lo] == nums[lo + 1]:
lo += 1
while lo < hi and nums[hi] == nums[hi - 1]:
hi -= 1
lo += 1
hi -= 1
return unique_triplets
The TLE is most likely for those instances that fall into these two whiles:
while lo < hi and nums[lo] == nums[lo + 1]:
while lo < hi and nums[lo] == nums[lo + 1]:
References
For additional details, please see the Discussion Board where you can find plenty of well-explained accepted solutions with a variety of languages including low-complexity algorithms and asymptotic runtime/memory analysis1, 2.
I'd suggest:
for j in range(i+1, length):
This will save you len(nums)^2/2 steps and first if statement becomes redundant.
sorted_num = sorted([nums[i],nums[j],nums[k]])
if nums[i]+nums[j]+nums[k] == 0 and sorted_num not in data:
sorted_num = sorted([nums[i],nums[j],nums[k]])
data.append(sorted_num)
To avoid unneeded calls to sorted in the innermost loop.
Your solution is the brute force one, and the slowest one.
Better solutions can be:
Assume you start from an element from array. Consider using a Set for finding next two numbers from remaining array.
There is a 3rd better solution as well. See https://www.gyanblog.com/gyan/coding-interview/leetcode-three-sum/

Finding first pair of numbers in array that sum to value

Im trying to solve the following Codewars problem: https://www.codewars.com/kata/sum-of-pairs/train/python
Here is my current implementation in Python:
def sum_pairs(ints, s):
right = float("inf")
n = len(ints)
m = {}
dup = {}
for i, x in enumerate(ints):
if x not in m.keys():
m[x] = i # Track first index of x using hash map.
elif x in m.keys() and x not in dup.keys():
dup[x] = i
for x in m.keys():
if s - x in m.keys():
if x == s-x and x in dup.keys():
j = m[x]
k = dup[x]
else:
j = m[x]
k = m[s-x]
comp = max(j,k)
if comp < right and j!= k:
right = comp
if right > n:
return None
return [s - ints[right],ints[right]]
The code seems to produce correct results, however the input can consist of array with up to 10 000 000 elements, so the execution times out for large inputs. I need help with optimizing/modifying the code so that it can handle sufficiently large arrays.
Your code inefficient for large list test cases so it gives timeout error. Instead you can do:
def sum_pairs(lst, s):
seen = set()
for item in lst:
if s - item in seen:
return [s - item, item]
seen.add(item)
We put the values in seen until we find a value that produces the specified sum with one of the seen values.
For more information go: Referance link
Maybe this code:
def sum_pairs(lst, s):
c = 0
while c<len(lst)-1:
if c != len(lst)-1:
x= lst[c]
spam = c+1
while spam < len(lst):
nxt= lst[spam]
if nxt + x== s:
return [x, nxt]
spam += 1
else:
return None
c +=1
lst = [5, 6, 5, 8]
s = 14
print(sum_pairs(lst, s))
Output:
[6, 8]
This answer unfortunately still times out, even though it's supposed to run in O(n^3) (since it is dominated by the sort, the rest of the algorithm running in O(n)). I'm not sure how you can obtain better than this complexity, but I thought I might put this idea out there.
def sum_pairs(ints, s):
ints_with_idx = enumerate(ints)
# Sort the array of ints
ints_with_idx = sorted(ints_with_idx, key = lambda (idx, num) : num)
diff = 1000000
l = 0
r = len(ints) - 1
# Indexes of the sum operands in sorted array
lSum = 0
rSum = 0
while l < r:
# Compute the absolute difference between the current sum and the desired sum
sum = ints_with_idx[l][1] + ints_with_idx[r][1]
absDiff = abs(sum - s)
if absDiff < diff:
# Update the best difference
lSum = l
rSum = r
diff = absDiff
elif sum > s:
# Decrease the large value
r -= 1
else:
# Test to see if the indexes are better (more to the left) for the same difference
if absDiff == diff:
rightmostIdx = max(ints_with_idx[l][0], ints_with_idx[r][0])
if rightmostIdx < max(ints_with_idx[lSum][0], ints_with_idx[rSum][0]):
lSum = l
rSum = r
# Increase the small value
l += 1
# Retrieve indexes of sum operands
aSumIdx = ints_with_idx[lSum][0]
bSumIdx = ints_with_idx[rSum][0]
# Retrieve values of operands for sum in correct order
aSum = ints[min(aSumIdx, bSumIdx)]
bSum = ints[max(aSumIdx, bSumIdx)]
if aSum + bSum == s:
return [aSum, bSum]
else:
return None

Longest Increasing Subsequence Efficient Algorithm Implementation in Python

I am trying to write an efficient 0(nlogn) algorithm for longest increasing subseuqnce:
def whereToInsert(a, k):
l, r = 0, len(a)-1
while l<=r:
m = l + (r-l)//2
if a[m]==k:
return m
elif a[m]>k:
r = m - 1
else:
l = m + 1
if l==len(a)-1:
return l+1
else:
return l
#print(whereToInsert([1,2,3,4,5,6,7,8,9], 0.5)) #This works fine
def lengthOfLISEfficient(nums):
lis = [nums[0]]
for x in nums[1:]:
t = whereToInsert(lis,x)
if t>=len(lis):
lis.append(0)
lis.insert(t, x)
return len(lis)
print(lengthOfLISEfficient([10,9,2,5,3,4]))
But the answer returned is 7 whereas the logest increasing subsequence 2 3 4 is of length 3.
The algorithm is described at the end in https://leetcode.com/problems/longest-increasing-subsequence/.
I am not getting why the answer is coming 7, my algorithm is following the correct logic.
Thanks for your help.
There are a number of issues with your code. Firstly, in the method,
def lengthOfLISEfficient(nums):
when you state:
lis = [nums[0]]
you send only the first item of the list [10,9,2,5,3,4] to the method:
def whereToInsert(a, k):
whereas the latter method is meant to position a number within a list.
Here is a different approach, which involves matching each sublist of the main list with a sorted version of that sublist:
def lengthOfLISEfficient(nums):
#lis = [nums[0]]
lisList = []
for h in range(len(nums)-1):
lis = []
#numberNow = nums[h]
addableLength = len(nums) - h
#lis.append(numberNow)
for f in range(addableLength):
additem = nums[h+f]
lis.append(additem)
lisList.append(lis)
print(lisList) #just for check, feel free to delete this line
subsequenceList = []
for list in lisList:
sortedList = list.copy()
sortedList.sort()
subsequence = []
for e in range(len(list)):
if len(subsequence) > 0:
if prev <= list[e] and sortedList.index(list[e]) == index+1:
subsequence.append(list[e])
else:
continue
else:
subsequence.append(list[0])
prev = list[e]
index = sortedList.index(prev)
subsequenceList.append(subsequence)
print(subsequenceList) #just for check, feel free to delete this line
lengths = []
for l in range(len(subsequenceList)):
lengths.append(len(subsequenceList[l]))
if len(lengths) == len(subsequenceList):
longest = max(lengths)
longestSublist = subsequenceList[lengths.index(longest)]
return longest, longestSublist # Don't return longestSublist if you do not want it
print(lengthOfLISEfficient([10,9,2,5,3,4]))

Longest non-decreasing subsequence with minimal sum

I am trying to find topic algorithm and am stuck. Basically, I adopted the code given in zzz's answer here, which is Longest Increasing Subsequence algorithm, to get Longest Non-decreasing Subsequence. What I aim to find is LNDS that has a minimal sum (MSLNDS) and don't know do I have one. But as far as I can tell, original LIS algorithm as presented on wikipedia does locate minimal sum LIS. Docstring of its code says that LIS algorithm guarantees that if multiple increasing subsequences exist, the one that ends with the smallest value is preferred, and if multiple occurrences of that value can end the sequence, then the earliest occurrence is preferred. Don't know what earliest occurrence means, but would love not to be in the position to generate all LNDS to find my MSLNDS. It seems to me that clever transformation given by templatetypedef may be used to show that unique MSLIS transforms to MSLNDS, but dont have the proof. So,
a) Will LIS algorithm as given on wikipedia always output minimal sum LIS?
b) If LIS algorithm is adopted this way, will LNDS algorithm retain this property?
def NDS(X):
n = len(X)
X = [0.0] + X
M = [None]*(n+1)
P = [None]*(n+1)
L = 0
for i in range(1,n+1):
#########################################
# for LIS algorithm, this line would be
# if L == 0 or X[M[1]] >= X[i]:
#########################################
if L == 0 or X[M[1]] > X[i]:
j = 0
else:
lo = 1
hi = L+1
while lo < hi - 1:
mid = (lo + hi)//2
#########################################
# for LIS algorithm, this line would be
# if X[M[mid]] < X[i]:
#########################################
if X[M[mid]] <= X[i]:
lo = mid
else:
hi = mid
j = lo
P[i] = M[j]
if j == L or X[i] < X[M[j+1]]:
M[j+1] = i
L = max(L,j+1)
output = []
pos = M[L]
while L > 0:
output.append(X[pos])
pos = P[pos]
L -= 1
output.reverse()
return output

Finding all possible permutations of a given string in python

I have a string. I want to generate all permutations from that string, by changing the order of characters in it. For example, say:
x='stack'
what I want is a list like this,
l=['stack','satck','sackt'.......]
Currently I am iterating on the list cast of the string, picking 2 letters randomly and transposing them to form a new string, and adding it to set cast of l. Based on the length of the string, I am calculating the number of permutations possible and continuing iterations till set size reaches the limit.
There must be a better way to do this.
The itertools module has a useful method called permutations(). The documentation says:
itertools.permutations(iterable[, r])
Return successive r length permutations of elements in the iterable.
If r is not specified or is None, then r defaults to the length of the
iterable and all possible full-length permutations are generated.
Permutations are emitted in lexicographic sort order. So, if the input
iterable is sorted, the permutation tuples will be produced in sorted
order.
You'll have to join your permuted letters as strings though.
>>> from itertools import permutations
>>> perms = [''.join(p) for p in permutations('stack')]
>>> perms
['stack', 'stakc', 'stcak', 'stcka', 'stkac', 'stkca', 'satck',
'satkc', 'sactk', 'sackt', 'saktc', 'sakct', 'sctak', 'sctka',
'scatk', 'scakt', 'sckta', 'sckat', 'sktac', 'sktca', 'skatc',
'skact', 'skcta', 'skcat', 'tsack', 'tsakc', 'tscak', 'tscka',
'tskac', 'tskca', 'tasck', 'taskc', 'tacsk', 'tacks', 'taksc',
'takcs', 'tcsak', 'tcska', 'tcask', 'tcaks', 'tcksa', 'tckas',
'tksac', 'tksca', 'tkasc', 'tkacs', 'tkcsa', 'tkcas', 'astck',
'astkc', 'asctk', 'asckt', 'asktc', 'askct', 'atsck', 'atskc',
'atcsk', 'atcks', 'atksc', 'atkcs', 'acstk', 'acskt', 'actsk',
'actks', 'ackst', 'ackts', 'akstc', 'aksct', 'aktsc', 'aktcs',
'akcst', 'akcts', 'cstak', 'cstka', 'csatk', 'csakt', 'cskta',
'cskat', 'ctsak', 'ctska', 'ctask', 'ctaks', 'ctksa', 'ctkas',
'castk', 'caskt', 'catsk', 'catks', 'cakst', 'cakts', 'cksta',
'cksat', 'cktsa', 'cktas', 'ckast', 'ckats', 'kstac', 'kstca',
'ksatc', 'ksact', 'kscta', 'kscat', 'ktsac', 'ktsca', 'ktasc',
'ktacs', 'ktcsa', 'ktcas', 'kastc', 'kasct', 'katsc', 'katcs',
'kacst', 'kacts', 'kcsta', 'kcsat', 'kctsa', 'kctas', 'kcast',
'kcats']
If you find yourself troubled by duplicates, try fitting your data into a structure with no duplicates like a set:
>>> perms = [''.join(p) for p in permutations('stacks')]
>>> len(perms)
720
>>> len(set(perms))
360
Thanks to #pst for pointing out that this is not what we'd traditionally think of as a type cast, but more of a call to the set() constructor.
You can get all N! permutations without much code
def permutations(string, step = 0):
# if we've gotten to the end, print the permutation
if step == len(string):
print "".join(string)
# everything to the right of step has not been swapped yet
for i in range(step, len(string)):
# copy the string (store as array)
string_copy = [character for character in string]
# swap the current index with the step
string_copy[step], string_copy[i] = string_copy[i], string_copy[step]
# recurse on the portion of the string that has not been swapped yet (now it's index will begin with step + 1)
permutations(string_copy, step + 1)
Here is another way of doing the permutation of string with minimal code based on bactracking.
We basically create a loop and then we keep swapping two characters at a time,
Inside the loop we'll have the recursion. Notice,we only print when indexers reaches the length of our string.
Example:
ABC
i for our starting point and our recursion param
j for our loop
here is a visual help how it works from left to right top to bottom (is the order of permutation)
the code :
def permute(data, i, length):
if i==length:
print(''.join(data) )
else:
for j in range(i,length):
#swap
data[i], data[j] = data[j], data[i]
permute(data, i+1, length)
data[i], data[j] = data[j], data[i]
string = "ABC"
n = len(string)
data = list(string)
permute(data, 0, n)
Stack Overflow users have already posted some strong solutions but I wanted to show yet another solution. This one I find to be more intuitive
The idea is that for a given string: we can recurse by the algorithm (pseudo-code):
permutations = char + permutations(string - char) for char in string
I hope it helps someone!
def permutations(string):
"""
Create all permutations of a string with non-repeating characters
"""
permutation_list = []
if len(string) == 1:
return [string]
else:
for char in string:
[permutation_list.append(char + a) for a in permutations(string.replace(char, "", 1))]
return permutation_list
Here's a simple function to return unique permutations:
def permutations(string):
if len(string) == 1:
return string
recursive_perms = []
for c in string:
for perm in permutations(string.replace(c,'',1)):
recursive_perms.append(c+perm)
return set(recursive_perms)
itertools.permutations is good, but it doesn't deal nicely with sequences that contain repeated elements. That's because internally it permutes the sequence indices and is oblivious to the sequence item values.
Sure, it's possible to filter the output of itertools.permutations through a set to eliminate the duplicates, but it still wastes time generating those duplicates, and if there are several repeated elements in the base sequence there will be lots of duplicates. Also, using a collection to hold the results wastes RAM, negating the benefit of using an iterator in the first place.
Fortunately, there are more efficient approaches. The code below uses the algorithm of the 14th century Indian mathematician Narayana Pandita, which can be found in the Wikipedia article on Permutation. This ancient algorithm is still one of the fastest known ways to generate permutations in order, and it is quite robust, in that it properly handles permutations that contain repeated elements.
def lexico_permute_string(s):
''' Generate all permutations in lexicographic order of string `s`
This algorithm, due to Narayana Pandita, is from
https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
To produce the next permutation in lexicographic order of sequence `a`
1. Find the largest index j such that a[j] < a[j + 1]. If no such index exists,
the permutation is the last permutation.
2. Find the largest index k greater than j such that a[j] < a[k].
3. Swap the value of a[j] with that of a[k].
4. Reverse the sequence from a[j + 1] up to and including the final element a[n].
'''
a = sorted(s)
n = len(a) - 1
while True:
yield ''.join(a)
#1. Find the largest index j such that a[j] < a[j + 1]
for j in range(n-1, -1, -1):
if a[j] < a[j + 1]:
break
else:
return
#2. Find the largest index k greater than j such that a[j] < a[k]
v = a[j]
for k in range(n, j, -1):
if v < a[k]:
break
#3. Swap the value of a[j] with that of a[k].
a[j], a[k] = a[k], a[j]
#4. Reverse the tail of the sequence
a[j+1:] = a[j+1:][::-1]
for s in lexico_permute_string('data'):
print(s)
output
aadt
aatd
adat
adta
atad
atda
daat
data
dtaa
taad
tada
tdaa
Of course, if you want to collect the yielded strings into a list you can do
list(lexico_permute_string('data'))
or in recent Python versions:
[*lexico_permute_string('data')]
Here is another approach different from what #Adriano and #illerucis posted. This has a better runtime, you can check that yourself by measuring the time:
def removeCharFromStr(str, index):
endIndex = index if index == len(str) else index + 1
return str[:index] + str[endIndex:]
# 'ab' -> a + 'b', b + 'a'
# 'abc' -> a + bc, b + ac, c + ab
# a + cb, b + ca, c + ba
def perm(str):
if len(str) <= 1:
return {str}
permSet = set()
for i, c in enumerate(str):
newStr = removeCharFromStr(str, i)
retSet = perm(newStr)
for elem in retSet:
permSet.add(c + elem)
return permSet
For an arbitrary string "dadffddxcf" it took 1.1336 sec for the permutation library, 9.125 sec for this implementation and 16.357 secs for #Adriano's and #illerucis' version. Of course you can still optimize it.
Here's a slightly improved version of illerucis's code for returning a list of all permutations of a string s with distinct characters (not necessarily in lexicographic sort order), without using itertools:
def get_perms(s, i=0):
"""
Returns a list of all (len(s) - i)! permutations t of s where t[:i] = s[:i].
"""
# To avoid memory allocations for intermediate strings, use a list of chars.
if isinstance(s, str):
s = list(s)
# Base Case: 0! = 1! = 1.
# Store the only permutation as an immutable string, not a mutable list.
if i >= len(s) - 1:
return ["".join(s)]
# Inductive Step: (len(s) - i)! = (len(s) - i) * (len(s) - i - 1)!
# Swap in each suffix character to be at the beginning of the suffix.
perms = get_perms(s, i + 1)
for j in range(i + 1, len(s)):
s[i], s[j] = s[j], s[i]
perms.extend(get_perms(s, i + 1))
s[i], s[j] = s[j], s[i]
return perms
See itertools.combinations or itertools.permutations.
why do you not simple do:
from itertools import permutations
perms = [''.join(p) for p in permutations(['s','t','a','c','k'])]
print perms
print len(perms)
print len(set(perms))
you get no duplicate as you can see :
['stack', 'stakc', 'stcak', 'stcka', 'stkac', 'stkca', 'satck', 'satkc',
'sactk', 'sackt', 'saktc', 'sakct', 'sctak', 'sctka', 'scatk', 'scakt', 'sckta',
'sckat', 'sktac', 'sktca', 'skatc', 'skact', 'skcta', 'skcat', 'tsack',
'tsakc', 'tscak', 'tscka', 'tskac', 'tskca', 'tasck', 'taskc', 'tacsk', 'tacks',
'taksc', 'takcs', 'tcsak', 'tcska', 'tcask', 'tcaks', 'tcksa', 'tckas', 'tksac',
'tksca', 'tkasc', 'tkacs', 'tkcsa', 'tkcas', 'astck', 'astkc', 'asctk', 'asckt',
'asktc', 'askct', 'atsck', 'atskc', 'atcsk', 'atcks', 'atksc', 'atkcs', 'acstk',
'acskt', 'actsk', 'actks', 'ackst', 'ackts', 'akstc', 'aksct', 'aktsc', 'aktcs',
'akcst', 'akcts', 'cstak', 'cstka', 'csatk', 'csakt', 'cskta', 'cskat', 'ctsak',
'ctska', 'ctask', 'ctaks', 'ctksa', 'ctkas', 'castk', 'caskt', 'catsk', 'catks',
'cakst', 'cakts', 'cksta', 'cksat', 'cktsa', 'cktas', 'ckast', 'ckats', 'kstac',
'kstca', 'ksatc', 'ksact', 'kscta', 'kscat', 'ktsac', 'ktsca', 'ktasc', 'ktacs',
'ktcsa', 'ktcas', 'kastc', 'kasct', 'katsc', 'katcs', 'kacst', 'kacts', 'kcsta',
'kcsat', 'kctsa', 'kctas', 'kcast', 'kcats']
120
120
[Finished in 0.3s]
def permute(seq):
if not seq:
yield seq
else:
for i in range(len(seq)):
rest = seq[:i]+seq[i+1:]
for x in permute(rest):
yield seq[i:i+1]+x
print(list(permute('stack')))
All Possible Word with stack
from itertools import permutations
for i in permutations('stack'):
print(''.join(i))
permutations(iterable, r=None)
Return successive r length permutations of elements in the iterable.
If r is not specified or is None, then r defaults to the length of the iterable and all possible full-length permutations are generated.
Permutations are emitted in lexicographic sort order. So, if the input iterable is sorted, the permutation tuples will be produced in sorted order.
Elements are treated as unique based on their position, not on their value. So if the input elements are unique, there will be no repeat values in each permutation.
This is a recursive solution with n! which accepts duplicate elements in the string
import math
def getFactors(root,num):
sol = []
# return condition
if len(num) == 1:
return [root+num]
# looping in next iteration
for i in range(len(num)):
# Creating a substring with all remaining char but the taken in this iteration
if i > 0:
rem = num[:i]+num[i+1:]
else:
rem = num[i+1:]
# Concatenating existing solutions with the solution of this iteration
sol = sol + getFactors(root + num[i], rem)
return sol
I validated the solution taking into account two elements, the number of combinations is n! and the result can not contain duplicates. So:
inpt = "1234"
results = getFactors("",inpt)
if len(results) == math.factorial(len(inpt)) | len(results) != len(set(results)):
print("Wrong approach")
else:
print("Correct Approach")
With recursive approach.
def permute(word):
if len(word) == 1:
return [word]
permutations = permute(word[1:])
character = word[0]
result = []
for p in permutations:
for i in range(len(p)+1):
result.append(p[:i] + character + p[i:])
return result
running code.
>>> permute('abc')
['abc', 'bac', 'bca', 'acb', 'cab', 'cba']
Yet another initiative and recursive solution. The idea is to select a letter as a pivot and then create a word.
def find_premutations(alphabet):
words = []
word =''
def premute(new_word, alphabet):
if not alphabet:
words.append(word)
else:
for i in range(len(alphabet)):
premute(new_word=word + alphabet[i], alphabet=alphabet[0:i] + alphabet[i+1:])
premute(word, alphabet)
return words
# let us try it with 'abc'
a = 'abc'
find_premutations(a)
Output:
abc
acb
bac
bca
cab
cba
Here's a really simple generator version:
def find_all_permutations(s, curr=[]):
if len(s) == 0:
yield curr
else:
for i, c in enumerate(s):
for combo in find_all_permutations(s[:i]+s[i+1:], curr + [c]):
yield "".join(combo)
I think it's not so bad!
def f(s):
if len(s) == 2:
X = [s, (s[1] + s[0])]
return X
else:
list1 = []
for i in range(0, len(s)):
Y = f(s[0:i] + s[i+1: len(s)])
for j in Y:
list1.append(s[i] + j)
return list1
s = raw_input()
z = f(s)
print z
Here's a simple and straightforward recursive implementation;
def stringPermutations(s):
if len(s) < 2:
yield s
return
for pos in range(0, len(s)):
char = s[pos]
permForRemaining = list(stringPermutations(s[0:pos] + s[pos+1:]))
for perm in permForRemaining:
yield char + perm
from itertools import permutations
perms = [''.join(p) for p in permutations('ABC')]
perms = [''.join(p) for p in permutations('stack')]
def perm(string):
res=[]
for j in range(0,len(string)):
if(len(string)>1):
for i in perm(string[1:]):
res.append(string[0]+i)
else:
return [string];
string=string[1:]+string[0];
return res;
l=set(perm("abcde"))
This is one way to generate permutations with recursion, you can understand the code easily by taking strings 'a','ab' & 'abc' as input.
You get all N! permutations with this, without duplicates.
Everyone loves the smell of their own code. Just sharing the one I find the simplest:
def get_permutations(word):
if len(word) == 1:
yield word
for i, letter in enumerate(word):
for perm in get_permutations(word[:i] + word[i+1:]):
yield letter + perm
This program does not eliminate the duplicates, but I think it is one of the most efficient approaches:
s=raw_input("Enter a string: ")
print "Permutations :\n",s
size=len(s)
lis=list(range(0,size))
while(True):
k=-1
while(k>-size and lis[k-1]>lis[k]):
k-=1
if k>-size:
p=sorted(lis[k-1:])
e=p[p.index(lis[k-1])+1]
lis.insert(k-1,'A')
lis.remove(e)
lis[lis.index('A')]=e
lis[k:]=sorted(lis[k:])
list2=[]
for k in lis:
list2.append(s[k])
print "".join(list2)
else:
break
With Recursion
# swap ith and jth character of string
def swap(s, i, j):
q = list(s)
q[i], q[j] = q[j], q[i]
return ''.join(q)
# recursive function
def _permute(p, s, permutes):
if p >= len(s) - 1:
permutes.append(s)
return
for i in range(p, len(s)):
_permute(p + 1, swap(s, p, i), permutes)
# helper function
def permute(s):
permutes = []
_permute(0, s, permutes)
return permutes
# TEST IT
s = "1234"
all_permute = permute(s)
print(all_permute)
With Iterative approach (Using Stack)
# swap ith and jth character of string
def swap(s, i, j):
q = list(s)
q[i], q[j] = q[j], q[i]
return ''.join(q)
# iterative function
def permute_using_stack(s):
stk = [(0, s)]
permutes = []
while len(stk) > 0:
p, s = stk.pop(0)
if p >= len(s) - 1:
permutes.append(s)
continue
for i in range(p, len(s)):
stk.append((p + 1, swap(s, p, i)))
return permutes
# TEST IT
s = "1234"
all_permute = permute_using_stack(s)
print(all_permute)
With Lexicographically sorted
# swap ith and jth character of string
def swap(s, i, j):
q = list(s)
q[i], q[j] = q[j], q[i]
return ''.join(q)
# finds next lexicographic string if exist otherwise returns -1
def next_lexicographical(s):
for i in range(len(s) - 2, -1, -1):
if s[i] < s[i + 1]:
m = s[i + 1]
swap_pos = i + 1
for j in range(i + 1, len(s)):
if m > s[j] > s[i]:
m = s[j]
swap_pos = j
if swap_pos != -1:
s = swap(s, i, swap_pos)
s = s[:i + 1] + ''.join(sorted(s[i + 1:]))
return s
return -1
# helper function
def permute_lexicographically(s):
s = ''.join(sorted(s))
permutes = []
while True:
permutes.append(s)
s = next_lexicographical(s)
if s == -1:
break
return permutes
# TEST IT
s = "1234"
all_permute = permute_lexicographically(s)
print(all_permute)
This code makes sense to me. The logic is to loop through all characters, extract the ith character, perform the permutation on the other elements and append the ith character at the beginning.
If i'm asked to get all permutations manually for string ABC. I would start by checking all combinations of element A:
A AB
A BC
Then all combinations of element B:
B AC
B CA
Then all combinations of element C:
C AB
C BA
def permute(s: str):
n = len(s)
if n == 1: return [s]
if n == 2:
return [s[0]+s[1], s[1]+s[0]]
permutations = []
for i in range(0, n):
current = s[i]
others = s[:i] + s[i+1:]
otherPermutations = permute(others)
for op in otherPermutations:
permutations.append(current + op)
return permutations
Simpler solution using permutations.
from itertools import permutations
def stringPermutate(s1):
length=len(s1)
if length < 2:
return s1
perm = [''.join(p) for p in permutations(s1)]
return set(perm)
def permute_all_chars(list, begin, end):
if (begin == end):
print(list)
return
for current_position in range(begin, end + 1):
list[begin], list[current_position] = list[current_position], list[begin]
permute_all_chars(list, begin + 1, end)
list[begin], list[current_position] = list[current_position], list[begin]
given_str = 'ABC'
list = []
for char in given_str:
list.append(char)
permute_all_chars(list, 0, len(list) -1)
The itertools module in the standard library has a function for this which is simply called permutations.
import itertools
def minion_game(s):
vow ="aeiou"
lsword=[]
ta=[]
for a in range(1,len(s)+1):
t=list(itertools.permutations(s,a))
lsword.append(t)
for i in range(0,len(lsword)):
for xa in lsword[i]:
if vow.startswith(xa):
ta.append("".join(xa))
print(ta)
minion_game("banana")

Categories