1

I have been trying different things for a while now and I can't figure out why my logic is wrong. It isn't making sense.

I am trying to make a program based on the following pseudocode.


Translate the following pseudocode for randomly permuting the characters in a string into a Java program.

  1. Read a word.
  2. Repeat the loop word.length() times
  3. Pick a random position i in the word, but not the last position.
  4. Pick a random position j > i in the word.
  5. Swap the letters at positions j and i.
  6. Print the word.
  7. Then replace the string with: first + word.charAt(j) + middle + word.charAt(i) + last

This is what I have so far:

package assignment4;

import java.util.Scanner;

public class P4Point7 {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);

        System.out.print("Please enter a word: ");
        String word = in.next();
        in.close();

        int wordLength = word.length(); // Gets the word.Length
        int x = 1; // Primes the loop

        while (x <= wordLength) {
            int i = (int) ((Math.random() * wordLength) - 1); // Gets a random letter i that is not the last letter
            int j = (int) (Math.random() * (wordLength - i)) + i; // Gets a random letter j after i 
            String first = word.substring(0, i); // Gets first part of word
            String middle = word.substring(i + 1, j); // Gets middle part of word
            String last = word.substring(j + 1, wordLength); // Gets last part of word
            x++; // Increments the loop
            String status = first + word.charAt(j) + middle + word.charAt(i) + last; // Swaps i and j in the word
            System.out.println(status);
        }   
    }
}

The problem I am having is

Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: -1
at java.lang.String.substring(Unknown Source)
at assignment4.P4Point7.main(P4Point7.java:21)

I am testing the program with the word "Waffle".

2
  • I added the problem to the post SLaks Commented Oct 13, 2013 at 23:03
  • I will still be posting the solution the teacher has at a later time. I will update this post with a new comment. :) Commented Oct 13, 2013 at 23:41

6 Answers 6

1
  i = (int) ((Math.random() * wordLength) - 1); 
  j = (int) (Math.random() * (wordLength - i)) + i; //  

In this two line, there are case (int) (Math.random() * (wordLength - i)) will result in 0 and i == j. If so then, the following line of code:

String middle = word.substring(i+1, j); 
          // if i==j, then  i+1 > j which will result in index exception.
  1. Debug your code with a debugger step by step thoroughly to find the BUG.
  2. use Random class which has a nice function random.nextInt(n) to return a random integer between 0 (inclusive) and the specified value (exclusive).
Sign up to request clarification or add additional context in comments.

2 Comments

I did that fora bout 30 minutes before I decided to post the question on here. I have tried many different things with no success.
read the code comment i mentioned above and check what i have said is happening or not!
1

A Couple of suggestions:

Using a Random Object to generate your random index may simplify the index generation. Math.random() returns a double between 0.0 and 1.0. Multiplying this by wordlength is not guaranteed to return a random number in the range 0 to wordlength - 1;

Random indexGen = new Random();
int i = indexGen.nextInt(wordlength -1);
int j = indexGen.nextInt(wordlength -1 - i) + i;

Also the way I read the pseudocode is that you want to just swap the character at i with the character at j so you could do this

char[] charArray = yourWord.toCharArray()
char temp = charArray[i];
charArray[i] = charArray[j];
charArray[j] = temp;
String finalWord = new String(charArray);

Edit using substring

Firstly fix your logic so that your index is always correct and ensure that 0 <= i < j <= wordlength. Put that into an if statement then you will know if indices are wrong

if( 0 <= i && i < j && j <=wordlength)
{
     String first = word.substring(0, i);
     String middle = word.substring(i+1, j);
     String last = word.substring(j+1, wordLength);
     //... etc
}
else
     System.out.println("There was an indexing error: i = " + i + ", j = " + j);

Edit for index

int i = (int) ((Math.random() * wordLength) - 1)
if ( i < 0)
    i = 0;

Then same for j but checking j > i. Another alternative would be to use Math.abs() like so

int i = Math.abs((int) ((Math.random() * wordLength) - 1))

4 Comments

I understand that these methods are the solution to what I am trying to do but I am only allowed to use methods in class that I know. I just can't figure how to do it with what we are supposed to know. We have not learned arrays yet. Could you explain the index.Gen part. Thanks. As far as the Math.random function goes. I thought that since I cast (int) type on it that it will always give me a value 0 to wordLength.
It will always give you an Int that for sure but consider this Math.random() gives you 0.0001. You multiply this by wordlength and cast as int, this gives you 0, you then substract 1 giving oyu index of -1. This is the source of your error. The above will ensure that doesnt happen as Random.nextInt(n) returns a number between 0(inclusive) and n(exclusive)
Do you feel that it is impossible to do with the Math.random function? I am going to e-mail the teacher about the problem because he has the solution manual to our textbook. (Which this problem comes from). I will update the post tomorrow with the solution he has. (If he will allow me to see it before the due date.)
You can do it with Math.random you will will just have to do extra checking, see my edit
0

It seems to me that your i and j can be positions outside the string size. Try changing the way you get the random positions.

Give a try to:

Random rand = new Random();
int i = rand.nextInt(wordLength - 1); // This will return you a random position between 0 and wordLength -2
int j = rand.nextInt(wordLength - i) + i; // This should give you a position after or equals i.

Comments

0

Like Sage and Java Devil said above, lines 18-19 are causing your problem, but since you're using Math.random(), it's going to be difficult to reproduce your problem in a debugger - you're creating something that's by nature indeterministic. Since you're looking for random, though, the key is to ensure that

  1. i >= 0, and
  2. j > i (or i+1, depending on the exact results you'd like).

This exercise seems to be exploring the Math library, so I'd suggest looking into some of its other methods for ensuring that i and j always have acceptable values (say, Math.min() and Math.max()).

3 Comments

I replied to this before you updated your post in my last reply. Math.min and Math.max will most likely work. I will try and incorporate it.
If you can't use the fancy methods, you can always use simple conditionals: if (i<0) { /* fix it */ } and if (j<=i) { /* fix it */}...
I know using if and else is allowed in the assignment so that is probably what it wants me to do. The solution probably includes the cases that would solve my errors. That would make sense because everything is compiling as we go throughout the book.
0

This was the solution.

import java.util.Scanner;

public class PermuteCharacters
{
   public static void main(String[] args)
 {
       Scanner in = new Scanner(System.in);

  System.out.println("Enter a word to permute: ");

  String word = in.next();
  for (int n = 0; n < word.length(); n++)
  {
     /** 
        The -1 here guarantees that later we won't pick a j that goes off
        the end of the string. This is important since since the 
        pseudocode tells us to pick a j > i
     */
     int i = (int) (Math.random() * word.length() - 1);
     int j = (int) (Math.random() * (word.length() - i - 1)) + i + 1;

     String first = word.substring(0, i);
     String middle = word.substring(i + 1, j);
     String last = word.substring(j + 1);

     word = first + word.charAt(j) + middle + word.charAt(i) + last;
  }

  System.out.println("Your permuted word is: " + word);
   }
}

Comments

0

It worked for me with this code:

import java.util.Random;

public class Word
{
   private Random generator = new Random();
   public Word() 
   {
        generator = new Random();
        final long SEED = 42;
        generator.setSeed(SEED);
   }

   public String scramble(String word)
   {     
    int lenWord = word.length();      
    for (int l = 0; l < lenWord; l++)
    {
        int i = generator.nextInt(lenWord - 1);    
        int j = i + 1 + generator.nextInt(lenWord - i - 1);

        String letterI = word.substring(i, i + 1);
        String letterJ = word.substring(j, j + 1);

        String FIRST = word.substring(0, i);
        String MIDDLE = word.substring(i + 1, j);;
        String LAST = word.substring(j + 1, lenWord);

        word = FIRST + letterJ + MIDDLE + letterI + LAST;
    }
    return word;
}
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.