Problem in Understanding Recursion - Java - java

I got the code from this question, I ran it in Eclipse and the code was fine, but I confused myself in how the recursion order goes internally.
public class Permute {
public static void main(String[] args) throws IOException {
System.out.println("Enter a string");
BufferedReader bufReader = new BufferedReader(new InputStreamReader(
System.in));
String text = bufReader.readLine();
shuffle("", text);
}
public static void shuffle(String dummy, String input) {
if (input.length() <= 1)
System.out.println(dummy + input);
else {
for (int i = 0; i < input.length(); i++) {
input = input.substring(i, i + 1) + input.substring(0, i)
+ input.substring(i + 1);
shuffle(dummy + input.substring(0, 1), input.substring(1));
}
}
}
}
I found difficulty in understanding recursion in the for loop of Shuffle. Any pointers in decoding the recursion steps?
EDIT : Okay this is my understanding, say suppose my input is ABC and when i run in the first loop , i get dummy = A and input = BC, so the immediate step would be to go down the recursion for input = BC and dummy = A and then come back to iterate i for the initial input ?

Add a global counter:
static int depth = 0; /* calling depth of the recursive method */
Add as the first line of shuffle:
System.out.printf("%" + depth++ + "s call dummy='%s' input='%s'\n", "", dummy, input);
Add as the last line of shuffle:
System.out.printf("%" + --depth + "s return\n", "");
Run the program. Now you can see what happens.

Think of it as dividing the job in steps. Your shuffle function takes two arguments, dummy for the part of the string that is already shuffled, and input for the part of the string that still has to be shuffled.
At every step, you shuffle the first character of input:
for (int i = 0; i < input.length(); i++) {
input = input.substring(i, i + 1) + input.substring(0, i)
+ input.substring(i + 1);
and then, recursively apply the algorhythm, with the part already shuffled being a character longer:
shuffle(dummy + input.substring(0, 1), input.substring(1));
Until there is nothing more to shuffle:
if (input.length() <= 1)
System.out.println(dummy + input);

It exhaustively shuffles the input by the inputs length, recursively. So once each recursion has shuffled the string by the i'th term, it returns.
This would be an n-squared complexity algorithm in big-O notation.
The shuffling is tricky to work out without a debugger ;)

Related

Java code for Permutation (all possible combination of letters) of a String, explanation? [duplicate]

I have this working code to print string permutations without repetitions, but not able to wrap my head around how is it working as in logic. Any suggestions will be really helpful.
private static void permutation(String input, String sofar) {
if (input.equals("")) {
System.out.println(count + " " + sofar);
count++;
}
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if (input.indexOf(c, i + 1) != -1)
continue;
permutation(input.substring(0, i) + input.substring(i + 1), sofar+c);
}
}
Function call:
String input = "ABBCD";
permutation(input, "");
for (int i = 0; i < input.length(); i++) {
The above for loop is doing the magic
Input ABCD
Iterations
input: BCD sofar: A .... recursion goes on
input: ACD sofar: B ....
input: ABD sofar: C ....
input: ABC sofar: D .....
Hope this helps
Just remember that recursion is usually a stop condition, and an attempt to solve a smaller problem using the recursive call, under the assumption that the recursion works.
I've commented the code so you can replace that with your copy to keep track of what it's doing when you get back to it. Add your own comments once you understand as they'll help you follow what happens:
Part 1: The basic condition / stop condition:
if (input.equals("")) {
System.out.println(count + " " + sofar);
count++;
}
This part stops the recursion and returns a result, the base case being an empty string, which has a single permutation that is also an empty string.
Part 2: Iterating smaller problems.
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
// ...
permutation(input.substring(0, i) + input.substring(i + 1), sofar+c);
}
This part uses the recursive call on a smaller (by one character) string, to solve the problem. It calls the same string omitting a character it prepends to whatever following results it generates. We know the call generates all permutations (that's our assumption). So we now know what the recursion does.
Part 2.1: The de-duplicating "if":
This is probably the trickiest part here...
if (input.indexOf(c, i + 1) != -1)
continue;
Let's figure this out. What it means, is: "try and find a character the same as the one selected, and if one exists, skip this iteration and it's generated solutions".
Think of a word like "ABBA" it will skip the first "A" and "B", but not the last ones. Why? Well, since order of similar characters does not matter (if we tag the character A1 B1 B2 A2, and now replace them: A2 B2 B1 A1, this is still the same word, so there is only one permutation for words like "AA", since A1 A2 is the same as A2 A1.
Taking the last characters is easier, since we don't need to maintain a list of the characters we already used in this iteration.
The full code with basic comments:
private static void permutation(String input, String sofar) {
if (input.equals("")) {
// this is the stop condition
// the only permutation of "" is ""
System.out.println(count + " " + sofar);
// this counts how many permutations were outputted.
count++;
}
for (int i = 0; i < input.length(); i++) {
// this loop basically means "take every
// possible character, and append permutations of all
// other characters to it.
char c = input.charAt(i);
if (input.indexOf(c, i + 1) != -1)
// this makes sure we only take a single "A" or "B"
// character in words like "ABBA", since selecting
// the same character would create duplicates
continue;
// this creates a new string without the selected character
// and under the assumption the recursion works
// appends all permutations of all other characters
// to it
permutation(input.substring(0, i) + input.substring(i + 1), sofar+c);
}
}
if (input.equals("")) {
System.out.println(count + " " + sofar);
count++;
}
This step is passed as the input is not "". Note that you could simply use input.empty() here. The only thing to remember here is that count have not been incremented.
for (int i = 0; i < input.length(); i++) {
This will, loop over all character of the input
char c = input.charAt(i);
if (input.indexOf(c, i + 1) != -1)
This check if the next character is equal to the current one, if it does then it will jump directly to the next iteration(the next character) using the continue keyword.
If it does not, then it will recall the method (We call that recursivity), passing in the string without the current char. But giving it back to sofar.
permutation(input.substring(0, i) + input.substring(i + 1), sofar+c);
Now in the case where input is empty,
The count of non-distinct character will be printed + all these character.

Printing text with spacing recursively

This is an assignment for school. I am having trouble understanding how I can print the following recursively:
This was written by call number 2.
This was written by call number 3.
This was written by call number 4.
This ALSO written by call number 4.
This ALSO written by call number 3.
This ALSO written by call number 2.
This ALSO written by call number 1.
I'm not sure if I am supposed to be illustrating a loop vs. recursion or if there is a way to print all of this recursively. Additionally, how would I go about reversing the recursion call so it starts from 4 as per the example output?
This is my current output.
This was written by call number 2.
This was written by call number 3.
This was written by call number 4.
This ALSO written by call number 1.
This ALSO written by call number 2.
This ALSO written by call number 3.
This ALSO written by call number 4.
There is no spacing implemented in the for loop yet b/c I'm not sure if that part is also supposed to be recursive.
My code:
public class Recursion {
public static void main(String[] args) {
for (int i = 2; i < 5; i++) {
System.out.println("This was written by call number " + i + ".");
}
recurse(4);
}
public static void recurse(int n) {
String temp = "";
for (int i = 0; i < n; i++) {
temp += " ";
}
if (n < 2) {
System.out.println("This ALSO written by call number " + n + ".");
}
else {
recurse(n - 1);
System.out.println(temp + "This ALSO written by call number " + n + ".");
}
}
A simpler solution.
public static void main(String[] args) {
recurse(1);
}
public static void recurse (int n) {
if (n==5) return;
String temp="";
for (int i=0;i<n;i++) temp += " ";
if (n!=1) {
System.out.println(temp + "This was written by call number " + n + ".");
}
recurse(n+1);
temp=" ";
for (int i=0;i<n;i++) temp += " ";
System.out.println(temp + "This ALSO was written by call number " + n + ".");
}
The key to writing most recursive programs (especially the ones you're given as assignments) is to look for a larger problem that contains a similar but smaller occurrence of the same problem.
In your case, the "larger problem" would be to print the 6 lines that start and end with "call number 2". That is, print lines for call numbers 2 through 4. The way to do this is: print the first line that says "call number 2", solve the problem to print the 4 lines for call numbers 3 through 4, and print the last line that says "call number 2". The part in the middle is the smaller occurrence of the same problem. That's going to be the recursive call.
Since your larger problem is going to start with "call number 2", and your smaller problem is going to start with the call number that's one higher, I'd recommend arranging things so that you call recurse(n+1) instead of recurse(n-1). If you do that, you'll need a second parameter so that you know when to stop recursing--something like recurse(n+1, last).
Hopefully this will be enough to get you thinking on the right track.
Try this:
public static void main(String[] args) {
recurse(1, true, 1);
}
public static void recurse(int n, boolean loop, int add) {
String temp = "";
String out = "";
for (int i = 0; i < n; i++) {
temp += " ";
}
if (add > 0) {
out = temp + "This was written by call number ";
} else {
out = temp + "This ALSO written by call number ";
}
if (n == 1 && !loop) {
System.out.println(out + n + ".");
return;
} else if (n == 1) {
recurse(n+add, false, add);
} else if (n == 5) {
add = add - 2 * add;
recurse(n+add, false, add);
} else {
System.out.println(out + n + ".");
recurse(n+add, false, add);
}
}
Here is quite a straightforward solution. Also pay attention how you can easily get the indent string (via substring). The recursion is as simple as it gets: print the number, enter the function with a larger number if below the max, then follow back.
class R{
static final String spaces=" ";
public static void main(String[] args) {
rec3(1,4);
}
private static void rec3(int i, int max) {
if (i>1) System.out.printf("%sThis was written by call number: %d%n", spaces.substring(0, i-1), i);
if (i<max) rec3(i+1, max);
System.out.printf("%sThis was ALSO written by call number: %d%n", spaces.substring(0, i-1), i);
}
}
Thanks to everyone for the help. I ended up modifying the solution from #JoseLuis a little bit.
public class Recursion {
public static void main(String[] args) {
recurse(1, 5);
}
public static void recurse(int n, int max) {
String temp = "";
for (int i = 0; i < n; i++) {
temp += " ";
}
if (n == max) {
return;
}
if (n != 1) {
System.out.println(temp + "This was written by call number " + n + ".");
}
recurse(n + 1, max);
System.out.println(temp + "This ALSO was written by call number " + n + ".");
}
}

Stuck on Mean word length

The goal of this code was to create a program using main method java to analysis a piece text which has been entered from a user.
They do this by entering the text into a scanner which is then analysed by the program. The analysis is to produce word frequency, for example " This is a test" produces this results:
This is a test
1 letter words: 1
2 letter words: 1
3 letter words: 0
4 letter words: 2
5 letter words: 0
The bit that I'm stuck on is producing a mean/average, My guts telling to divide
counts.length by str.length but I'm not the Best at java and I've tried to implement this but all I get are errors. I'm not expecting anyone to just hand me code, but if someone could give me a hint in what I should do or just point me the right direction it would be greatly appreciated.
Code:
import java.util.Scanner;
public class Text_AD {
public static void main (String[] args) {
while(true){
Scanner input = new Scanner(System.in);
System.out.println("Enter text: ");
String s;
s = input.nextLine();
System.out.println("" + s);
String[] strings = s.split(" ");
int[] counts = new int[6];
for(String str : strings)
if(str.length() < counts.length) counts[str.length()] += 1;
for(int i = 1; i < counts.length; i++)
System.out.println(i + " letter words: " + counts[i]);
}}}
By average, I am assuming that you mean the mean length. I am also assuming you want to get a floating point mean. In which case you just need to divide the total of all the lengths in strings by the length of the array itself.
You could do something like the following;
int total = 0;
for(String s : strings) total += s.length();
System.out.println((double)total/strings.length);
I hope this helps.
Without breaking up your code much, you could run a for loop through your counts[] array, adding up all the values, and then dividing by counts.length to get the average.
Be aware of type casting though. You may want to do Double division instead of integer.
It this what you are looking for?
import java.util.Scanner;
public class While_Loop {
public static void main (String[] args) {
int lengthSum, wordCount;
lengthSum = wordCount = 0;
while(true){
Scanner input = new Scanner(System.in);
System.out.println("Enter text: ");
String s;
s = input.nextLine();
System.out.println("" + s);
String[] strings = s.split(" ");
int[] counts = new int[6];
for(String str : strings)
if(str.length() < counts.length) counts[str.length()] += 1;
wordCount++;
lengthSum += str.length();
for(int i = 1; i < counts.length; i++)
System.out.println(i + " letter words: " + counts[i]);
System.out.println("Average: " + lengthSum/wordCount);
}}}
NOTE: I only added stuff to your code. The way it is written is pretty messy. I'd clean up some of the for loops and the brackets at the end for practice making the code more readable.
When I understand you correct you should have one variable int totalCount = 0; where you add
totalCount += i*counts[i]; in your last for loop.
After the loop you can simply divide through the size-1 (because 0 does not count)
double average = totalCount/(counts.length-1);
Alternative way
You take the inputstring length without the spaces and divide it by the number of spaces + 1 (which is equal to the number of words)
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
System.out.println("Enter text: ");
String s = "This is a sample text";
System.out.println("" + s);
String[] strings = s.split(" ");
for(String str : strings) {
Integer counter = map.get(str.length())==null?0:map.get(str.length());
map.put(str.length(),counter++);
}
Integer sum=0;
Integer counter=0;
for(Integer len : map.keySet()) {
sum+=len*map.get(len);
counter+=map.get(len);
}
Double average = Double.valueOf(sum/counter);
Or you can combine the loops
Few suggestions which might help you (not related to the specific question).
Choose a meaningful class name rather than While_Loop .
Do, Scanner input = new Scanner(System.in); before the start of the loop.
As soon as you read each line, do the following.
Split the line using "\\s+" .
Create a HashMap with Key as Count (Integer) and Value as a list of Words with that count. Create this outside the loop.
For each split word,,get the length . and check if the map already contains the count, get the list (value), add he current word to it. else, add a new entry with the word as the single entry in the list.
Get the keySet of the map, add values of all keys i.e, *count * number of elements in the list*. then divide by total number of elements.
And yes, I know this is a very big change (something you might as well ignore..). But this is the right way to go.

Odd and Even Numbers [duplicate]

This question already has an answer here:
Odds and Evens Applications
(1 answer)
Closed 8 years ago.
How can I display all the evens on one line and all the odds on the next line? need to display 25 integers.
public class OddsOrEvens
{
public static void main(String[] args)
{
int[] numbers = new int[25];
System.out.print ("EVENS & ODDS");
for(int i=0; i < 25; i++)
{
numbers [i] = (int) (Math.random()*99) + 1;
if(numbers[i]%2 == 0)
System.out.println(numbers[i] +" " );
else
System.out.println(numbers[i] +" " );
}
}
}
Instead of printing each number immediately, consider building up two strings (the first made up of the evens, and the second the odds). Then print the result strings when you're done. This should require just one loop.
In your providing code you print every number at time when it processed.if you want to print in one line so one possible solution is that you have store numbers in some array, or a string instead of display the number.
So in your code this line must change
System.out.println(numbers[i] +" ");
like this (if you want to store them in string variable)
even += numbers[i] +" ";
and later when loops end you can print out both line one by one.
Hope this will help you
//Snippet
if(numbers[i]%2 == 0)
even += numbers[i] +" ";
else
odd += numbers[i] +" ";
//after loops ends
System.out.println(even);
System.out.println(odd);
Just save all the evens in one array and all the odds in another and then print them seperately.
Well right now you are printing them all individually. what you could do is before the for loop declare a String for the odds and a String for the evens. and initialize them to "". then in the for loop instead of printing, just add the numbers[i] to the string and print them outside of the for loop
Alternatively ...
Read the javadoc for PrintStream, 'cos System.out is a PrintStream. Look at the different print methods available.
Create a string to hold them and just display them at once at the end:
public class OddsOrEvens
{
public static void main(String[] args)
{
int[] numbers = new int[25];
String evens = "";
String odds = "";
System.out.print ("EVENS & ODDS");
for(int i = 0; i < 25; i++)
{
numbers [i] = (int) (Math.random() * 99) + 1;
if(numbers[i] % 2 == 0)
evens += numbers[i] + " "; // save it to evens string
else
odds += numbers[i] + " "; // save it to odds string
}
// now print them
System.out.println("Evens: " + evens);
System.out.println("Odds: " + odds);
}
}

Slicing a string

I'm trying to slice a string for the first time.
With this code, if I input, for example 'one two three' it works fine until the last word.
This is the last few lines of the output:
Current word is thr
Sentence is now e
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 3
at java.lang.String.substring(String.java:1907)
at TestCurr.main(testCurrentWord.java:18)
Has anyone any idea why it does that to the last word?
class TestCurr
{
public static void main (String []args)
{
String s;
int i;
String currentWord;
int length;
int spacePos;
System.out.println("Enter a sentence ");
s = EasyIn.getString();
spacePos = s.indexOf(" ");
length = s.length();
for (i = length -1; i >= 0; i--)
{
currentWord = s.substring(0,spacePos);
s = s.substring(spacePos +1);
System.out.println("Current word is " + currentWord);
System.out.println("Sentence is now " + s);
}
}
}
First of all, you call
spacePos = s.indexOf(" ");
length = s.length();
only once, but these values should change with each iteration of the loop. Furthermore,
s.substring(spacePos +1);
with
spacePos == s.length()-1
means you are passing an index beyond the end of the string as the start index for substring(). Once you fix the first error, this will be your next exception.
Your problem is that you only get the index of the space once. This causes the program to cut the string every three characters, as the first word is three letters long. You need to update spacePos after each iteration.
I believe your problem is in your usage of your spacePos variable.
Outside the loop, you initialize the variable like so:
spacePos = s.indexOf(" ");
Which in your example string of "one two three", yields 3.
But then inside your loop, you never set the variable again, based on what whatever is left that you haven't processed.
Try re-calculating spacePos's value inside the loop and your problem should go away.
Your current approach is too error prone.
And you have too many variables.
Try this just as an idea.
class TestCurr {
public static void main(String[] args) {
String s = null;
System.out.println("Enter a sentence: ");
s = " one two three ";
System.out.println("|" + s + "|");
int i = 0;
int j = 0;
while (true){
while (i<s.length() && s.charAt(i)==' ') i++;
j = i;
if (i>=s.length()) break;
while (i<s.length() && s.charAt(i)!=' ') i++;
System.out.println("Current word is: [" + s.substring(j, i)+ "]");
System.out.println("Sentence is now: [" + s.substring(i) + "]");
if (i>=s.length()) break;
}
}
}
As others have stated, you only get the index once. But I'm curious, why re-invent the wheel?
String s = "one two three";
String[] split = s.split(" ");
for (String out : split) {
System.out.println("Word: " + out);
}

Categories