I have a string of characters '<', '>', '?' for example <>> . Now I want to find the longest symmetric substring (first half letters are < and last half letters are >) by replacing ? with < or >
Case 1:
For example input string <><??>>, the longest can be obtained as <><<<>>. In this symmetric substring is <<>> which is of length 4.
Case 2:
Another example ??????, it can be replaced as <<<>>> with length 6.
My program:
public static int process(String s) {
StringBuilder sb = new StringBuilder();
for (char c : s.toCharArray()) {
if (c == '?') {
c = '<';
}
sb.append(c);
}
int max = 0;
int open = 0;
int close = 0;
char[] arr = sb.toString().toCharArray();
for (int i=0; i<arr.length; i++) {
char c = arr[i];
if (c == '<') {
open++;
} else {
int j=i;
for(; j<arr.length && arr[j] == '>'; j++) {
close++;
int curr = Math.min(open, close);
max = Math.max(curr, max);
}
open = 0;
close = 0;
i = j;
}
}
int curr = Math.min(open, close);
max = Math.max(curr, max);
return max*2;
}
My program works for case 1 and fails for case 2 as I am always replacing ? with < symbols. what is the correct approach to solve this problem.
Constraints:
Length of string can be from 1 to 200,000
You did not specify the size of the input Strings, and since premature optimization is the root of all evil, I would start with a brute force approach.
I would put the case of calculating the result for a "string without the letter ?" to a seperate method. This can be used as a recursion starting point.
Then, given a String that includes the letter ?, I would simply replace it with < and call itself recursively, then replace it with > and call itself recursively, compare the results and see which is better.
Note, that this will solve the problem, but increases exponentially in runtime as well as in memory with the number of ? letters in the given input String. If that's an issue, I hope you can take this idea as a baseline and optimize from there.
Edit:
200k is definitely too much for exponential growth. With this in mind, let me point you to Manacher's algorithm
It has linear runtime and you might be able to adjust it to your problem setting by letting count ? as both < or >, when determining the longest palindrome around a certain center point.
Below is an algorithm that I came up with; I'm not too sure if it's even correct, but if it is, it runs in the required constraints.
Basically, we uses dynamic programming to calculate the Longest Symmetric Substring (LSS) of the input S from the current index, using the result from its right neighbor. I believe there are only a few states that we have to worry about, for any arbitrary index i:
If S[i] is a > then we can't build a symmetric substring from i.
Inspect one past the end of the LSS from i+1. If it's a > or ? we can make a longer LSS.
Otherwise, check if we can maintain the length of the neighboring LSS. We do some preprocessing and leverage the symmetry of what's considered a symmetric substring to do this quickly.
If we can't maintain the length of the neighbor, then we can't have a LSS starting from index i. (This is the part I'm not certain about)
Anyhow, below is an implementation of the above algorithm along with some tests in Python(3+). It passes the small test cases I've come up with, but this is certainly not exhaustive and I'm not sure if the algorithm is even correct.
def solve(S):
"""
LSS = longest symmetric substring
Returns (length of LSS, start index of LSS)
"""
N = len(S)
next_opens, closest_idx = [-1] * N, -1 # next_opens[i] = closest '(' to the left of i, inclusive
all_qs = set() # index of all '?'
for i, c in enumerate(S):
if c == '<':
closest_idx = i
elif c == '?':
all_qs.add(i)
next_opens[i] = closest_idx
res, F, best_idx = 0, [0] * N, -1 # F[i] = length of LSS starting from i, including it
for i in range(N - 2, -1, -1):
if S[i] == '>': # do not bother
F[i] = 0
continue
nb_len = F[i + 1]
if i+nb_len+1 < N and (S[i+nb_len+1] == '?' or S[i+nb_len+1] == '>'): # leverage symmetry of neighbor to extend
F[i] = nb_len + 2 # +2 bc of index i and character to right
if F[i] > res: # update result
res = F[i]
best_idx = i
elif (S[i+nb_len-1] == '?' or S[i+nb_len-1] == '>'): # can be nb length
n_open = nb_len//2 # how many '(' / '?' in the first half
last_open_idx = i + n_open - 1
if next_opens[i+nb_len-1] == last_open_idx or last_open_idx in all_qs:
F[i] = nb_len
else: # pretty sure if we can't do at least nb_len, it's 0
F[i] = 0
else: # definitely 0
F[i] = 0
return res, best_idx
def print_sol(S, best_len, sub_idx):
print("--------")
print(f"Input: {S}")
print(f"Answer: {best_len}")
if best_len:
print(f"Substring: {S[sub_idx:sub_idx+best_len]} starting at index {sub_idx}")
else:
print("No symmetric substring found")
return
def main():
for S in [
"<><??>>",
"<>?<??>>",
"<><<??>>",
"<>",
"<<<>>>",
"??????",
"?????",
"?",
"><",
">",
"<"
"<<<???<???????>>>>",
"<><>?????><??>",
"??????>>"
]:
res, sub_idx = solve(S)
print_sol(S, res, sub_idx)
return 0
if __name__ == "__main__":
main()
And below is some sample output of the above:
--------
Input: <><??>>
Answer: 4
Substring: ??>> starting at index 3
--------
Input: <>?<??>>
Answer: 6
Substring: ?<??>> starting at index 2
--------
Input: <><<??>>
Answer: 6
Substring: <<??>> starting at index 2
--------
Input: <>
Answer: 2
Substring: <> starting at index 0
--------
Input: <<<>>>
Answer: 6
Substring: <<<>>> starting at index 0
--------
Input: ??????
Answer: 6
Substring: ?????? starting at index 0
--------
Input: ?????
Answer: 4
Substring: ???? starting at index 1
--------
Input: ?
Answer: 0
No symmetric substring found
--------
Input: ><
Answer: 0
No symmetric substring found
--------
Input: >
Answer: 0
No symmetric substring found
--------
Input: <<<<???<???????>>>>
Answer: 18
Substring: <<<???<???????>>>> starting at index 1
--------
Input: <><>?????><??>
Answer: 6
Substring: ?????> starting at index 4
--------
Input: ??????>>
Answer: 8
Substring: ??????>> starting at index 0
I'm thinking about something like:
String s = "<><>?????><??>";
int len = s.length();
if (len < 2) {
return 0;
}
int[] left = new int[len - 1];
int[] right = new int[len - 1];
left[0] = s.charAt(0) != '>' ? 1 : 0;
for (int i = 1; i < len - 1; i++) {
left[i] = s.charAt(i) != '>' ? left[i - 1] + 1 : 0;
}
right[len - 2] = s.charAt(len - 1) != '<' ? 1 : 0;
for (int i = len - 3; i >= 0; i--) {
right[i] = s.charAt(i + 1) != '<' ? right[i + 1] + 1 : 0;
}
int max = 0;
for (int i = 0; i < len - 1; i++) {
max = Math.max(max, 2 * Math.min(left[i], right[i]));
}
return max;
i.e. for each position between symbols we count the continuous length of < and ? to the left and continuous length of > and ? to the right.
Here is a linear algorithm. It has 3 variables start, mid, and end. All start at the beginning of the string, at each step at least one advances, and at some point we'll be sure to find any symmetric pattern that can be made which is < until mid and then > afterwards.
Note, I'm using the idiosyncratic definition of "symmetric" in the OP. Namely, "first half letters are < and last half letters are >". This definition is NOT the same as a palindrome. So, for instance, <<><<>><>> would NOT be counted as symmetric.
def longest_symmetric (string):
start = mid = last_gt = end = 0
best = 0
while start < len(string):
#print(start, mid, last_gt, end)
current = min(mid - start, end - mid)
if best < current:
best = current
if end - mid == current and end < len(string):
if string[end] == '?':
end += 1
elif string[end] == '>':
end += 1
last_gt = end
else:
end += 1
mid = end
start = max(start, last_gt)
elif mid < len(string) and string[mid] == '?':
mid += 1
elif start < mid:
start += 1
else:
start = max(start, last_gt)
mid = mid + 1
end = max(mid, end)
return 2*best
for s in ('?????', '??????', '<><??>>', '<<?'):
print(s, longest_symmetric(s))
Related
Given an input string of digits, split that into groups of prime numbers by maintaining the order given in the input string and each group should hold all the characters of the input string. Find the count of such groups.
Example:
11375
Ans:
3
Explanation:
The 3 combinations are [11,37,5], [11,3,7,5] and [113,7,5]
Code that I tried
public int countPossibilities(String s) {
int n = s.length();
int[] ar = new int[n + 1];
ar[0] = 1;
for (int i = 1; i < n; i++) {
int j = i - 1;
while (j >= 0 && j >= i - 3) {
if (prime(s.substring(j, i)))
ar[i] += ar[j];
j--;
}
}
return ar[n];
}
public boolean prime(String s) {
int n = Integer.parseInt(s);
if (n < 2) return false;
for (int i = 2; i * i <= n; i++)
if (n % i == 0) return false;
return true;
}
This works fine if the input string length is small.
But the length of the input string can be from 1 to 10^5. So my program fails for large strings.
Example:
1350297079989171477791892123929141605573631151125933376097791877830238462471373933362476484818693477173990672289892448124097556197582379957168911392680312103962394732707409889862447273901522659
Expected result is : 4386816
What is the right approach to solve this problem.
Here's working Python code that answers your long example.
Let dp[i] represent the number of valid combinations ending at the ith index of the input. Then for each prime suffix of length x ending at input[i], we add to dp[i] the count of valid combinations ending at dp[i-x], provided there is also a count of valid combinations recorded for dp[i-x].
# https://rosettacode.org/wiki/Sieve_of_Eratosthenes
def primes2(limit):
if limit < 2: return []
if limit < 3: return [2]
lmtbf = (limit - 3) // 2
buf = [True] * (lmtbf + 1)
for i in range((int(limit ** 0.5) - 3) // 2 + 1):
if buf[i]:
p = i + i + 3
s = p * (i + 1) + i
buf[s::p] = [False] * ((lmtbf - s) // p + 1)
return set(["2"] + [str(i + i + 3) for i, v in enumerate(buf) if v])
def f(n):
# The constant, k, limits the number
# of digits in the suffix we're
# checking for primality.
k = 6
primes = primes2(10**k)
dp = [0] * len(n) + [1]
for i in range(len(n)):
suffix = ""
for j in range(min(i + 1, k)):
suffix = n[i-j] + suffix
if suffix in primes and dp[i-j-1] > 0:
dp[i] += dp[i-j-1]
return dp[len(n) - 1]
Output:
n = "1350297079989171477791892123929141605573631151125933376097791877830238462471373933362476484818693477173990672289892448124097556197582379957168911392680312103962394732707409889862447273901522659"
print(f(n)) # 4386816
Proof of concept from my comments, but in C# (I'm an AP Comp Sci teacher that doesn't like to code in Java; go figure!):
Take the length of the input string minus 1 and call this "padLength".
Now raise 2 to the power of padLength to get the total number of
possibilities for string combinations; call this number
"numberOfCombinations". Next, count from 0 to numberOfCombinations and
convert that decimal number to a BINARY number, left padded with
zeroes out to padLength, called "binaryNumber". The binary number
represents whether or not a space should be added in-between the
digits of the original number. For instance, binary "1100" and dec
"11375" would result in "1 1 375" because 1 means put a space
in-between. This process will give you all combinations of the
original string in the different groups. Then you can extract the
numbers from the groups and see if they are primes...
Code:
private async void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text.Trim().Length == 0) { return; }
textBox1.Enabled = false;
button1.Enabled = false;
textBox2.Clear();
String binary;
StringBuilder sb = new StringBuilder();
String input = textBox1.Text.Trim();
char[] digits = input.ToCharArray();
int padLength = input.Length - 1;
long combinations = (long)Math.Pow(2, padLength);
List<String> combos = new List<string>();
await Task.Run(() => {
for (long i = 0; i < combinations; i++)
{
binary = Convert.ToString(i, 2).ToString().PadLeft(padLength, '0');
char[] binaryDigits = binary.ToCharArray();
sb.Clear();
for (int s = 0; s < digits.Length; s++)
{
sb.Append(digits[s]);
if (s < (digits.Length - 1))
{
if (binaryDigits[s] == '1')
{
sb.Append(' ');
}
}
}
combos.Add(sb.ToString());
}
});
textBox2.Lines = combos.ToArray();
textBox1.Enabled = true;
button1.Enabled = true;
}
Output:
For very large inputs, you won't be able to compute the number of combinations using Math.Pow(), or any built-in methods for converting a decimal to a binary number. In those cases, you can "count manually" in binary by using a String directly and following the counting algorithm. You'd build the binary numbers using only String manipulation directly by inspecting each char to see if it is 1 or 0 and acting accordingly. You'll know you're done when you have a string of ones that has a length one less than the length of your input. It will run a lot slower than working with numbers directly.
I am trying to work out a solution to the CodeWars challenge Catching Car Mileage Numbers:
Write the function that parses the mileage number input, and returns a 2 if the number is "interesting" (see below), a 1 if an interesting number occurs within the next two miles, or a 0 if the number is not interesting.
Interesting numbers are 3-or-more digit numbers that meet one or more of the following criteria:
Any digit followed by all zeros: 100, 90000
Every digit is the same number: 1111
The digits are sequential, incementing†: 1234
The digits are sequential, decrementing‡: 4321
The digits are a palindrome: 1221 or 73837
The digits match one of the values in the awesomePhrases array
† For incrementing sequences, 0 should come after 9, and not before 1, as in 7890.
‡ For decrementing sequences, 0 should come after 1, and not before 9, as in 3210.
I can pass all tests in the first batch, but fail to pass the second batch.
Any feedback would be very much appreciated, not only on a possible solution but also to the way I'm thinking about the exercise.
public static int isInteresting(int number, int[] awesomePhrases) {
for (int offSet = 0; offSet <= 2; offSet++) {
int testNumber = number;
testNumber += offSet;
boolean isYellow = testNumber != number;
int yellowOffset = 0;
if (isYellow) {
yellowOffset = 1;
}
//check three or more digit number
boolean greaterThan99 = testNumber > 99;
int[] numbers = Integer.toString(testNumber).chars().map(c -> c - '0').toArray();
int zeroCounter = 0;
int identicalCounter = 0;
int incrementingCounter = 0;
int decrementingCounter = 0;
int palindromeCounter = 0;
boolean endsInZero = numbers[numbers.length - 1] == 0;
for (int i = 0; i < numbers.length; i++) {
//check digit followed by zeros
if (numbers[i] == 0) {
zeroCounter++;
}
if (i + 1 < numbers.length) {
//check every digit is the same
if (numbers[i] == numbers[i + 1]) identicalCounter++;
//check ascending order
if (numbers[i + 1] - numbers[i] == 1) incrementingCounter++;
//check descending order
if (numbers[i] - numbers[i + 1] == 1) decrementingCounter++;
}
}
if (greaterThan99) {
//check awesomePhrases
for (int phrase : awesomePhrases) {
if (phrase == testNumber) return 2 - yellowOffset;
}
//check palindrome
int reversedIndex = numbers.length - 1;
for (int i = 0; i < numbers.length; i++) {
if (numbers[reversedIndex] == numbers[i]) {
palindromeCounter++;
}
reversedIndex--;
}
if (zeroCounter == numbers.length - 1) return 2 - yellowOffset;
if (identicalCounter == numbers.length - 1) return 2 - yellowOffset;
if (incrementingCounter == numbers.length - 1) return 2 - yellowOffset;
if (incrementingCounter == numbers.length - 2 && endsInZero) return 2 - yellowOffset;
if (decrementingCounter == numbers.length - 1) return 2 - yellowOffset;
if (decrementingCounter == numbers.length - 2 && endsInZero) return 2 - yellowOffset;
if (palindromeCounter == numbers.length) return 2 - yellowOffset;
}
}
return 0;
}
I've tried pretty much all I know but to no result, all the tests I try pass, would love to know what I'm doing wrong.
The problem is in how your code tests for increasing sequences that end in a zero. It is not enough to test that the sequence has n-2 increments and the last digit is a zero, because that will give a false positive on numbers like 6780. It is required that the one-but-last digit is a 9.
A similar issue exist for the decreasing sequence logic, however, there you would not need a special test for an ending zero at all. This condition is covered by counting n-1 decrements, where the ending could be a 1 followed by a zero. There is no special case to be handled here.
To fix the first problem, I would suggest you not only check whether the last digit is a zero, but whether the last two digits are 9 and 0, or in other words, that the number modulo 100 is equal to 90.
You could replace this:
boolean endsInZero = numbers[numbers.length - 1] == 0;
by this:
boolean endsInNinety = testNumber % 100 == 90;
and then replace:
if (incrementingCounter == numbers.length - 2 && endsInZero) return 2 - yellowOffset;
by:
if (incrementingCounter == numbers.length - 2 && endsInNinety) return 2 - yellowOffset;
and finally remove this test:
if (decrementingCounter == numbers.length - 2 && endsInZero) return 2 - yellowOffset;
This will fix it.
Note that it can be helpful to have your function print the input it gets, so that when a test fails, at least you can know for which input there was a problem:
System.out.println("input " + number);
I had an interview and I've been asked to print numbers from 1 to a 1000 digit number -
1,
2,
3,
.
.
.
.,
999999999999999999999999999999999999999999999999........
I couldn't solve it but I'm still looking for the best way to do it, because obviously, you cant use integers or floats in a case like this and because it's a job interview I couldn't use any libraries that can handle it.
Can anyone think of a good solution? preferably in Java/pseudocode.
I had an interview and I've been asked to print numbers from 1 to a 1000 digit number
I guess the kind of answer they expected you to give is:
"We need to print the numbers from 1 to 10^1000-1. Last year, $80e9 worth of processors were sold worldwide [1], even if one processor per dollar had been sold and each processor was a thousand times faster than the fastest of them all [2] and only one instruction was used to print each number and all these processors had been produced during the last 1000 years, still: 1e1000 / (80e9 - 1000 - 8.4e9 - 1000) > 1e973 seconds to print all the numbers. That is 10e956 billion years."
Anyway, if you wish wait:
BigInteger n = BigInteger.ONE;
BigInteger last = BigInteger.TEN.pow(1000);
while(n.compareTo(last) < 0) {
System.out.println(n);
n = n.add(BigInteger.ONE);
}
Assuming only System.out.print is able to use (String is a library, see [3]), a possible solution without copy over and over again strings, and with the expected output could be:
static void printDigits(int n) {
ds(0, n, new byte[n]);
}
static void ds(int p, int k, byte[] d) {
if (p < d.length) { // if more digits to print
for (byte i = 0; i < 10; i++) { // from digit 0 to 9
d[p] = i; // set at this position
ds(p + 1, i == 0 ? k : (p < k ? p : k), d); // populate next storing first non-zero
}
} else {
if(k < d.length) { // if is not zero
if(k < d.length - 1 || d[d.length - 1] != 1) // if is not one
System.out.print(", "); // print separator
for(int i = k; i < d.length; i++) // for each digit
System.out.print((char)('0' + d[i])); // print
}
}
}
then, for printDigits(5) the output is
1, 2, 3, 4, ..., 99999
[1] https://epsnews.com/2020/09/14/total-microprocessor-sales-to-edge-slightly-higher-in-2020/
[2] https://en.wikipedia.org/wiki/Clock_rate
[3] https://docs.oracle.com/javase/7/docs/api/java/lang/String.html
Using recursion (if only to print):
void digits(int count) {
if (count < 0) throw new IllegalArgumentException("invalid count: " + count);
digits(count, "");
}
void digits(int count, String text) {
if (count == 0) {
System.out.println(text);
} else {
for (var i = 0; i < 10; i++) {
if (i == 0 && text.isEmpty()) {
digits(count-1, text);
} else {
digits(count-1, text+i);
}
}
}
}
Given a string of even size, say:
abcdef123456
How would I interleave the two halves, such that the same string would become this:
a1b2c3d4e5f6
I tried attempting to develop an algorithm, but couldn't. Would anybody give me some hints as to how to proceed? I need to do this without creating extra string variables or arrays. One or two variable is fine.
I just don't want a working code (or algorithm), I need to develop an algorithm and prove it correctness mathematically.
You may be able to do it in O(N*log(N)) time:
Want: abcdefgh12345678 -> a1b2c3d4e5f6g7h8
a b c d e f g h
1 2 3 4 5 6 7 8
4 1-sized swaps:
a 1 c 3 e 5 g 7
b 2 d 4 f 6 h 8
a1 c3 e5 g7
b2 d4 f6 h8
2 2-sized swaps:
a1 b2 e5 f6
c3 d4 g7 h8
a1b2 e5f6
c3d4 g7h8
1 4-sized swap:
a1b2 c3d4
e5f6 g7h8
a1b2c3d4
e5f6g7h8
Implementation in C:
#include <stdio.h>
#include <string.h>
void swap(void* pa, void* pb, size_t sz)
{
char *p1 = pa, *p2 = pb;
while (sz--)
{
char tmp = *p1;
*p1++ = *p2;
*p2++ = tmp;
}
}
void interleave(char* s, size_t len)
{
size_t start, step, i, j;
if (len <= 2)
return;
if (len & (len - 1))
return; // only power of 2 lengths are supported
for (start = 1, step = 2;
step < len;
start *= 2, step *= 2)
{
for (i = start, j = len / 2;
i < len / 2;
i += step, j += step)
{
swap(s + i,
s + j,
step / 2);
}
}
}
char testData[][64 + 1] =
{
{ "Aa" },
{ "ABab" },
{ "ABCDabcd" },
{ "ABCDEFGHabcdefgh" },
{ "ABCDEFGHIJKLMNOPabcdefghijklmnop" },
{ "ABCDEFGHIJKLMNOPQRSTUVWXYZ0<({[/abcdefghijklmnopqrstuvwxyz1>)}]\\" },
};
int main(void)
{
unsigned i;
for (i = 0; i < sizeof(testData) / sizeof(testData[0]); i++)
{
printf("%s -> ", testData[i]);
interleave(testData[i], strlen(testData[i]));
printf("%s\n", testData[i]);
}
return 0;
}
Output (ideone):
Aa -> Aa
ABab -> AaBb
ABCDabcd -> AaBbCcDd
ABCDEFGHabcdefgh -> AaBbCcDdEeFfGgHh
ABCDEFGHIJKLMNOPabcdefghijklmnop -> AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPp
ABCDEFGHIJKLMNOPQRSTUVWXYZ0<({[/abcdefghijklmnopqrstuvwxyz1>)}]\ -> AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz01<>(){}[]/\
Generically that problem is quite hard -- and it reduces to finding permutation cycles. The number and length of those varies quite a lot depending on the length.
The first and last cycles are always degenerate; the 10 entry array has 2 cycles of lengths 6 and 2 and the 12 entry array has a single cycle of length 10.
Withing a cycle one does:
for (i=j; next=get_next(i) != j; i=next) swap(i,next);
Even though the function next can be implemented as some relatively easy formula of N, the problem is postponed to do book accounting of what indices have been swapped. In the left case of 10 entries, one should [quickly] find the starting positions of the cycles (they are e.g. 1 and 3).
Ok lets start over. Here is what we are going to do:
def interleave(string):
i = (len(string)/2) - 1
j = i+1
while(i > 0):
k = i
while(k < j):
tmp = string[k]
string[k] = string[k+1]
string[k+1] = tmp
k+=2 #increment by 2 since were swapping every OTHER character
i-=1 #move lower bound by one
j+=1 #move upper bound by one
Here is an example of what the program is going to do. We are going to use variables i,j,k. i and j will be the lower and upper bounds respectively, where k is going to be the index at which we swap.
Example
`abcd1234`
i = 3 //got this from (length(string)/2) -1
j = 4 //this is really i+1 to begin with
k = 3 //k always starts off reset to whatever i is
swap d and 1
increment k by 2 (k = 3 + 2 = 5), since k > j we stop swapping
result `abc1d234` after the first swap
i = 3 - 1 //decrement i
j = 4 + 1 //increment j
k= 2 //reset k to i
swap c and 1, increment k (k = 2 + 2 = 4), we can swap again since k < j
swap d and 2, increment k (k = 4 + 2 = 6), k > j so we stop
//notice at EACH SWAP, the swap is occurring at index `k` and `k+1`
result `ab1c2d34`
i = 2 - 1
j = 5 + 1
k = 1
swap b and 1, increment k (k = 1 + 2 = 3), k < j so continue
swap c and 2, increment k (k = 3 + 2 = 5), k < j so continue
swap d and 3, increment k (k = 5 + 2 = 7), k > j so were done
result `a1b2c3d4`
As for proving program correctness, see this link. It explains how to prove this is correct by means of a loop invariant.
A rough proof would be the following:
Initialization: Prior to the first iteration of the loop we can see that i is set to
(length(string)/2) - 1. We can see that i <= length(string) before we enter the loop.
Maintenance. After each iteration, i is decremented (i = i-1, i=i-2,...) and there must be a point at which i<length(string).
Termination: Since i is a decreasing sequence of positive integers, the loop invariant i > 0 will eventually equate to false and the loop will exit.
The solution is here J. Ellis and M. Markov. In-situ, stable merging by way of perfect shuffle.
The Computer Journal. 43(1):40-53, (2000).
Also see the various discussions here:
https://cs.stackexchange.com/questions/332/in-place-algorithm-for-interleaving-an-array/400#400
https://cstheory.stackexchange.com/questions/13943/linear-time-in-place-riffle-shuffle-algorithm.
Alright, here's a rough draft. You say you don't just want an algorithm, but you are taking hints, so consider this algorithm a hint:
Length is N.
k = N/2 - 1.
1) Start in the middle, and shift (by successive swapping of neighboring pair elements) the element at position N/2 k places to the left (1st time: '1' goes to position 1).
2) --k. Is k==0? Quit.
3) Shift (by swapping) the element at N/2 (1st time:'f' goes to position N-1) k places to the right.
4) --k.
Edit: The above algorithm is correct, as the code below shows. Actually proving that it's correct is waaay beyond my capabilities, fun little question though.
#include <iostream>
#include <algorithm>
int main(void)
{
std::string s("abcdefghij1234567890");
int N = s.size();
int k = N/2 - 1;
while (true)
{
for (int j=0; j<k; ++j)
{
int i = N/2 - j;
std::swap(s[i], s[i-1]);
}
--k;
if (k==0) break;
for (int j=0; j<k; ++j)
{
int i = N/2 + j;
std::swap(s[i], s[i+1]);
}
--k;
}
std::cout << s << std::endl;
return 0;
}
Here's an algorithm and working code. It is in place, O(N), and conceptually simple.
Walk through the first half of the array, swapping items into place.
Items that started in the left half will be swapped to the right
before we need them, so we use a trick to determine where they
were swapped to.
When we get to the midpoint, unscramble the unplaced left items that were swapped to the right.
A variation of the same trick is used to find the correct order for unscrambling.
Repeat for the remaining half array.
This goes through the array making no more than N+N/2 swaps, and requires no temporary storage.
The trick is to find the index of the swapped items. Left items are swapped into a swap space vacated by the Right items as they are placed. The swap space grows by the following sequence:
Add an item to the end(into the space vacated by a Right Item)
Swap an item with the oldest existing (Left) item.
Adding items 1..N in order gives:
1 2 23 43 435 465 4657 ...
The index changed at each step is:
0 0 1 0 2 1 3 ...
This sequence is exactly OEIS A025480, and can be calculated in O(1) amortized time:
def next_index(n):
while n&1: n=n>>1
return n>>1
Once we get to the midpoint after swapping N items, we need to unscramble. The swap space will contain N/2 items where the actual index of the item that should be at offset i is given by next_index(N/2+i). We can advance through the swaps space, putting items back in place. The only complication is that as we advance, we may eventually find a source index that is left of the target index, and therefore has already been swapped somewhere else. But we can find out where it is by doing the previous index look up again.
def unscramble(start,i):
j = next_index(start+i)
while j<i: j = next_index(start+j)
return j
Note that this only an indexing calculation, not data movement. In practice, the total number of calls to next_index is < 3N for all N.
That's all we need for the complete implementation:
def interleave(a, idx=0):
if (len(a)<2): return
midpt = len(a)//2
# the following line makes this an out-shuffle.
# add a `not` to make an in-shuffle
base = 1 if idx&1==0 else 0
for i in range(base,midpt):
j=next_index(i-base)
swap(a,i,midpt+j)
for i in range(larger_half(midpt)-1):
j = unscramble( (midpt-base)//2, i);
if (i!=j):
swap(a, midpt+i, midpt+j)
interleave(a[midpt:], idx+midpt)
The tail-recursion at the end can easily be replaced by a loop. It's just less elegant with Python's array syntax. Also note that for this recursive version, the input must be a numpy array instead of a python list, because standard list slicing creates copies of the indexes that are not propagated back up.
Here's a quick test to verify correctness. (8 perfect shuffles of a 52 card deck restore it to the original order).
A = numpy.arange(52)
B = A.copy()
C =numpy.empty(52)
for _ in range(8):
#manual interleave
C[0::2]=numpy.array(A[:26])
C[1::2]=numpy.array(A[26:])
#our interleave
interleave(A)
print(A)
assert(numpy.array_equal(A,C))
assert(numpy.array_equal(A, B))
I am designing a program to print all permutations of a given N such that the each digit should be greater than the next digit.
For Example
if N=3:
output should be 123,456,789,134,145,178,189 etc...
Initial Design:
Generate all possible permutations
Pass the generated permutation to a digit extraction function which checks for the condition
Print out the result
This is a very naive algorithm. But I do not know the implementation/initial design because of the dynamic size of N.
Since N will always be less than 10, i've used recursion
Call the function as f(3,0,0)
public static void f(int N,int digit,int num)
{
if(N > 0 )
{
for(int d = digit + 1; d < 11 - N; d++) // earlier d < 10, see comments
{
f(N-1,d,num * 10 + d);
}
}else {
System.out.println(num); //add it to a list or whatever
}
}
Output:
123
124
...
678
679
689
789
The most straightforward way to do this is with recursion. Suppose you've generated the first n digits and the last digit generated is i. You have N - n digits left to generate and they must start with i + 1 or higher. Since the last digit can be no more than 9, the next digit can be no more than 10 - (N - n). This gives the basic rule for recursion. Something like this (in Java) should work:
void generate(int N) {
int[] generated = new int[N];
generate(generated, 0);
}
void generate(int[] generated, int nGenerated) {
if (nGenerated == generated.length) {
// print the generated digits
for (int g : generated) {
System.out.print(g);
}
System.out.println();
return;
}
int max = 10 - (generated.length - nGenerated);
int min = nGenerated == 0 ? 1 : (generated[nGenerated - 1] + 1);
for (int i = min; i <= max; ++i) {
generated[nGenerated] = i;
generate(generated, nGenerated + 1);
}
}
Just generate them in lexicographic order:
123
124
125
...
134
135
...
145
...
234
235
...
245
...
345
This assumes you have digits at most 5. For larger bound B, just keep going. Some simple code to do this is:
nextW = w;
for (int i=n-1; i>=0; --i) {
// THE LARGEST THE iTH DIGIT CAN BE IS B-(n-i-1)
// OTHERWISE YOU CANNOT KEEP INCREASING AFTERWARDS
// WITHOUT USING A NUMBER LARGER THAN B
if w[i]<B-(n-i-1) {
// INCREMENT THE RIGHTMOST POSITION YOU CAN
nextW[i] = w[i]+1;
// MAKE THE SEQUENCE FROM THERE INCREASE BY 1
for (int j=i+1; j<N; ++j) {
nextW[j] = w[i]+j-i+1;
}
// VOILA
return nextW;
}
}
return NULL;
Start with w = [1,2,3,...,N]; (easy to make with a for loop), print w, call the function above with w as an input, print that, and continue. With N = 3 and B = 5, the answer will be the above list (without the ... lines).
If there is no bound B, then you're SOL because there are infinitely many.
In general, you are computing the Nth elementary symmetric function e_N.