Scramble a Word using Java - java

I wanted to scramble a String, to make it unreadable and so came up with this method:
public String scrambleWord(String start_word){
char[] wordarray = start_word.toCharArray();
char[] dummywordarray = start_word.toCharArray();
Random random = new Random();
int r = random.nextInt(wordarray.length-1);
int i = 0;
int j = r+1;
while(i <= r){
dummywordarray[wordarray.length -i-1] = wordarray[i];
i++;
}
while (j <= wordarray.length -1){
dummywordarray[j-r-1] = wordarray[j];
j++;
}
String newword = String.valueOf(dummywa);
return newword;
SO I first converted the string to a char array, and in my method I had to duplicate the char array "dummywordarray". Passing once through this algorithm every lette rof the word will have changed position. But it wont be scrambled very well, in the sense that you could put it back together at a glance.
SO I passed a given String of less than 9 characters through the method 7 times, and the words are fairly well scrambled, i.e. unreadable.
But I tried it with a 30 character string and it took 500 passes before I could guarantee it was nicely scrambled. 500!
I'm sure there is a better algorithm, I'd like some advice on either
a)improving this method
or
b)a better way.

How about
ArrayList<Character> chars = new ArrayList<Character>(word.length());
for ( char c : word.toCharArray() ) {
chars.add(c);
}
Collections.shuffle(chars);
char[] shuffled = new char[chars.size()];
for ( int i = 0; i < shuffled.length; i++ ) {
shuffled[i] = chars.get(i);
}
String shuffledWord = new String(shuffled);
In other words, you could take advantage of the existing java.util.Collections.shuffle(List) method. Unfortunately you have to jump through a couple of hoops to use it, since you can't use primitives in Generics.
Edit:
The basic way that shuffle works (see the Javadoc for the full explanation), is like this:
for position = last_index to first_index
let swap_pos = random number between first_index and position, inclusive
swap(swap_pos, position)
Edit 2:
This approach is significantly less verbose with Guava's Chars utilities:
List<Character> chars = Chars.asList(word.toCharArray());
Collections.shuffle(chars);
String shuffledWord = new String(Chars.toArray(chars));

Related

Is there a way to initialize a 2d array with other arrays?

I have been given a homework assignment as follows:
Read three sentences from the console application. Each sentence should not exceed 80 characters. Then, copy each character in each input sentence in a [3 x 80] character array.
The first sentence should be loaded into the first row in the reverse order of characters – for example, “mary had a little lamb” should be loaded into the array as “bmal elttil a dah yram”.
The second sentence should be loaded into the second row in the reverse order of words – for example, “mary had a little lamb” should be loaded into the array as “lamb little a had mary”.
The third sentence should be loaded into the third row where if the index of the array is divisible by 5, then the corresponding character is replaced by the letter ‘z’ – for example, “mary had a little lamb” should be loaded into the array as “mary zad azlittze lazb” – that is, characters in index
positions 5, 10, 15, and 20 were replaced by ‘z’. Note that an empty space is also a character, and that the index starts from position 0.
Now print the contents of the character array on the console.
The methods, return types, and parameters in the code below are all specified as required so I cannot change any of that information. I am having trouble initializing the 2d array. The instructions say that the sentences must be loaded into the array already reversed etc. but the parameters of the methods for doing this calls for strings. I assume that means I should read the lines as strings and then call the methods to modify them, then use toCharyArray to convert them before loading them into the 2d array. I don't understand how to initialize the 2D array with the values of the char arrays. Is there some kind of for loop I can use? Another issue is that no processing can be done inside of the main method but in the instructions there is no method that I can call to fill the array.
import java.util.regex.Pattern;
public class ReversedSentence {
public static String change5thPosition(String s){
char[] chars = s.toCharArray();
for (int i = 5; i < s.length(); i = i + 5) {
chars[i] = 'z';
}
String newString = new String(chars);
return newString;
}
public static String printChar2DArray(char[][] arr){
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 80; y++) {
// just a print so it does not make new lines for every char
System.out.print(arr[x][y]);
}
}
return null;
}
public static String reverseByCharacter(String s){
String reverse = new StringBuffer(s).reverse().toString();
return reverse;
}
public static String reverseByWord(String s){
Pattern pattern = Pattern.compile("\\s"); //splitting the string whenever there
String[] temp = pattern.split(s); // is whitespace and store in temp array.
String result = "";
for (int i = 0; i < temp.length; i++) {
if (i == temp.length - 1)
result = temp[i] + result;
else
result = " " + temp[i] + result;
}
return result;
}
public static String truncateSentence(String s){
if (s==null || s.length() <= 80)
return s;
int space = s.lastIndexOf(' ', 80);
if (space < 0)
return s.substring(0, 80);
return s;
}
public static void main(String[] args) {
String sentence1 = ("No one was available, so I went to the movies alone.");
String sentence2 = "Ever since I started working out, I am so tired.";
String sentence3 = "I have two dogs and they are both equally cute.";
char[][] arr = new char[3][80];
arr[0] = reverseByCharacter(sentence1).toCharArray();
arr[1] = reverseByWord(sentence2).toCharArray();
arr[2] = change5thPosition(sentence3).toCharArray();
printChar2DArray(arr);
}
}
The error I am getting is:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 52 out of bounds for length 52
at ReversedSentence.printChar2DArray(ReversedSentence.java:20)
at ReversedSentence.main(ReversedSentence.java:71)
.enola seivom eht ot tnew I os ,elbaliava saw eno oN
The problem is that in your printChar2DArray method you assume that every array has the length of 80, but that's actually not the case here. In Java, a 2D array is just an array of arrays. So, when you have this: char[][] arr = new char[3][80], you are creating an array of 3 arrays, and each of these arrays has the length of 80 characters. That may seem ok, but in the next lines you reinitialize the 3 arrays with something different entirely.
arr[0] = reverseByCharacter(sentence1).toCharArray();
arr[1] = reverseByWord(sentence2).toCharArray();
arr[2] = change5thPosition(sentence3).toCharArray();
Now none of these arrays has the length of 80. Each of them has the length of the respective string.
You can solve this in 2 ways (depending on how constrained your task actually is).
First, you can copy the string into arrays, instead of assigning the arrays to the results of the toCharArray method. You can achieve this with a simple loop, but I wouldn't recommend this approach, because you will end up with arrays of 80 characters, even if the strings contain less.
String firstSentence = reverseByCharacter(sentence1);
for (int i = 0; i < firstSentence.length(); i++) {
arr[0][i] = firstSentence.charAt(i);
}
Or:
char[] firstSentence = reverseByCharacter(sentence1).toCharArray();
for (int i = 0; i < firstSentence.length; i++) {
arr[0][i] = firstSentence[i];
}
Second, you can drop the assumption of the arrays' lengths in the printChar2DArray method. I recommend this approach, because it makes you code much more flexible. Your printChar2DArray method will then look like this:
public static String printChar2DArray(char[][] arr){
for (int x = 0; x < arr.length; x++) {
for (int y = 0; y < arr[x].length; y++) {
// just a print so it does not make new lines for every char
System.out.print(arr[x][y]);
}
}
return null;
}
You can see that I've substituted numbers with the length field, which can be accessed for any array.
Also, this way you don't need to initialize the inner arrays, because you reinitialize them in the next lines anyway.
char[][] arr = new char[3][];
arr[0] = reverseByCharacter(sentence1).toCharArray();
arr[1] = reverseByWord(sentence2).toCharArray();
arr[2] = change5thPosition(sentence3).toCharArray();
But this approach may not be suitable for your task, because then the sentences could be of any length, and they wouldn't be constained to 80 characters max.
UPDATE - To answer the question in the comment
To print a newline character you can use System.out.println() without parameters. It's better than putting the newline character into the arrays because it's not a logical part of the sentences.
So your for-loop in the printChar2DArray would look like this:
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 80; y++) {
// just a print so it does not make new lines for every char
System.out.print(arr[x][y]);
}
System.out.println();
}

How to Optimise a given problem time complexity?

I have a question which says
Given an input
ababacad
The output should be all the a's should come first together rest characters should follow their sequence as they were originally. i.e.
aaaabbcd
I solved it like below code
String temp="", first="" ;
for(int i=0;i<str.length;i++) {
if(str.charAt(i)!='a')
temp=temp+str.charAt(i);
else
first=first+str.charAt(i);
}
System.out.print(first+temp);
The output matches but it says it is still not optimised. I guess its already order of N complexity. Can it be optimised further.
Optimization here can mean string operations as well as the number of iterations. So, just to be on the safe side, you can implement it using arrays. The time complexity will be O(n) which is the minimum for this problem as you have to check every position for the presence of char 'a'.
String input = "ababacad";
char[] array = input.toCharArray();
char[] modified = new char[array.length];
int a = 0; // index for a
int b = array.length - 1; // index for not a
for (int i = array.length - 1; i >= 0; --i) {
if (array[i] != 'a')
modified[b--] = array[i];
else
modified[a++] = array[i];
}
String output = new String(modified);
System.out.println(output);

Replace entire char array with different char

I'm very new to programming and I've spent some time looking for a way to do this that I can understand. I'm making a hangman game in java, it's all text based, and I've got almost the entire thing done. All I need is to replace a character array that holds the value of a random word to be replaced with dashes. So if the word was "java" I need to change that character array to "----". Since the word is chosen at random from a list, I have to find a way to use the length of the word to apply those dashes, but I'm not sure how.
Any help is appreciated!
A simple way to replace all the characters by '_' would be :
char[] charArray = {'W','O','R','D'};
Arrays.fill(charArray, '_');
I will give you an example based on what you have provided so far with java and ----:
public class Program {
public static void main(String[] args) {
String value = "java";
char[] array = value.toCharArray();
// Convert string to a char array.
for(int i = 0; i < value.length(); i++)
{
array[i] = '-';
}
// Loop over chars in the array.
for (char c : array) {
System.out.print(c);
}
}
}
OK, a few things that may be helpful in solving this task:
If you have a String you can easily get the length of that String like this:
String word = "java";
int lengthOfWord = word.length();
You can easily edit the contents of an array by accessing the individual elements:
char[] array = new char[4];
array[0] = '-';
array[1] = '_';
array[2] = '-';
array[3] = '_';
If you want to do something repeatedly and know how often you want to do that, using a for-loop is often a great idea. And you can use the counter within the loop. So for example:
int sum = 0;
for(int i = 0; i < 10; i++) {
sum += i;
}
So, combine those pieces of information and you can replace every element of that array. :-)

Avoiding duplicates without Sets?

I am in a beginner Java class and I haven't gotten the chance to learn how to avoid duplicated values when storing values inside arrays.
String[] newAlphabet = new String[26];
for(int I = 0; I < newAlphabet.length; I++){
int random = (65 + (int)(Math.random() * ((90 - 65) + 1));
char ascii = (char)random;
String letters = ascii + "";
if(letters != newAlphabet[0] && letters != newAlphabet[1] ... so on and so on until
newAlphabet[25])
newAlphabet[I] = letters;
}//end
So this is my pseudo code for part of my program and the point of it is to avoid having duplicated letters inside the array.
The problem that I am having is inside the if statement. Instead of typing letters != newAlphabet[] to 25, is there another way of doing it?
I have seen some of the forums in stackedoverflow that I should use HashSet but I have not learned that? I can ask my teacher if I am allowed but is there another way to avoid this problem?
I have been thinking of using for-each loop to search through all the elements in the array but I haven't thought out the plan long enough if it's valid.
As you are talking about a beginner Java class, I am assuming you are fairly new to programming. So, rather than just give you a library function that will do it for you, let's walk through the steps of how to do this with just the basic code so you can get a better idea of what is going on behind the scenes.
Firstly, for any repetitive action, think loops. You want to check, for each letter in your new alphabet, if the one you are about to add matches it. So...
boolean exists = false; //indicates whether we have found a match
for (int j = 0; j < 26; j++) { //for each letter in the new alphabet
//true if this one, or a previous one is a match
exists = exists || letters == newAlphabet[i];
}
//if we don't have a match, add the new letter
if (!exists) newAlphabet[I] = letters;
Now, as you are building up your new alphabet as we go, we don't have a full 26 letters for most cases of running this code, so only check the parts of the new alphabet we have defined:
boolean exists = false;
for (int j = 0; j < I; j++) { //note in this line we stop before the insertion point
exists = exists || letters == newAlphabet[i];
}
if (!exists) newAlphabet[I] = letters;
Finally, we don't need to keep checking if we have already found a match, so we can change the loop to stop when we have found a match:
boolean exists = false;
int j = 0;
while (!exists && j < I) { //we now also stop if we have already found a match
exists = letters == newAlphabet[i];
//as we are stopping at the first match,
//we no longer need to allow for previous matches
}
if (!exists) newAlphabet[I] = letters;
You could use the asList method:
if( Arrays.asList(newAlphabet).contains(letters) ) {
newAlphabet[I] = letters;
}
It's not the most efficient, but since your array is only 26 elements long, I would favor clarity over efficiency.
Some explanation: asList is a static method on the Arrays class. This just means that we don't have to create an Arrays object to call it. We simply say Arrays.asList() and pass it the arguments. The asList method takes an array (newAlhpabet in this case) as a parameter, and builds a java.util.List out of it. This means that we can call List methods on the return value. contains() is a method on List that returns true if the List contains an element that is equal to the parameter (letters in this case).
Based on this line it looks like all you're trying to do is produce the letters A to Z in some other order:
int random = (65 + (int)(Math.random() * ((90 - 65) + 1));
If I'm understanding that right, then really all you're trying to do is shuffle the alphabet:
// Initialize new alphabet array
String originalAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char[] newAlphabet = originalAlphabet.toCharArray();
// Shuffle the new alphabet by swapping each character to a random position
for (int i=0; i<26; i++) {
int j = (int)(Math.random() * 26);
char temp = newAlphabet[i];
newAlphabet[i] = newAlphabet[j];
newAlphabet[j] = temp;
}
// Print the new alphabet
for (int i=0; i<26; i++) {
System.out.print(newAlphabet[i]);
}
System.out.println();
Here's a sample output: VYMTBIPWHKZNGUCDLRAQFSOEJX
You have a couple options.
Loop through the array and do basically what you're doing now.
Insert the characters in sorted order so you can perform binary search to determine if a letter is already in the list. As a bonus, if you use option 2, you'll already know the insertion point.
Check out Arrays.binarySearch(): http://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html
You could use this :
if(Arrays.binarySearch(newAlphabet, letters) < 0){
newAlphabet[I] = letters;
}
You should either include a while loop to make sure each index of the array is filled before moving to the next or you could make use of the return value of Arrays.binarySearch which is (-(insertion index) - 1) to fill the array and exit when the array is filled up.

Replacing characters in Strings Java [duplicate]

This question already has an answer here:
String Replace not working as I think it should [duplicate]
(1 answer)
Closed 8 years ago.
I need to cycle through each character in a string, and based on the character that it is, replace it with another character from a char array.
Basically it looks like this:
for (int k = 0; k < messageToBeEncrypted.length(); k++)
{
switch(messageToBeEncrypted.charAt(k))
{
case 'a' : messageToBeEncrypted.replace('a', cryptList[0]);
break;
case 'b' : messageToBeEncrypted.replace('b', cryptList[1]);
break;
//it keeps going for each letter of the alphabet
}
System.out.println(messageToBeEncrypted);
}
The char array cryptList is a randomly generated alphabet, "fgtaixnebqwjkzumlydrovsphc" A is to be replaced by f, b by g, and so on. The problem I'm having is that this code prints the exact same message that was inputted, so if the messageToBeEncrypted was ab, instead of fg, it prints ab. How can I fix this? And if theres a clearer more concise way to accomplish this, do tell me. I realize 26 case statements probably isn't the best way to achieve my goal.
If you want to google it the keyword is Substitution cipher.
Here a short help:
String messageToBeEncrypted = "HelloWorld".toLowerCase();
String alphabet = "fgtaixnebqwjkzumlydrovsphcab";
StringBuilder sb = new StringBuilder();
int pos;
for (int k = 0; k < messageToBeEncrypted.length(); k++)
{
pos = (messageToBeEncrypted.charAt(k) - 97);
sb.append(alphabet.charAt(pos));
}
System.out.println(sb.toString());
The number 97 is the offset in the ASCII table... My example is just for small letters, but its not that hard to complete it for every letter.
This seems about what your after (minus the brutal switch statement):
public static String substitutionCipher(String str) {
//i'm assuming that this random alphabet is exactly 26 long, each unique
char[] crypt = "fgtaixnebqwjkzumlydrovsphc".toCharArray();
char[] chars = str.toCharArray();
for(int i = 0; i < chars.length; i++){
chars[i] = crypt[((int) chars[i]) - 97];
}
return new String(chars);
}
But to answer your original question, the reason it's not working is that Strings are immutable. By calling String.replace, it's not modifying your string; that's actually returning the modified version of the string and then just disappearing since you're not storing the return value.
You'd need to say:
for (int k = 0; k < messageToBeEncrypted.length(); k++)
{
switch(messageToBeEncrypted.charAt(k))
{
case 'a' :
messageToBeEncrypted = messageToBeEncrypted.replace('a', cryptList[0]);
break;
case 'b' :
messageToBeEncrypted = messageToBeEncrypted.replace('b', cryptList[1]);
break;
//etc.
}
System.out.println(messageToBeEncrypted);
}
but the way I mentioned previously is a little gentler on memory.

Categories

Resources