Example: I have the array[9,0,1,2,3,6,4,5,0,9,7,8,9] and It should return the max consecutive subsequence, so the answer should be (and if the number is 9 and the next one is 0 than it's fine) 9,0,1,2,3, but my code is returning 0,1,2,3
Starting from each element, do a loop that compares adjacent elements, until you get a pair that isn't consecutive.
Instead of saving all the consecutive sublists in another list, just save the sublist in a variable. When you get another sublist, check if it's longer and replace it.
def constructPrintLIS(arr: list, n: int):
longest_seq = []
for i in range(n-1):
for j in range(i, n-1):
if not (arr[j] == arr[j+1]-1 or (arr[j] == 9 and arr[j+1] == 0)):
break
else:
# if we reach the end, need to update j
j = n
if j - i > len(longest_seq):
longest_seq = arr[i:j+1]
if n - i <= len(longest_seq):
# there can't be any longer sequences, so stop
break
printLIS(longest_seq)
Related
Following is the code:
for (i = n-1; i>0; i--)
for (j=0; j<i; j++)
if (arr[i] < arr[i+1])
{
temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}
I could find for the outer for outer for loop will execute n times and the inner for loop will be executed i+i-1+i-2+....+1 i(i+1)/2=(i^2+i)/2 and the if condition will be checked for (i-1)*i/2=(i^2-i)/2 times but I am confused for the statements in if condition and also correct me if I am wrong for the my above calculations too.
for n = 5, the values of i and j encountered when the if statement is executed can be listed as follows:
(4,0) (4,1) (4,2) (4,3)
(3,0) (3,1) (3,2)
(2,0) (2,1)
(1,0)
I arranged the items like that on purpose because they form a triangle.
####
###
##
#
To count how many items are in this triangle we can mirror the triangle and count each item twice. There are two ways to do it neatly depending on whether you place the mirrored items to the right or below.
####o
###oo
##ooo
#oooo
####
###o
##oo
#ooo
oooo
Either way, by inspecting width times height, this can easily be seen to be a rectangle of either n * (n-1) or (n-1) * n items (equal area in both cases). And since we counted each element twice, we can divide by two, and use (n-1) * n / 2 as the formula for the number of items.
Therefore your if condition will be computed exactly (n-1) * n / 2 times.
You also correctly expanded this expression to be ((n*n) - (n)) / 2 which is also equal to (n^2 - n) / 2.
But a few things were bad...
You said (i-1)*i/2, using i instead of n. That's not right.
Your code appears to intend to compute a Bubble sort. And the index for the if condition and its block should be j (not i) throughout. (You were comparing arr[i] to arr[i+1] for the same value of i repeatedly in the inner loop. The actual swap would be evaluated at most once for a given value of i, in that case, or not at all, depending on the values of arr.)
The code you intended was likely:
for (i = n-1; i>0; i--)
for (j=0; j<i; j++)
if (arr[j] < arr[j+1])
{
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
Question:
Given a string S S.length() <= 5.10^5 and an integer K K <= S.length(). For each removal, you can:
Remove the first character of the string
Remove the second character of the string
Remove the last character of the string
Remove the second last character of the string
How can I do exactly K removals such that the final string has minimum lexicographical order?
Example:
S= "abacaaba", K = 2
Remove the second character of the string
Remove the second last character of the string
The final string: "aacaaa" which is the smallest lexicographical possible.
P/S:
I've tried for many days but can't figure out an efficience way to solve this problem. But I think there's something to do with dynamic programming.
All together, these ideas should lead to a linear-time algorithm.
If K ≤ N−4, the final string has at least four characters. Its two-character prefix is the least two-character subsequence of the (K+2)-character prefix of the initial string. Compute this prefix and the possible positions of its second character. This can be accomplished in O(K) time by scanning through first K+2 characters, maintaining the least character so far and the least two-character subsequence so far.
Now that we know the two-character prefix, we just have to determine the best suffix. For a prefix that required J deletions to set up, the final string continues with the next N−4 − K characters that we can't touch, followed by the least two-character subsequence of the (K+2 − J)-character suffix of the initial string. We can compute the least two-character subsequence of each of the relevant suffixes using the scanning algorithm described previously. The one tricky part is comparing the untouchable middles efficiently. This can be accomplished with some difficulty using a suffix array with longest common prefixes.
If K > N−4, just return the least (N−K)-character subsequence.
Interesting task!
Update: step 5 incorrect. Here is correct one:
All combinations with length M, which consist of 3'th and 4'th remove operations are equal to this class of operations:
Zero or more 3 after that zero or more 4, like this regexp: (3)(4)
You can prove it:
43 pair is equal to 33
343 pair equal to 443.
Moreover 34...43 is equal to 44...43.
So you can pick rightmost 3 and with rule 3 make it the only one 3. And with rule 4 make transform all left 4 to 3.
any ->rule3-> 4...434...4 -> rule1-> 3...34...4
It leads to O(K^3) complexity of step 6 brute force.
Original answer
There are some ideas and solution that works nice in common
[More short word is smaller in lexicographical order] Wrong, as #n. 1.8e9-where's-my-share m. mentinoed. All possible results will be equal length (Length-K), because we should use all of them.
Lexicographical order means: for semi-length words we match symbols from left to right until it equal. Result of word comparison is result of first different char comparison result. So minimization of i'th symbol is more important than minimization (i+j)'th symbol for all positive j.
So most important is first symbol minimization. Only first removal operation can influence on it. By first removal operation we try to place at first place minimal possible value (It will be minimal value from first K symbols). If there is some positions with minimal letter - we will pick leftmost one (we don't want to delete extra symbols and lost correct answer).
Now most important is second letter. So we want to minimize it too. We will make it like in 3'th step of algorithm. But, we use 2'nd remove operation and if we had some variants as minimal - we save all of them as candidates.
All combinations with length M, which consist of 3'th and 4'th remove operations are equal to only 2 combinations:
all operations are 4'th: 44...44
all operations are 4'th but the last one is 3: 44...43.
So for every candidate we can check only two possibilities.
Brute force all candidates with both possibilities. Find minimal.
In common case this algorithm work's well. But in worst case it's weak. There is counterpoint: Maxlength string with same letter. Then we have K candidates and algorithm complexity will be O(K^2) - it's not good for this task.
For deal with it i think we can choose right candidate at 6'th step of algorithm:
6*. For two candidates - compare their suffix - letters after it. Candidate with smaller letter at same tail position (tail position counts from this candidate head position) is better for our purposes.
7*. Compare two possibilities form 5'th algorithm step and choose minimal.
Problem of this (*) approach - i cannot get a rigid proof that it's better solution. Most hard part, when one candidate is a prefix of another - we compare it letter by letter until smallest doesn't end. for example in string abcabcabc...abc with candidate at first and fourth position.
Here is a (hopefully) mostly complete solution in Python (sorry, I'm even less versed in C++). The idea is I believe the same or very similar to David Eisenstat's, who's answer helped me think more about handling the middles. The comparisons for the middle section use O(1) lookups with O(n log n) preprocessing based on the suffix array construction referenced and linked in the code (David's suggestion is to use O(n) preprocessing and O(1) lookups but I haven't had time to get into O(1) RMQs or Ukkonen's; I'm also charmed by the referenced CP suffix array algorithm). The code includes testing comparing with brute-force but is incomplete in that it does not handle the case where there are only the prefix and suffix and no middle, which should be much simpler to handle anyway. There are probably ways to make the code more succinct and organised but I haven't had time yet to consider it more carefully.
Since we can remove the first, second, penultimate or last characters; the first two letters of the solution will be chosen from two letters (a subsequence) remaining after k or less deletions:
xxxAxxxxxxxB...
Once we've committed to character A by deleting some first characters, we are left only with a choice for B, based on how many deletions we make of the second character. Clearly, we'd like the lowest available character for A, which we may have more than one instance of, and the lowest choice for B after that, for which we also may have more than once instance of.
The suffix is composed similarly, but we need to store the best suffix for each k - num_deletions already chosen for the prefix. Then the final candidate is the lowest two-character-prefix + middle + two-character-suffix, where the middle is fixed by the distribution of deletions in each candidate. We can compare middles using a suffix array or tree with additional information.
Python
def log2(n):
i = -1
while(n):
i += 1
n >>= 1
return i
# https://cp-algorithms.com/string/suffix-array.html
def sort_cyclic_shifts(s):
n = len(s)
alphabet = 256
cs = []
p = [0] * n
c = [0] * n
cnt = [0] * max(alphabet, n + 1)
for i in range(n):
cnt[ord(s[i])] += 1
for i in range(1, alphabet):
cnt[i] += cnt[i-1]
for i in range(n):
cnt[ord(s[i])] -= 1
p[cnt[ord(s[i])]] = i
c[p[0]] = 0
classes = 1
for i in range(1, n):
if s[p[i]] != s[p[i-1]]:
classes += 1
c[p[i]] = classes - 1
cs.append(c[:])
pn = [0] * n
cn = [0] * n
h = 0
while (1 << h) < n:
for i in range(n):
pn[i] = p[i] - (1 << h)
if pn[i] < 0:
pn[i] += n
for i in range(0, classes):
cnt[i] = 0
for i in range(n):
cnt[c[pn[i]]] += 1
for i in range(1, classes):
cnt[i] += cnt[i-1]
for i in range(n-1, -1, -1):
cnt[c[pn[i]]] -= 1
p[cnt[c[pn[i]]]] = pn[i]
cn[p[0]] = 0
classes = 1
for i in range(i, n):
cur = c[p[i]], c[(p[i] + (1 << h)) % n]
prev = c[p[i-1]], c[(p[i-1] + (1 << h)) % n]
if cur != prev:
classes += 1
cn[p[i]] = classes - 1
c = cn
cs.append(c[:])
h += 1
return p, cs
# https://cp-algorithms.com/string/suffix-array.html
def suffix_array_construction(s):
s += "$"
sorted_shifts, cs = sort_cyclic_shifts(s)
return sorted_shifts[1:], cs
# https://cp-algorithms.com/string/suffix-array.html
def compare(i, j, l, k, n, c):
a = c[k][i], c[k][(i+l-(1 << k))%n]
b = c[k][j], c[k][(j+l-(1 << k))%n]
if a == b:
return 0
elif a < b:
return -1
return 1
## MAIN FUNCTION
def f(s, k):
debug = 0
n = len(s)
# Best prefix
best_first = s[k]
best_second = s[k+1]
first_idxs = [k]
second_idxs = [k + 1]
for i in range(k - 1, -1, -1):
if s[i] <= best_first:
best_first = s[i]
# We only need one leftmost index
first_idxs = [i]
for i in range(k, first_idxs[0], -1):
if (s[i] < best_second):
best_second = s[i]
second_idxs = [i]
elif s[i] == best_second:
second_idxs.append(i)
second_idxs = list(reversed(second_idxs))
# Best suffix
# For each of l deletions,
# we can place the last
# character anywhere ahead
# of the penultimate.
last_idxs = {(n - 2): [n - 1]}
best_last = s[n - 1]
for l in range(2, k + 2):
idx = n - l
if s[idx] < best_last:
best_last = s[idx]
last_idxs[n - 1 - l] = [idx]
else:
last_idxs[n - 1 - l] = last_idxs[n - l]
p, cs = suffix_array_construction(s)
second_idx = 0
if debug:
print(first_idxs, second_idxs, last_idxs)
while first_idxs[0] >= second_idxs[second_idx]:
second_idx += 1
prefix_end = second_idxs[second_idx]
num_deleted = prefix_end - 1
remaining = k - num_deleted
suffix_start = n - remaining - 2
best = (prefix_end + 1, suffix_start - 1)
while second_idx < len(second_idxs):
prefix_end = second_idxs[second_idx]
num_deleted = prefix_end - 1
remaining = k - num_deleted
suffix_start = n - remaining - 2
len_candidate_middle = suffix_start - 1 - prefix_end
# The prefixes are all equal.
# We need to compare the middle
# and suffix.
# compare(i, j, l, k, n, c)
len_best_middle = best[1] - best[0] + 1
l = min(len_candidate_middle, len_best_middle)
# Compare middles
comp = compare(best[0], prefix_end + 1, l, log2(l), n + 1, cs)
# Candidate is better
if comp == 1:
best = (prefix_end + 1, suffix_start - 1)
elif comp == 0:
# Compare suffix of candidate with
# substring at the comparable position
# of best.
[last_idx] = last_idxs[suffix_start]
candidate_suffix = s[suffix_start] + s[last_idx]
if len_candidate_middle < len_best_middle:
# One character of best's suffix
if len_candidate_middle + 1 == len_best_middle:
to_compare = s[best[1]] + s[best[1] + 1]
# None of best's suffix
else:
idx = best[0] + len_candidate_middle
to_compare = s[idx] + s[idx + 1]
# If the candidate suffix is equal
# to best's equivalent, the candidate
# wins since it's shorter.
if candidate_suffix <= to_compare:
best = (prefix_end + 1, suffix_start - 1)
elif len_candidate_middle == len_best_middle:
idx = best[1] + 1
to_compare = s[idx] + s[last_idxs[idx][0]]
if candidate_suffix < to_compare:
best = (prefix_end + 1, suffix_start - 1)
# len_best_middle < len_candidate_middle
else:
# One character of candidate's suffix
if len_best_middle + 1 == len_candidate_middle:
to_compare = s[suffix_start - 1] + s[suffix_start]
# None of candidates's suffix
else:
idx = prefix_end + 1 + len_best_middle
to_compare = s[idx] + s[idx + 1]
if candidate_suffix < to_compare:
best = (prefix_end + 1, suffix_start - 1)
second_idx += 1
prefix = s[first_idxs[0]] + s[second_idxs[second_idx-1]]
middle = s[best[0]:best[1] + 1]
suffix = s[best[1] + 1] + s[last_idxs[best[1] + 1][0]]
return prefix + middle + suffix
def brute_force(s, k):
best = s + "z"
stack = [(s, k)]
while stack:
_s, _k = stack.pop()
if _k == 0:
best = min(best, _s)
continue
stack.append((_s[1:], _k - 1))
stack.append((_s[0] + _s[2:], _k - 1))
stack.append((_s[0:len(_s)-1], _k - 1))
stack.append((_s[0:len(_s)-2] + _s[-1], _k - 1))
return best
# 01234567
#s = "abacaaba"
#k = 2
# Test
import random
n = 12
num_tests = 500
for _ in range(num_tests):
s = "".join([chr(97 + random.randint(0, 25)) for i in range(n)])
k = random.randint(1, n - 5)
#print(s, k)
_f = f(s, k)
brute = brute_force(s, k)
if brute != _f:
print("MISMATCH!")
print(s, k)
print(_f)
print(brute)
break
print("Done.")
A non-solution failing for abcbaa, K = 2
(Kudos to גלעד ברקן for sharing a test.)
find the minimum in the first K+1 elements at lowest 0-based index l1
drop a prefix of length l1 (remove 1st l1 times) - done if l1 = K
find the minimum in the elements from 1 to 1 + K - l1, inclusive at l2
"delete" elements from 1 to l2 (if any)(remove 2nd l2 times)
starting with l3 = 0 and while K - l1 - l2 - l3 > 0,
remove the larger of the last two elements and increase l3
I will post this answer even though there is an accepted answer because I feel like all the other answers are more complex than they need to be. Below is a O(NK) algorithm that solves this, which can "easily" be made into an O(N) algorithm if a suffix tree is used to do the comparisons of the "middle" portions.
#!/usr/bin/python
def lex_kr(x,K,k_r):
"""
Get a lexicographically comparable subset of `x` for a given value of
`k_r`.
"""
N = len(x)
assert k_r > 0 and k_r < K # check for corner cases
k_l = K - k_r
v_l = min(x[:k_l+1])
v_r = min(x[-k_r-1:])
lex = [v_l]
lex += x[k_l+1:N-k_r-1]
lex += [v_r]
return lex
def lex_corner(x,K):
"""
Get the two lexicographically comparable subsets of `x` for corner cases
when `k_r=0` and `k_r=K`.
"""
N = len(x)
k_l = K
v_l = min(x[:k_l+1])
lex0 = [v_l]
lex0 += x[k_l+1:]
k_r = K
v_r = min(x[-k_r-1:])
lex1 = x[:N-k_r-1]
lex1 += [v_r]
return lex0,lex1
def min_lex(x,K):
subsets = [ lex_kr(x,K,k_r) for k_r in range(1,K) ]
subsets += lex_corner(x,K) # append the two corner cases
return min(subsets)
if __name__ == '__main__':
S = [ x for x in 'abacaaba' ]
K = 2
print(min_lex(S,K))
which prints ['a', 'a', 'c', 'a', 'a', 'a'].
The comparisons of the min of the left and right (prefix & suffix) of the arrays can obviously be pre-computed in O(N) time in the function lex_kr.
The middle portion (i.e. x[k_l+1:N-k_r-1]) needs a clever trick to compare lexographically against all other middle portions efficiently. This can be done in O(1) per comparison using a suffix-tree/array as described in other answers (https://cp-algorithms.com/string/suffix-array.html) or a suffix automaton (https://cp-algorithms.com/string/suffix-automaton.html) with the latter being more complex but more efficient. Once implemented, this would yield an O(N) algorithm with less special cases to be checked than other answers.
Most common way of bubble sort algorithm is to have two for loops. Inner one being done from j=0 until j n-i-1. I assume we substract minus i, because when we reach last element we don't compare it because we don't have an element after him. But why do we use n-1. Why we don't run outer loop from i=0 until i < n and inner from j=0 until n-i? Could someone explain it to me, tutorials on internet does not emphasize this.
for (int i = 0; i < n - 1; i++) // Why do we have n-1 here?
{
swapped = false;
for (int j = 0; j < n - i - 1; j++)
{
countComparisons++;
if (arr[j] > arr[j + 1])
{
countSwaps++;
swap(&arr[j], &arr[j + 1]);
swapped = true;
}
}
}
For example, if I have an array with 6 elements, why do I only need to make 5 iterations?
Because a swap requires at least two elements.
So if you have 6 elements, you only need to consider 5 consecutive pairs.
For comparison purposes in an array, two adjacent cells are needed; in an array of 6 elements, you do 5 comparisons only; in an array of 10 elements, 9 comparisons, and so on:
array and comparisons between adjacent cells
So for 7 elements, just 6 comparisons are done, hence the general rule of n-1 in the outer for loop
About the n-1-i expression, remember that the highest (or lowest, depending on the ordering criterion) value in the bubble sort goes to the last position in the array after the first cycle, so there is no need to compare that value with anything else, therefore the array has to be "shortened" 1 cell at a time, and the value of i in the outer loop is the counter responsible for that in the inner loop:
5 | 3 | 9 | 20 | elements (n) = 4
after first cycle (i = 0), 20 has reached its correct position within the array (using an ascending order), leaving us with an array of 3 elements to do comparisons to; in next cycle, i will be equal to 1, and as n-1 remains the same, we need to substract 1 in that expression to "shorten" the array:
n-1-i = 4-1-1 = 2, which is the index of the last element in that new array as well as the quantity of comparisons needed.
Hope it helps!
I'm currently stuck on a question regarding lists and formulating codes. I have to
For example, if list = [4,6] I would have to return 2. (4+6) and (6+4). This code has to work for any length of list and no two numbers will be the same within the list. I'm new to lists and and stuck on how to begin coding.
def countsum(list):
Would appreciate the help
def count_list_aux(num_possibilities, a_list, i, j):
if i == j: # Only 1 item to check now.
if a_list[i] == 10: # The item itself is 10 so that can be a combo.
return num_possibilities + 1
else: # Otherwise we are done.
return num_possibilities
else:
combo = a_list[i] + a_list[j]
if combo == 10: # (4,6) for instance.
return count_list_aux(num_possibilities+2, a_list, i+1, j-1)
elif combo > 10: # (4,8) for instance. Clearly 8 needs to go when we have a sorted list.
return count_list_aux(num_possibilities, a_list, i, j-1)
else: # (4,7) for instance. Clearly 4 needs to go when we have a sorted list.
return count_list_aux(num_possibilities, a_list, i+1, j)
def countsum(a_list):
a_list = sorted(a_list)
return count_list_aux(0, a_list, 0, len(a_list)-1)
print(countsum([4,6,3,7,5,2,8]))
I have made a recursive solution where I simply sort the list (ascending order) and then recursively add up left most (i) and right most (j) and check if they add up to 10. If they do, then I increment num_possibiltiies by 2 (eg. 6,4 and 4,6 are 2 combos). If the sum is greater than 10, then I decrement j by 1 because clearly, the current index j cannot work with any other values in the list (list is sorted). Similarly, if the sum is smaller than 10, I increment i by 1 as the current index i cannot work with any other values to get a sum of 10 (it failed with the largest value at index j).
The function can also be implemented using:
from itertools import combinations
from math import factorial
def countsum(L):
x = 10
n = 2
return sum(factorial(n) for c in combinations(L, n) if sum(c) == x)
The factorial is because combinations produces tuples that are sets of items, rather than counting each of the permutations, simply compute their count. As the factorial depends on a constant it can be hoisted:
def countsum(L):
x = 10
n = 2
return factorial(n) * sum(1 for c in combinations(L, n) if sum(c) == x)
next_permutation is a C++ function which gives the lexicographically next permutation of a string. Details about its implementation can be obtained from this really awesome post. http://wordaligned.org/articles/next-permutation
Is anyone aware of a similar implementation in Python?
Is there a direct python equivalent for STL iterators?
itertools.permutations is close; the biggest difference is it treats all items as unique rather than comparing them. It also doesn't modify the sequence in-place. Implementing std::next_permutation in Python could be a good exercise for you (use indexing on a list rather than random access iterators).
No. Python iterators are comparable to input iterators, which are an STL category, but only the tip of that iceberg. You must instead use other constructs, such as a callable for an output iterator. This breaks the nice syntax generality of C++ iterators.
Here's a straightforward Python 3 implementation of wikipedia's algorithm for generating permutations in lexicographic order:
def next_permutation(a):
"""Generate the lexicographically next permutation inplace.
https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
Return false if there is no next permutation.
"""
# Find the largest index i such that a[i] < a[i + 1]. If no such
# index exists, the permutation is the last permutation
for i in reversed(range(len(a) - 1)):
if a[i] < a[i + 1]:
break # found
else: # no break: not found
return False # no next permutation
# Find the largest index j greater than i such that a[i] < a[j]
j = next(j for j in reversed(range(i + 1, len(a))) if a[i] < a[j])
# Swap the value of a[i] with that of a[j]
a[i], a[j] = a[j], a[i]
# Reverse sequence from a[i + 1] up to and including the final element a[n]
a[i + 1:] = reversed(a[i + 1:])
return True
It produces the same results as std::next_permutation() in C++ except it doesn't transforms the input into the lexicographically first permutation if there are no more permutations.
itertools is seems to be what you need.
An implementation for the lexicographic-ally next permutation in Python (reference)
def lexicographically_next_permutation(a):
"""
Generates the lexicographically next permutation.
Input: a permutation, called "a". This method modifies
"a" in place. Returns True if we could generate a next
permutation. Returns False if it was the last permutation
lexicographically.
"""
i = len(a) - 2
while not (i < 0 or a[i] < a[i+1]):
i -= 1
if i < 0:
return False
# else
j = len(a) - 1
while not (a[j] > a[i]):
j -= 1
a[i], a[j] = a[j], a[i] # swap
a[i+1:] = reversed(a[i+1:]) # reverse elements from position i+1 till the end of the sequence
return True
A verbose implementation of this approach on lexicographic ordering
def next_permutation(case):
for index in range(1,len(case)):
Px_index = len(case) - 1 - index
#Start travelling from the end of the Data Structure
Px = case[-index-1]
Px_1 = case[-index]
#Search for a pair where latter the is greater than prior
if Px < Px_1 :
suffix = case[-index:]
pivot = Px
minimum_greater_than_pivot_suffix_index = -1
suffix_index=0
#Find the index inside the suffix where ::: [minimum value is greater than the pivot]
for Py in suffix:
if pivot < Py:
if minimum_greater_than_pivot_suffix_index == -1 or suffix[minimum_greater_than_pivot_suffix_index] >= Py:
minimum_greater_than_pivot_suffix_index=suffix_index
suffix_index +=1
#index in the main array
minimum_greater_than_pivot_index = minimum_greater_than_pivot_suffix_index + Px_index +1
#SWAP
temp = case[minimum_greater_than_pivot_index]
case[minimum_greater_than_pivot_index] = case[Px_index]
case[Px_index] = temp
#Sort suffix
new_suffix = case[Px_index+1:]
new_suffix.sort()
#Build final Version
new_prefix = case[:Px_index+1]
next_permutation = new_prefix + new_suffix
return next_permutation
elif index == (len(case) -1):
#This means that this is at the highest possible lexicographic order
return False
#EXAMPLE EXECUTIONS
print("===INT===")
#INT LIST
case = [0, 1, 2, 5, 3, 3, 0]
print(case)
print(next_permutation(case))
print("===CHAR===")
#STRING
case_char = list("dkhc")
case = [ord(c) for c in case_char]
print(case)
case = next_permutation(case)
print(case)
case_char = [str(chr(c)) for c in case]
print(case_char)
print(''.join(case_char))
The algorithm is implemented in module more_itertools as part of function more_itertools.distinct_permutations:
Documentation;
Source code.
def next_permutation(A):
# Find the largest index i such that A[i] < A[i + 1]
for i in range(size - 2, -1, -1):
if A[i] < A[i + 1]:
break
# If no such index exists, this permutation is the last one
else:
return
# Find the largest index j greater than j such that A[i] < A[j]
for j in range(size - 1, i, -1):
if A[i] < A[j]:
break
# Swap the value of A[i] with that of A[j], then reverse the
# sequence from A[i + 1] to form the new permutation
A[i], A[j] = A[j], A[i]
A[i + 1 :] = A[: i - size : -1] # A[i + 1:][::-1]
Alternatively, if the sequence is guaranteed to contain only distinct elements, then next_permutation can be implemented using functions from module more_itertools:
import more_itertools
# raises IndexError if s is already the last permutation
def next_permutation(s):
seq = sorted(s)
n = more_itertools.permutation_index(s, seq)
return more_itertools.nth_permutation(seq, len(seq), n+1)