Understanding of Recursive Method (Permutations) [duplicate] - java

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I am working on a project. I found this code regarding permutations on the Interwebz. I would like to use it as a basis for writing my own code. However, I don't really understand what is going on in the code. Could anybody lend me a hand and explain what the code is doing exactly?
public void permutations(String prefix, String s) {
int n = s.length();
if (n == 0)
System.out.println(prefix);
else {
for(int i = 0; i < n; i++){
permutations(prefix + s.charAt(i), s.substring(0, i) + s.substring(i+1, n));
}
}
}

The method permutations is taking in a String prefix and a String s as its parameters.
The int type n is being set to the length of the String s. (length of a String being how many characters it contains).
Now we move on to the if-else statements. The if statement is saying, if the length of s is 0, that is, s is a blank String and does not contain any information, then we are simply printing the String prefix instead to the console. The method will then skip over the else part and execute the code after the permutations method.
If the if statement's conditions are not met, we are going to run the else statement is saying, for each character in the String s, we are going to append (add) that character at the end of prefix, so for example, if prefix was originally "hello" and the character was 'U', we would get prefix to be "helloU". After we are finished appending all of the characters in s, we are going to be using the result as the new prefix String.
For the other parameter, the String s, we are going to be taking part of the String, from character 0 (inclusive) to character at position i (exclusive). Please note that the String indexes start at 0 and go up to (The length of the String - 1). We are also taking the part of the String from the character at position i + 1 (inclusive) to the last character in the String s. We are going to use this result as the new s String.
Then we would be calling the method again, and then the method would execute again with the newly defined Strings if the else condition is met. This would continue in a loop until the else condition is not met, at which point the method would stop running and we would move on to the next section of code (if it is present).

p(String prefix, String s) takes 1 character out of s and adds it to prefix and recursively continues until s is empty.
The s.charAt(i), s.substring(0, i) + s.substring(i+1, n) part extracts a character from s.
Assume s = "Magic!" and i = 3 then charAt(i) = 'i', s.substring(0, i) = "Mag" and s.substring(i+1, n) = c!". That spilts Magic! into i and Magc!. Next time in the loop with i = 4 it will result in c + Magi!. Since it does that for every character in s every character will be in the front in one of the recursive steps.
The call hierarchy would look like this
/ p("ab", "c") - "abc"
/- p("a", "bc") x
/ \ p("ac", "b") - "acb"
/
/ / p("ba", "c") - "bac"
p("", "abc") x ---- p("b", "ac") x
\ \ p("bc", "a") - "bca"
\
\ / p("ca", "b") - "cab"
\- p("c", "ab") x
\ p("cb", "a") - "cba"
^-- 1st for loop ^- 2nd for ^- 3rd one prints

permutations(prefix + s.charAt(i), s.substring(0, i) + s.substring(i+1, n));
Actually, this permutation algorithm is using the idea of
Switching current character with ith character.
Suppose we have a string abc. So the permutation of it is:
abc, acb, bac, bca, cab, cba
We can find that the acb is just switching b and c in abc with prefix a. And the bca is just switching c and a in bac with prefix b.
Then we just use the same idea to recursively solve permutation problem.

This is some really confusing code, for two reasons:
The prefix argument: you should call this function with an empty string in the first argument, for example permutations("", "ab") to print all (both) permutations of "ab".
The recursive call with s.substring(0, i) + s.substring(i+1, n) in the second argument: note that java's String.substring(x,y) will not include the y-th character. So this amounts to passing s with the y-th character deleted.
Now think what happens as you step through the for loop: the first argument becomes "" concatenated with "a", i.e. "a", and the second argument becomes s with the first character deleted, i.e. "b". In the next recursive subcall, prefix becomes "ab" and the second argument becomes the empty string "". So the base-case n == 0 gets hit and we print the result "ab".
Now we go to the next iteration of the for loop, i == 1. Now we pass "b" in the first argument of our recursive subcall, and "a" in the second argument. In the next recursive subcall prefix becomes "ba" and s.length is 0, so base case again: print "ba".
It's clever, but inscrutable.

Related

Strange behavior of Java String split() method

I have a method which takes a string parameter and split the string by # and after splitting it prints the length of the array along with array elements. Below is my code
public void StringSplitTesting(String inputString) {
String tokenArray[] = inputString.split("#");
System.out.println("tokenArray length is " + tokenArray.length
+ " and array elements are " + Arrays.toString(tokenArray));
}
Case I : Now when my input is abc# the output is tokenArray length is 1 and array elements are [abc]
Case II : But when my input is #abc the output is tokenArray length is 2 and array elements are [, abc]
But I was expecting the same output for both the cases. What is the reason behind this implementation? Why split() method is behaving like this? Could someone give me proper explanation on this?
One aspect of the behavior of the one-argument split method can be surprising -- trailing nulls are discarded from the returned array.
Trailing empty strings are therefore not included in the resulting array.
To get a length of 2 for each case, you can pass in a negative second argument to the two-argument split method, which means that the length is unrestricted and no trailing empty strings are discarded.
Just take a look in the documentation:
Trailing empty strings are therefore not included in the resulting
array.
So in case 1, the output would be {"abc", ""} but Java cuts the trailing empty String.
If you don't want the trailing empty String to be discarded, you have to use split("#", -1).
The observed behavior is due to the inherently asymmetric nature of the substring() method in Java:
This is the core of the implementation of split():
while ((next = indexOf(ch, off)) != -1) {
if (!limited || list.size() < limit - 1) {
list.add(substring(off, next));
off = next + 1;
} else { // last one
//assert (list.size() == limit - 1);
list.add(substring(off, value.length));
off = value.length;
break;
}
}
The key to understanding the behavior of the above code is to understand the behavior of the substring() method:
From the Javadocs:
String java.lang.String.substring(int beginIndex, int endIndex)
Returns a new string that is a substring of this string. The substring
begins at the specified beginIndex and extends to the character at index
endIndex - 1. Thus the length of the substring is endIndex-beginIndex.
Examples:
"hamburger".substring(4, 8) returns "urge" (not "urger")
"smiles".substring(1, 5) returns "mile" (not "miles")
Hope this helps.

Find every possible subset given a string [duplicate]

This question already has answers here:
Memory efficient power set algorithm
(5 answers)
Closed 8 years ago.
I'm trying to find every possible anagram of a string in Java - By this I mean that if I have a 4 character long word I want all the possible 3 character long words derived from it, all the 2 character long and all the 1 character long. The most straightforward way I tought of is to use two nested for loops and iterare over the string. This is my code as of now:
private ArrayList<String> subsets(String word){
ArrayList<String> s = new ArrayList<String>();
int length = word.length();
for (int c=0; c<length; c++){
for (int i=0; i<length-c; i++){
String sub = word.substring(c, c+i+1);
System.out.println(sub);
//if (!s.contains(sub) && sub!=null)
s.add(sub);
}
}
//java.util.Collections.sort(s, new MyComparator());
//System.out.println(s.toString());
return s;
}
My problem is that it works for 3 letter words, fun yelds this result (Don't mind the ordering, the word is processed so that I have a string with the letters in alphabetical order):
f
fn
fnu
n
nu
u
But when I try 4 letter words, it leaves something out, as in catq gives me:
a
ac
acq
acqt
c
cq
cqt
q
qt
t
i.e., I don't see the 3 character long word act - which is the one I'm looking for when testing this method. I can't understand what the problem is, and it's most likely a logical error I'm making when creating the substrings. If anyone can help me out, please don't give me the code for it but rather the reasoning behind your solution. This is a piece of coursework and I need to come up with the code on my own.
EDIT: to clear something out, for me acq, qca, caq, aqc, cqa, qac, etc. are the same thing - To make it even clearer, what happens is that the string gets sorted in alphabetical order, so all those permutations should come up as one unique result, acq. So, I don't need all the permutations of a string, but rather, given a 4 character long string, all the 3 character long ones that I can derive from it - that means taking out one character at a time and returning that string as a result, doing that for every character in the original string.
I hope I have made my problem a bit clearer
It's working fine, you just misspelled "caqt" as "acqt" in your tests/input.
(The issue is probably that you're sorting your input. If you want substrings, you have to leave the input unsorted.)
After your edits: see Generating all permutations of a given string Then just sort the individual letters, and put them in a set.
Ok, as you've already devised your own solution, I'll give you my take on it. Firstly, consider how big your result list is going to be. You're essentially taking each letter in turn, and either including it or not. 2 possibilities for each letter, gives you 2^n total results, where n is the number of letters. This of course includes the case where you don't use any letter, and end up with an empty string.
Next, if you enumerate every possibility with a 0 for 'include this letter' and a 1 for don't include it, taking your 'fnu' example you end up with:
000 - ''
001 - 'u'
010 - 'n'
011 - 'nu'
100 - 'f'
101 - 'fu' (no offense intended)
110 - 'fn'
111 - 'fnu'.
Clearly, these are just binary numbers, and you can derive a function that given any number from 0-7 and the three letter input, will calculate the corresponding subset.
It's fairly easy to do in java.. don't have a java compiler to hand, but this should be approximately correct:
public string getSubSet(string input, int index) {
// Should check that index >=0 and < 2^input.length here.
// Should also check that input.length <= 31.
string returnValue = "";
for (int i = 0; i < input.length; i++) {
if (i & (1 << i) != 0) // 1 << i is the equivalent of 2^i
returnValue += input[i];
}
return returnValue;
}
Then, if you need to you can just do a loop that calls this function, like this:
for (i = 1; i < (1 << input.length); i++)
getSubSet(input, i); // this doesn't do anything, but you can add it to a list, or output it as desired.
Note I started from 1 instead of 0- this is because the result at index 0 will be the empty string. Incidentally, this actually does the least significant bit first, so your output list would be 'f', 'n', 'fn', 'u', 'fu', 'nu', 'fnu', but the order didn't seem important.
This is the method I came up with, seems like it's working
private void subsets(String word, ArrayList<String> subset){
if(word.length() == 1){
subset.add(word);
return;
}
else {
String firstChar = word.substring(0,1);
word = word.substring(1);
subsets(word, subset);
int size = subset.size();
for (int i = 0; i < size; i++){
String temp = firstChar + subset.get(i);
subset.add(temp);
}
subset.add(firstChar);
return;
}
}
What I do is check if the word is bigger than one character, otherwise I'll add the character alone to the ArrayList and start the recursive process. If it is bigger, I save the first character and make a recursive call with the rest of the String. What happens is that the whole string gets sliced in characters saved in the recursive stack, until I hit the point where my word has become of length 1, only one character remaining.
When that happens, as I said at the start, the character gets added to the List, now the recursion starts and it looks at the size of the array, in the first iteration is 1, and then with a for loop adds the character saved in the stack for the previous call concatenated with every element in the ArrayList. Then it adds the character on its own and unwinds the recursion again.
I.E., with the word funthis happens:
f saved
List empty
recursive call(un)
-
u saved
List empty
recursive call(n)
-
n.length == 1
List = [n]
return
-
list.size=1
temp = u + list[0]
List = [n, un]
add the character saved in the stack on its own
List = [n, un, u]
return
-
list.size=3
temp = f + list[0]
List = [n, un, u, fn]
temp = f + list[1]
List = [n, un, u, fn, fun]
temp = f + list[2]
List = [n, un, u, fn, fun, fu]
add the character saved in the stack on its own
List = [n, un, u, fn, fun, fu, f]
return
I have been as clear as possible, I hope this clarifies what was my initial problem and how to solve it.
This is working code:
public static void main(String[] args) {
String input = "abcde";
Set<String> returnList = permutations(input);
System.out.println(returnList);
}
private static Set<String> permutations(String input) {
if (input.length() == 1) {
Set<String> a = new TreeSet<>();
a.add(input);
return a;
}
Set<String> returnSet = new TreeSet<>();
for (int i = 0; i < input.length(); i++) {
String prefix = input.substring(i, i + 1);
Set<String> permutations = permutations(input.substring(i + 1));
returnSet.add(prefix);
returnSet.addAll(permutations);
Iterator<String> it = permutations.iterator();
while (it.hasNext()) {
returnSet.add(prefix + it.next());
}
}
return returnSet;
}

What is the correlation between string length and string substring methods?

I basically had to make a program that returns the number of times that the string "code" appears anywhere in the given string, except we'll accept any letter for the 'd', so "cope" and "cooe" count for my APCS class, I had no problems with the code except for the parameters of the for loop, the i<str.length()-3 in particular. It works fine, but only after I kept subtracting random numbers arbitrarily from the length. I really want to know what the correlation between that and the rest of the code is so it isn't just a guess and check thing for me. I don't want to get in the habit of doing that.
public int countCode(String str) {
int times = 0;
for(int i =0;i<str.length()-3;i++){
if(str.substring(i,i+2).equals("co") && str.substring(i+3,i+4).equals("e"))
times++;
}
return times;
}
The correlation is that the substring has to fit inside the source string. You are calling str.substring(i, i+2). Now let's say that your string is 5 characters long. This means the first index inside the string is 0, and the last one is 4. Now imagine that i is equal to 3.
When you call substring(i, i+2), you are really calling substring(3, 5). The substring method takes a start index and an end index. Your end index turns out to be 5, which is illegal because it's outside of the string the last index of which is 4.
So you should really be checking i < str.length() - searchString.length() + 1 instead of i < str.length() - 3.
Your search pattern is 4 characters long. The last character of the string is at index .length() - 1. Therefore the last index where the pattern can start is 3 characters earlier at .length() - 4. You used a less than comparison with .length - 3. So the last iteration of the loop is at this value. It's correct.
A little sketch can help in cases like this:
| 0 | 1 | 2 | 3 | Pattern
... | L-5 | L-4 | L-3 | L-2 | L-1 | String (L==str.length)
... < L-3 ...| Iterations
This is essentially a regular expression match. Using String#substring is needlessly complicated for this scenario. A better approach is to use Pattern#matcher as follows:
public static int countCode(String s) {
Pattern codepattern = Pattern.compile("co.e");
Matcher codematcher = codepattern.matcher(s);
int count = 0;
while (codematcher.find()) count++;
return count;
}
As you can see, find() will keep finding the regex until the end of the given string. For example, given String s = "This core supports all the code. Everyone comes to the core, for the cool stuff is all coded in here.";, the above method returns 5.
Edit: I realize this is not exactly what you had asked, but I thought this might help you.
Gene is spot on, but consider this regex-based alternative:
int times = str.replaceAll("co[a-z]e", "xxxxx").length() - str.length();
It's all done in one line and you let the regex engine do the heavy lifting.

Can someone explain this code? Permutation code [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I am working on a project. I found this code regarding permutations on the Interwebz. I would like to use it as a basis for writing my own code. However, I don't really understand what is going on in the code. Could anybody lend me a hand and explain what the code is doing exactly?
public void permutations(String prefix, String s) {
int n = s.length();
if (n == 0)
System.out.println(prefix);
else {
for(int i = 0; i < n; i++){
permutations(prefix + s.charAt(i), s.substring(0, i) + s.substring(i+1, n));
}
}
}
The method permutations is taking in a String prefix and a String s as its parameters.
The int type n is being set to the length of the String s. (length of a String being how many characters it contains).
Now we move on to the if-else statements. The if statement is saying, if the length of s is 0, that is, s is a blank String and does not contain any information, then we are simply printing the String prefix instead to the console. The method will then skip over the else part and execute the code after the permutations method.
If the if statement's conditions are not met, we are going to run the else statement is saying, for each character in the String s, we are going to append (add) that character at the end of prefix, so for example, if prefix was originally "hello" and the character was 'U', we would get prefix to be "helloU". After we are finished appending all of the characters in s, we are going to be using the result as the new prefix String.
For the other parameter, the String s, we are going to be taking part of the String, from character 0 (inclusive) to character at position i (exclusive). Please note that the String indexes start at 0 and go up to (The length of the String - 1). We are also taking the part of the String from the character at position i + 1 (inclusive) to the last character in the String s. We are going to use this result as the new s String.
Then we would be calling the method again, and then the method would execute again with the newly defined Strings if the else condition is met. This would continue in a loop until the else condition is not met, at which point the method would stop running and we would move on to the next section of code (if it is present).
p(String prefix, String s) takes 1 character out of s and adds it to prefix and recursively continues until s is empty.
The s.charAt(i), s.substring(0, i) + s.substring(i+1, n) part extracts a character from s.
Assume s = "Magic!" and i = 3 then charAt(i) = 'i', s.substring(0, i) = "Mag" and s.substring(i+1, n) = c!". That spilts Magic! into i and Magc!. Next time in the loop with i = 4 it will result in c + Magi!. Since it does that for every character in s every character will be in the front in one of the recursive steps.
The call hierarchy would look like this
/ p("ab", "c") - "abc"
/- p("a", "bc") x
/ \ p("ac", "b") - "acb"
/
/ / p("ba", "c") - "bac"
p("", "abc") x ---- p("b", "ac") x
\ \ p("bc", "a") - "bca"
\
\ / p("ca", "b") - "cab"
\- p("c", "ab") x
\ p("cb", "a") - "cba"
^-- 1st for loop ^- 2nd for ^- 3rd one prints
permutations(prefix + s.charAt(i), s.substring(0, i) + s.substring(i+1, n));
Actually, this permutation algorithm is using the idea of
Switching current character with ith character.
Suppose we have a string abc. So the permutation of it is:
abc, acb, bac, bca, cab, cba
We can find that the acb is just switching b and c in abc with prefix a. And the bca is just switching c and a in bac with prefix b.
Then we just use the same idea to recursively solve permutation problem.
This is some really confusing code, for two reasons:
The prefix argument: you should call this function with an empty string in the first argument, for example permutations("", "ab") to print all (both) permutations of "ab".
The recursive call with s.substring(0, i) + s.substring(i+1, n) in the second argument: note that java's String.substring(x,y) will not include the y-th character. So this amounts to passing s with the y-th character deleted.
Now think what happens as you step through the for loop: the first argument becomes "" concatenated with "a", i.e. "a", and the second argument becomes s with the first character deleted, i.e. "b". In the next recursive subcall, prefix becomes "ab" and the second argument becomes the empty string "". So the base-case n == 0 gets hit and we print the result "ab".
Now we go to the next iteration of the for loop, i == 1. Now we pass "b" in the first argument of our recursive subcall, and "a" in the second argument. In the next recursive subcall prefix becomes "ba" and s.length is 0, so base case again: print "ba".
It's clever, but inscrutable.

Subsequence of a string

I have to write a program that takes string argument s and integer argument k and prints out all subsequences of s of length k. For example if I have
subSequence("abcd", 3);
the output should be
abc abd acd bcd
I would like guidance. No code, please!
Thanks in advance.
Update:
I was thinking to use this pseudocode:
Start with an empty string
Append the first letter to the string
Append the second letter
Append the third letter
Print the so-far build substring - base case
Return the second letter
Append the fourth letter
Print the substring - base case
Return the first letter
Append the third letter
Append the fourth letter
Print the substring - base case
Return third letter
Append the second letter
Append the third letter
Append the fourth letter
Print the substring - base case
Return the third letter
Return the second letter
Append the third letter
Append the fourth letter
Return third letter
Return fourth letter
Return third letter
Return second letter
Return first letter
The different indent means going deeper in the recursive calls.
(In response to Diego Sevilla):
Following your suggestion:
private String SSet = "";
private String subSequence(String s, int substr_length){
if(k == 0){
return SSet;
}
else{
for(int i = 0; i < substr_length; i++){
subString += s.charAt(i);
subSequence(s.substring(i+1), k-1);
}
}
return SSet;
}
}
As you include "recursion" as a tag, I'll try to explain you the strategy for the solution. The recursive function should be a function like that you show:
subSequence(string, substr_length)
that actually returns a Set of (sub)-strings. Note how the problem could be divided in sub-problems that are apt to recursion. Each subSequence(string, substr_length) should:
Start with an empty substring set, that we call SSet.
Do a loop from 0 to the length of the string minus substr_length
In each loop position i, you take string[i] as the beginning character, and call recursively to subSequence(string[i+1..length], substr_length - 1) (here the .. imply an index range into the string, so you have to create the substring using these indices). That recursive call to subSequence will return all the strings of size substr_length -1. You have to prepend to all those substrings the character you selected (in this case string[i]), and add all of them to the SSet set.
Just return the constructed SSet. This one will contain all the substrings.
Of course, this process is highly optimizable (for example using dynamic programming storing all the substrings of length i), but you get the idea.
So, I see you want to implement a method: subSequence(s, n): Which returns a collection of all character character combinations from s of length n, such that ordering is preserved.
In the spirit of your desire to not provide you with code, I assume you would prefer no pseudo-code either. So, I will explain my suggested approach in a narrative fashion, leaving the translation to procedural code as an exercise-to-the-reader(TM).
Think of this problem where you are obtaining all combinations of character positions, which could be represented as an array of bits (a.k.a. flags). So where s="abcd" and n=3 (as in your example), all combinations could be represented as follows:
1110 = abc
1101 = abd
1011 = acd
0111 = bcd
Note, that we start with a bit-field where all characters are turned "on" and then shift the "off" bit over by 1. Things get interesting in an example where n < length(s) - 1. For example, say s="abcd" and n=2. Then we have:
1100 = ab
1001 = ad
1010 = ac
0110 = bc
0101 = bd
0011 = cd
The recursion comes into play when you analyze a sub set of the bit-fields. Hence, a recursive call would reduce the size of the bit-field and "bottom-out" where you have three flags:
100
010
001
The bulk of the work is a recursive approach to find all of the bit-fields. Once you have them, the positions of each bit can be used as an index in the the array of characters (that is s).
This should be sufficient to get you started on some pseudo-code!
The problem is precisely this:
Given an ordered set S : {C0, C1, C2, ..., Cn}, derive all ordered subsets S', where each member of S' is a member of S, and relative order of {S':Cj, S':Cj+1} is equivalent to relative order {S:Ci, S:Ci+d} where S':Cj = S:Ci and S':Cj+1 = S:Ci+d. |S|>=|S'|.
Assume/assert size of set S, |S| is >= the size of the subset, |S'|
If |S| - |S'| = d, then you know each of the subsets S' begins with digit at Si, where 0 < i < d.
e.g given S:{a, b, d, c} and |S'| = 3
d = 1
S' sets begin with 'a' (S:0), and 'b' (S:1).
So we see the problem is actually to solve d lexically ordered permutations of length 3 of subsets of S.
#d=0: get l.o.permutations of length 3 for {a, b, c, d}
#d=1: get l.o.permutations of length 3 for {b, c, d}
#d=2: d > |S|-|S'|. STOP.
string subSeqString() {
string s1="hackerrank";
string s="hhaacckkekraraannk";
int k=0,c=0;
int size=s1.size();
for(int i=0;i<size;i++)
{
for(int j=k;j<s.size();j++)
{
if(s1[i]==s[j])
{
c++;
k++;
break;
}
k++;
}
}
if(c==size)
return "YES";
else
return "NO";
}

Categories