Shuffle a string via swapping content to different index - java

I have an assignment in which we are instructed to create a method which takes a string, scrambles the content of the string, and then returns the scrambled string (ie "Hello" returns "elloH"). However, we are only allowed to do this via loops and basic string functions (no arrays can be used).
My Teacher has left the following suggestion for us:
The best way to shuffle is to generate 2 random numbers (index number) and swap the numbers(the content, not the index) based on the random index numbers.
Continue to do it for 100 times, they are shuffled and all characters remain the same but in different positions
How would this nessasarily be done? For reference here is my try at the solution, however it does not work and I'm not sure where to go from here:
public void shuffle(String s1) {
int i1 = 0;
int i2 = 0;
String s2 = "";
for(int a2 = 0; a2 < s1.length(); a2++) {
char c1 = s1.charAt(i1);
s2 += c1;
for(int a1 = 0; a1 < 100; a1++) {
double d1 = Math.random();
d1 *= (s1.length()-1);
i1 = (int) d1;
}
}
System.out.println(s2);
}

The problem with your code is that you don't swap characters in the String but rather select randomly across the String which causes some characters to be used many times and some not at all.
I would do something like this using StringBuilder that is suitable for String manipulations as long as the String itself is immutable (calling any method from it does not change the former object but returns a new one).
// it's a good practice to delcare formal parameters in a method as final
public void shuffle(final String string) {
// store the string length to a variable for sake of comfort
final int length = string.length();
// use mutable StringBuilder for easy String manipulations
final StringBuilder stringBuilder = new StringBuilder(string);
// initialize the Random object generator once and use many times
// as you don't want to initialize with each loop and throw it away
final Random random = new Random();
// define the number of iterations
// to repeat as many times as the string is long is more than enough
for (int i=0; i<length; i++) {
// pick two random indices to be swapped
final int firstIndex = random.nextInt(length);
final int secondIndex = random.nextInt(length);
// remember the swapped characters
// otherwise it would end up in a mess and duplicated characters
final char firstChar = stringBuilder.charAt(firstIndex);
final char secondChar = stringBuilder.charAt(secondIndex);
// perform the swap: basically set the characters to their positions
stringBuilder.setCharAt(firstIndex, secondChar);
stringBuilder.setCharAt(secondIndex, firstChar);
}
// and see the result
System.out.println(stringBuilder);
}
Run three times (it looks nicely swapped and the characters remain unchanged):
WoodeHl rl!l
Wer lldooHl!
HW! llrloeod

Hi here is the updated code with your requirement I tried not using the concepts out of string manipulation the swap is not using StringBuilder (that would be the best way to do that but if not needed here as a custom logic to do so)
and also used Math.random() to generate the random number if you want to see all 100 iterations just print the s1 in the for loop.
static String swap(String str, int i, int j) {
// if both indexes are the same change nothing
if (i == j)
return str;
// if the second index is last then there will be no substring from j+1 to last;
if (j == str.length() - 1)
return str.substring(0, i) + str.charAt(j) + str.substring(1 + i, j) + str.charAt(i);
return str.substring(0, i) + str.charAt(j) + str.substring(1 + i, j) + str.charAt(i)
+ str.substring(j + 1, str.length());
}
public static void shuffle(String s1) {
// iterate the same logic 100 times
for (int a1 = 0; a1 < 100; a1++) {
// generate 2 random numbers in the range of the length of string
int randomNumber1 = (int) (Math.random() * s1.length());
int randomNumber2 = (int) (Math.random() * s1.length());
// setting the lower random number to randomnumber1 (it is swapping two number without temp)
if (randomNumber1 > randomNumber2) {
randomNumber1 = randomNumber1 + randomNumber2;
randomNumber2 = randomNumber1 - randomNumber2;
randomNumber1 -= randomNumber2;
}
// calling the swap method to swap the chars in string.
s1 = swap(s1, randomNumber1, randomNumber2);
}
System.out.println(s1);
}

Since you cannot use arrays, try using StringBuilder.
private String shuffleUtil(String s) {
final StringBuilder result = new StringBuilder(s);
for (int rep = 1; rep <= 100; rep++) {
final int randomOne = ThreadLocalRandom.current().nextInt(0, s.length());
final int randomTwo = ThreadLocalRandom.current().nextInt(0, s.length());
final char c = result.charAt(randomOne);
result.setCharAt(randomOne, result.charAt(randomTwo));
result.setCharAt(randomTwo, c);
}
return result.toString();
}
public void shuffle(String s) {
final String result = shuffleUtil(s);
System.out.println(s);
}

Related

Generate all possible combinations longer than the length of an array

I need to build each combination of length L from an String Array/ArrayList, where L is greater than the Array length
I currently have a recursive method (not of my own creation) that will generate each combination of a String[], as long as the combinations are shorter than the Array.
example/psudoCode:
input (2, {A,B,C})
returns {AA, AB, AC, BA, BC, CB, CA}
As of now, if the requested combination length (2 in the example) is greater than the Array length (4,5,6... instead of 2), the recursive method shoots out that sweet sweet ArrayIndexOutOfBounds error.
What I need is a method (recursive or not) that will return every combination of the array, regardless of whether the combinations are longer than the Array itself. Would this be done better by adding more letters to the Array and crossing my fingers or is there a legitimate way to accomplish this? Thank you!
Here is the method I have been using. If u know where the credit lies please say so, this is not of my own creation.
public class bizzBam
{
// Driver method to test below methods
public static void main(String[] args) {
System.out.println("First Test");
String set1[] = {"a", "b","c"};
printAllKLength(set1, pointX);
}
// The method that prints all possible strings of length k. It is
// mainly a wrapper over recursive function printAllKLengthRec()
static void printAllKLength(String set[], int k) {
int n = set.length+2;
printAllKLengthRec(set, "", n, k);
}
// The main recursive method to print all possible strings of length k
static void printAllKLengthRec(String set[], String prefix, int n, int length) {
// Base case: k is 0, print prefix
if (length == 0) {
System.out.println(prefix);
return;
}
// One by one add all characters from set and recursively
// call for k equals to k-1
for (int i = 0; i < n; ++i) {
// Next character of input added
String newPrefix = prefix + set[i];
// k is decreased, because we have added a new character
printAllKLengthRec(set, newPrefix, n, length - 1);
}
}
}
(Edit forgot to say:)
For this algorithim at least, if "PointX" is greater than the input array's length, it will return the indexoutofbounds.
Strictly speaking these are permutations rather than combinations. You're generating all permutations of k elements selected from a set of n candidates, with replacement (or repitition). There will be n^k such permutations.
Here's a non-recursive solution.
public class Permutations
{
public static void main(String[] args)
{
permutationsKN(new String[]{"a", "b", "c"}, 4);
}
static void permutationsKN(String[] arr, int k)
{
int n = arr.length;
int[] idx = new int[k];
String[] perm = new String[k];
while (true)
{
for(int i=0; i<k; i++) perm[i] = arr[idx[i]];
System.out.println(String.join("", perm));
// generate the next permutation
int i = idx.length - 1;
for (; i >= 0; i--)
{
idx[i]++;
if (idx[i] < n) break;
idx[i] = 0;
}
// if the first index wrapped around then we're done
if (i < 0) break;
}
}
}
You have two problems here:
int n = set.length+2; -> This is giving you your "sweet sweet" IndexArrayOutOfBoundsException. Change it to set.length-1. I am not sure why you decided to randomnly put +2 there.
for (int i = 0; i < n; ++i) -> You will be looping from 0 to n. You need to loop from 0 to n-1.
Edit: Or as #SirRaffleBuffle suggested, just do set.length. Total credits to him
Assuming your example is missing "BB" and "CC" because it includes "AA", it looks like what you want is just like the odometer of a car except that instead of ten digits, you want a choice of letters. It's not hard to model an odometer:
class Odo {
private final char [] chars;
private final int [] positions;
private boolean hasNext;
Oddo(String chars, int nPositions) {
this.chars = chars.toCharArray();
this.positions = new int [nPositions];
this.hasNext = true;
}
boolean hasNext() {
return hasNext;
}
String emitNext() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < positions.length; ++i) sb.append(chars[positions[i]]);
for (int i = 0; i < positions.length; ++i) {
if (++positions[i] < chars.length) {
hasNext = true;
return sb.toString();
}
positions[i] = 0;
}
hasNext = false;
return sb.toString();
}
}
Calling like so:
Odo odo = new Odo("AB", 3);
while (odo.hasNext()) {
System.out.println(odo.emitNext());
}
Produces
AAA
BAA
ABA
BBA
AAB
BAB
ABB
BBB

why is that performance diffrence

import java.util.Calendar;
public class MainClass
{
public static void main(String args[])
{
String s = new String("ABCD");
long swapStart = Calendar.getInstance().getTimeInMillis();
for(int i=0; i<s.length()/2;i++)
{
char left = s.charAt(i);
char right = s.charAt(s.length()-(i+1));
s=s.substring(0, i)+right+s.substring(i+1, s.length()-(i+1))+left+s.substring(s.length()-i, s.length());
}
long swapStop = Calendar.getInstance().getTimeInMillis();
long bufStart = Calendar.getInstance().getTimeInMillis();
String str = new String("ABCD");
StringBuffer strBuf = new StringBuffer(str);
str = strBuf.reverse().toString();
long bufStop = Calendar.getInstance().getTimeInMillis();
System.out.println(swapStop-swapStart);
System.out.println(bufStop-bufStart);
}
}
***** in the new String("ABCD") of the string if i provide a really big string say couple of hundreds of alpha numerics
*****in the console output is :
61
0
*****the stringbuffer always calculated in 0 milli seconds and my char swapping algo takes as per the string size
Q. how come my swap algo can't do it in 0 milli seconds and why stringbuffer always does it in 0 milli seconds ?
I checked the Java Source Code and StringBuffer.reverse() is implemented as follows :
public AbstractStringBuilder reverse() {
boolean hasSurrogate = false;
int n = count - 1;
for (int j = (n-1) >> 1; j >= 0; --j) {
char temp = value[j];
char temp2 = value[n - j];
if (!hasSurrogate) {
hasSurrogate = (temp >= Character.MIN_SURROGATE && temp <= Character.MAX_SURROGATE)
|| (temp2 >= Character.MIN_SURROGATE && temp2 <= Character.MAX_SURROGATE);
}
value[j] = temp2;
value[n - j] = temp;
}
if (hasSurrogate) {
// Reverse back all valid surrogate pairs
for (int i = 0; i < count - 1; i++) {
char c2 = value[i];
if (Character.isLowSurrogate(c2)) {
char c1 = value[i + 1];
if (Character.isHighSurrogate(c1)) {
value[i++] = c1;
value[i] = c2;
}
}
}
}
return this;
}
Q. Please explain the surrogate thing.
Q1: There is a performance difference because your swapping code creates a lot of String objects that get operated on, while the other routine works directly with a char array and requires no additional object creation. Let's examine your line of code:
s=s.substring(0, i)+right+s.substring(i+1, s.length()-(i+1))+left+s.substring(s.length()-i, s.length());
It does this kind of work:
s = [new String 1] + char + [new String 2] + char + [new String 3]
That's 4 new String objects (the three shown, plus the one resulting from the addition of String objects. Also, each of the 3 new strings shown has a call to substring which takes time to process. In addition you do all of this work in a for-loop so it gets repeated for each character!
String manipulation is convenient but expensive. Array manipulation is direct, requires no additional object or blocks of memory, so is much faster.
Q2: Surrogates are a special case of unicode character created to handle longer unicode characters. See this article for more details. The order of the hi/low parts of the surrogate are important so it would be wrong for the swap code to reverse those two characters, so if they are found, their order is put back the way it should be.

I am try to take a string and rebuild it with two random int values i created to swap two chars at those positions

public static String jumble(String s) {
int length = s.length() - 2;
Random r = new Random();
int n = r.nextInt(2)+1;
int a = r.nextInt(length)+1;
String s1 ="";
if (s.length() < 4) {
s1 = s1 + s;
} else if (s.length() == 4) {
s1 = s1 + s.charAt(0);
s1 = s1 + s.charAt(2);
s1 = s1 + s.charAt(1);
s1 = s1 + s.charAt(3);
}
while (n == a) {
a = r.nextInt(length)+1;
}
if (0 < n && n < a && a < s.length()) {
s1 = s1 + s.substring(0,n) + s.charAt(a) + s.substring(n + 1, a) + s.charAt(n) + s.substring(a+1,s.length());
}
System.out.println(s1);
return s1;
this is my requirement
String jumble(String): accepts a string and returns a jumbled version of the original: for this method, jumbled means that two randomly chosen characters other than the first and last characters of the string are swapped; this method must use the class, Random. The method must swap two different characters: in other words the two random indices into the string cannot be equal, cannot be 0, and cannot be equal to the string’s length minus one. So, for example, a four-letter string MUST result in the returned string having the same first and last characters and have the second and third characters swapped. Examples of what this method might do: “fist” returns “fsit”, “much” returns “mcuh”, but for longer strings there will be more possible return values: “spill” could return “splil” or “sipll”. Only ONE pair of letters should be swapped and strings shorter than four characters are returned unchanged. When the string length is greater than 3, the original string must never be returned.
I have to use Random class and can only use the string class methods of length, charAt, and substring. this is what i have so far, I really need help creating the last string when it is greater than 4 and i need to use the random numbers i made.
Edit: I have got my code working better now, thanks to Ursa. The problem i have now or at least I think it is a problem is that some times the code does not always print or return anything.
Approach #1
Wrap your input string with StringBuilder builder = new StringBuilder(s);
Get characters with builder.charAt(int) and compare them
Swap characters with builder.setCharAt(int, char)
Take result with builder.toString()
And you don't need to touch other characters.
Approach #2
At the first we should choose indexes of chars to swap:
// 0 < i1 < i2 < s.length - 1
int i1 = 1 + r.nextInt(s.length() - 3); // 1 <= i1 <= s.length - 3
int i2 = 1 + i1 + r.nextInt(s.length() - i1 - 2); // i1 < i2 <= s.length - 2
Then we should split the string on intervals:
[0, i1) - substring before the first swap char
{i1} - the first swap char
[i1 + 1, i2) - substring between swap chars
{i2} - the second swap char
[i2 + 1, s.length) - substring after the second swap char
At last we should swap {i1} & {i2} chars:
return s.substring(0, i1) + s.charAt(i2) + s.substring(i1 + 1, i2) + s.charAt(i1) + s.substring(i2 + 1, s.length);
try this :
public static String jumble(String s) {
int length = s.length();
StringBuilder sb=new StringBuilder(s);
int pos1 = getRandom(length);
int pos2 = getRandom(length);
while(pos1==pos2)
pos1=getRandom(length);
sb.setCharAt(pos1, s.charAt(pos2));
sb.setCharAt(pos2, s.charAt(pos1));
return new String(sb);
}
private static int getRandom(int length) {
Random r = new Random();
int rand=r.nextInt(length);
if(rand==0||rand==length)
return getRandom(length);
else
return rand;
}

Generate all possible string from a given length

I would like to be able to generate all possible strings from a given length, and I frankly don't know how to code that. So for further explanation, I and a friend would like to demonstrate some basic hacking techniques, so bruteforcing comes up. Of course, he will be my victim, no illegal thing there.
However, the only thing he told me is that his PW will be 4-char-long, but I'm pretty sure his PW won't be in any dictionnary, that would be toi easy.
So I came up with the idea of generating EVERY 4-char-long-string possible, containing a-z characters (no caps).
Would someone have a lead to follow to code such an algorithm ? I don't really bother with performances, if it takes 1 night to generate all PW, that's no problem.
Don't forget, that's only on demonstration purposes.
You can do it just how you'd do it with numbers. Start with aaaa. Then increment the 'least significant' part, so aaab. Keep going until you get to aaaz. Then increment to aaba. Repeat until you get to zzzz.
So all you need to do is implement is
String getNext(String current)
To expand on this; It possibly isnt the quickest way of doing things, but it is the simplest to get right.
As the old adage goes - 'first make it right, then make it fast'. Getting a working implementation that passes all your tests (you do have tests, right?) is what you do first. You then rewrite it to make it fast, using your tests as reassurance you're not breaking the core functionality.
The absolutely simplest way is to use four nested loops:
char[] pw = new char[4];
for (pw[0] = 'a' ; pw[0] <= 'z' ; pw[0]++)
for (pw[1] = 'a' ; pw[1] <= 'z' ; pw[1]++)
for (pw[2] = 'a' ; pw[2] <= 'z' ; pw[2]++)
for (pw[3] = 'a' ; pw[3] <= 'z' ; pw[3]++)
System.out.println(new String(pw));
This does not scale well, because adding extra characters requires adding a level of nesting. Recursive approach is more flexible, but it is harder to understand:
void findPwd(char[] pw, int pos) {
if (pos < 0) {
System.out.println(new String(pwd));
return;
}
for (pw[pos] = 'a' ; pw[pos] <= 'z' ; pw[pos]++)
findPwd(pw, pos-1);
}
Call recursive method like this:
char[] pw = new char[4];
findPwd(pw, 3);
private static void printAllStringsOfLength(int len) {
char[] guess = new char[len];
Arrays.fill(guess, 'a');
do {
System.out.println("Current guess: " + new String(guess));
int incrementIndex = guess.length - 1;
while (incrementIndex >= 0) {
guess[incrementIndex]++;
if (guess[incrementIndex] > 'z') {
if (incrementIndex > 0) {
guess[incrementIndex] = 'a';
}
incrementIndex--;
}
else {
break;
}
}
} while (guess[0] <= 'z');
}
public class GenerateCombinations {
public static void main(String[] args) {
List<Character> characters = new ArrayList<Character>();
for (char c = 'a'; c <= 'z'; c++) {
characters.add(c);
}
List<String> allStrings = new ArrayList<String>();
for (Character c : characters) {
for (Character d : characters) {
for (Character e : characters) {
for (Character f : characters) {
String s = "" + c + d + e + f;
allStrings.add(s);
}
}
}
}
System.out.println(allStrings.size()); // 456 976 combinations
}
}
This is something you can do recursively.
Lets define every (n)-character password the set of all (n-1)-character passwords, prefixed with each of the letters a thru z. So there are 26 times as many (n)-character passwords as there are (n-1)-character passwords. Keep in mind that this is for passwords consisting of lower-case letters. Obviously, you can increase the range of each letter quite easily.
Now that you've defined the recursive relationship, you just need the terminating condition.
That would be the fact that there is only one (0)-character password, that being the empty string.
So here's the recursive function:
def printNCharacterPasswords (prefix, num):
if num == 0:
print prefix
return
foreach letter in 'a'..'z':
printNCharacterPasswords (prefix + letter, num - 1)
to be called with:
printNCharacterPasswords ("", 4)
And, since Python is such a wonderful pseudo-code language, you can see it in action with only the first five letters:
def printNCharacterPasswords (prefix, num):
if num == 0:
print prefix
return
for letter in ('a', 'b', 'c', 'd', 'e'):
printNCharacterPasswords (prefix + letter, num - 1)
printNCharacterPasswords ("", 2)
which outputs:
aa
ab
ac
ad
ae
ba
bb
bc
bd
be
ca
cb
cc
cd
ce
da
db
dc
dd
de
ea
eb
ec
ed
ee
A aroth points out, using a digit counter approach is faster. To make this even faster, you can use a combination of an inner loop for the last digit and a counter for the rest (so the number of digits can be variable)
public static void main(String... args) {
long start = System.nanoTime();
int letters = 26;
int count = 6;
final int combinations = (int) Math.pow(letters, count);
char[] chars = new char[count];
Arrays.fill(chars, 'a');
final int last = count - 1;
OUTER:
while (true) {
for (chars[last] = 'a'; chars[last] <= 'z'; chars[last]+=2) {
newComination(chars);
chars[last]++;
newComination(chars);
}
UPDATED:
{
for (int i = last - 1; i >= 0; i--) {
if (chars[i]++ >= 'z')
chars[i] = 'a';
else
break UPDATED;
}
// overflow;
break OUTER;
}
}
long time = System.nanoTime() - start;
System.out.printf("Took %.3f seconds to generate %,d combinations%n", time / 1e9, combinations);
}
private static void newComination(char[] chars) {
}
prints
Took 0.115 seconds to generate 308,915,776 combinations
Note: the loop is so simple, its highly likely that the JIT can eliminate key pieces of code (after in-lining newCombination) and the reason its so fast is its not really calculating every combination.
A simpler way to generate combinations.
long start = System.nanoTime();
int letters = 26;
int count = 6;
final int combinations = (int) Math.pow(letters, count);
StringBuilder sb = new StringBuilder(count);
for (int i = 0; i < combinations; i++) {
sb.setLength(0);
for (int j = 0, i2 = i; j < count; j++, i2 /= letters)
sb.insert(0, (char) ('a' + i2 % letters));
// System.out.println(sb);
}
long time = System.nanoTime() - start;
System.out.printf("Took %.3f seconds to generate %,d combinations%n", time / 1e9, combinations);
prints
aaaa
aaab
aaac
....
zzzx
zzzy
zzzz
Took 0.785 seconds to generate 456,976 combinations
It spends most of its time waiting for the screen to update. ;)
If you comment out the line which prints the combinations, and increase the count to 5 and 6
Took 0.671 seconds to generate 11,881,376 combinations
Took 15.653 seconds to generate 308,915,776 combinations
public class AnagramEngine {
private static int[] anagramIndex;
public AnagramEngine(String str) {
AnagramEngine.generate(str);
}
private static void generate(String str) {
java.util.Map<Integer, Character> anagram = new java.util.HashMap<Integer, Character>();
for(int i = 0; i < str.length(); i++) {
anagram.put((i+1), str.charAt(i));
}
anagramIndex = new int[size(str.length())];
StringBuffer rev = new StringBuffer(AnagramEngine.start(str)+"").reverse();
int end = Integer.parseInt(rev.toString());
for(int i = AnagramEngine.start(str), index = 0; i <= end; i++){
if(AnagramEngine.isOrder(i))
anagramIndex[index++] = i;
}
for(int i = 0; i < anagramIndex.length; i++) {
StringBuffer toGet = new StringBuffer(anagramIndex[i] + "");
for(int j = 0; j < str.length(); j++) {
System.out.print(anagram.get(Integer.parseInt(Character.toString(toGet.charAt(j)))));
}
System.out.print("\n");
}
System.out.print(size(str.length()) + " iterations");
}
private static boolean isOrder(int num) {
java.util.Vector<Integer> list = new java.util.Vector<Integer>();
String str = Integer.toString(num);
char[] digits = str.toCharArray();
for(char vecDigits : digits)
list.add(Integer.parseInt(Character.toString(vecDigits)));
int[] nums = new int[str.length()];
for(int i = 0; i < nums.length; i++)
nums[i] = i+1;
for(int i = 0; i < nums.length; i++) {
if(!list.contains(nums[i]))
return false;
}
return true;
}
private static int start(String str) {
StringBuffer num = new StringBuffer("");
for(int i = 1; i <= str.length(); i++)
num.append(Integer.toString(i));
return Integer.parseInt(num.toString());
}
private static int size(int num) {
int size;
if(num == 1) {
return 1;
}
else {
size = num * size(num - 1);
}
return size;
}
public static void main(final String[] args) {
final java.util.Scanner sc = new java.util.Scanner(System.in);
System.out.printf("\n%s\t", "Entered word:");
String word = sc.nextLine();
System.out.printf("\n");
new AnagramEngine(word);
}
}
Put all the characters you expect the password to contain into an array. Write a stub function to test if your algorithm finds the correct password. Start with passwords of length 1, work your way up to 4 and see if your fake password is found on each iteration.
you can use the following code for getting random string. It will return you a string of 32 chars. you can get string of desired length by using substring(). Like if you want a string with 10 chars then:
import java.security.SecureRandom;
import java.math.BigInteger;
SecureRandom srandom = new SecureRandom();
String rand = new BigInteger(176, srandom).toString(32);
rand.substring(0,7);

What is the most efficient algorithm for reversing a String in Java?

What is the most efficient way to reverse a string in Java? Should I use some sort of xor operator? The easy way would be to put all the chars in a stack and put them back into a string again but I doubt that's a very efficient way to do it.
And please do not tell me to use some built in function in Java. I am interested in learning how to do it not to use an efficient function but not knowing why it's efficient or how it's built up.
You say you want to know the most efficient way and you don't want to know some standard built-in way of doing this. Then I say to you: RTSL (read the source, luke):
Check out the source code for AbstractStringBuilder#reverse, which gets called by StringBuilder#reverse. I bet it does some stuff that you would not have considered for a robust reverse operation.
The following does not deal with UTF-16 surrogate pairs.
public static String reverse(String orig)
{
char[] s = orig.toCharArray();
int n = s.length;
int halfLength = n / 2;
for (int i=0; i<halfLength; i++)
{
char temp = s[i];
s[i] = s[n-1-i];
s[n-1-i] = temp;
}
return new String(s);
}
You said you don't want to do it the easy way, but for those Googling you should use StringBuilder.reverse:
String reversed = new StringBuilder(s).reverse().toString();
If you need to implement it yourself, then iterate over the characters in reverse order and append them to a StringBuilder. You have to be careful if there are (or can be) surrogate pairs, as these should not be reversed. The method shown above does this for you automatically, which is why you should use it if possible.
An old post & question, however still did not see answers pertaining to recursion. Recursive method reverse the given string s, without relaying on inbuilt jdk functions
public static String reverse(String s) {
if (s.length() <= 1) {
return s;
}
return reverse(s.substring(1)) + s.charAt(0);
}
`
The fastest way would be to use the reverse() method on the StringBuilder or StringBuffer classes :)
If you want to implement it yourself, you can get the character array, allocate a second character array and move the chars, in pseudo code this would be like:
String reverse(String str) {
char[] c = str.getCharArray
char[] r = new char[c.length];
int end = c.length - 1
for (int n = 0; n <= end; n++) {
r[n] = c[end - n];
}
return new String(r);
}
You could also run half the array length and swap the chars, the checks involved slow things down probably.
I'm not really sure by what you mean when you say you need an efficient algorithm.
The ways of reversing a string that I can think of are (they are all already mentioned in other answers):
Use a stack (your idea).
Create a new reversed String by adding characters one by one in reverse order from the original String to a blank String/StringBuilder/char[].
Exchange all characters in the first half of the String with its corresponding position in the last half (i.e. the ith character gets swapped with the (length-i-1)th character).
The thing is that all of them have the same runtime complexity: O(N). Thus it cannot really be argued that any one is any significantly better than the others for very large values of N (i.e. very large strings).
The third method does have one thing going for it, the other two require O(N) extra space (for the stack or the new String), while it can perform swaps in place. But Strings are immutable in Java so you need to perform swaps on a newly created StringBuilder/char[] anyway and thus end up needing O(N) extra space.
public class ReverseInPlace {
static char[] str=null;
public static void main(String s[]) {
if(s.length==0)
System.exit(-1);
str=s[0].toCharArray();
int begin=0;
int end=str.length-1;
System.out.print("Original string=");
for(int i=0; i<str.length; i++){
System.out.print(str[i]);
}
while(begin<end){
str[begin]= (char) (str[begin]^str[end]);
str[end]= (char) (str[begin]^str[end]);
str[begin]= (char) (str[end]^str[begin]);
begin++;
end--;
}
System.out.print("\n" + "Reversed string=");
for(int i=0; i<str.length; i++){
System.out.print(str[i]);
}
}
}
I think that if you REALLY don't have performance problem you should just go with the most readable solution which is:
StringUtils.reverse("Hello World");
private static String reverse(String str) {
int i = 0;
int j = str.length()-1;
char []c = str.toCharArray();
while(i <= j){
char t = str.charAt(i);
c[i] = str.charAt(j);
c[j]=t;
i++;
j--;
}
return new String(c);
}
If you do not want to use any built in function, you need to go back with the string to its component parts: an array of chars.
Now the question becomes what is the most efficient way to reverse an array? The answer to this question in practice also depends upon memory usage (for very large strings), but in theory efficiency in these cases is measured in array accesses.
The easiest way is to create a new array and fill it with the values you encounter while reverse iterating over the original array, and returning the new array. (Although with a temporary variable you could also do this without an additional array, as in Simon Nickersons answer).
In this way you access each element exactly once for an array with n elements. Thus giving an efficiency of O(n).
I would simply do it this way without a use of any single util function. Just the String class is sufficient.
public class MyStringUtil {
public static void main(String[] args) {
String reversedString = reverse("StringToReverse");
System.out.println("Reversed String : " + reversedString);
}
/**
* Reverses the given string and returns reversed string
*
* #param s Input String
* #returns reversed string
*/
private static String reverse(String s) {
char[] charArray = s.toCharArray(); // Returns the String's internal character array copy
int j = charArray.length - 1;
for (int i = 0; charArray.length > 0 && i < j; i++, j--) {
char ch = charArray[i];
charArray[i] = charArray[j];
charArray[j] = ch;
}
return charArray.toString();
}
}
Check it. Cheers!!
Using String:
String abc = "abcd";
int a= abc.length();
String reverse="";
for (int i=a-1;i>=0 ;i--)
{
reverse= reverse + abc.charAt(i);
}
System.out.println("Reverse of String abcd using invert array is :"+reverse);
Using StringBuilder:
String abc = "abcd";
int a= abc.length();
StringBuilder sb1 = new StringBuilder();
for (int i=a-1;i>=0 ;i--)
{
sb1= sb1.append(abc.charAt(i));
}
System.out.println("Reverse of String abcd using StringBuilder is :"+sb1);
One variant can be, swapping the elements.
int n = length - 1;
char []strArray = str.toCharArray();
for (int j = 0; j < n; j++) {
char temp = strArray[j];
char temp2 = strArray[n];
strArray[j] = temp2;
strArray[n] = temp;
n--;
}
public static void main(String[] args){
String string ="abcdefghijklmnopqrstuvwxyz";
StringBuilder sb = new StringBuilder(string);
sb.reverse();
System.out.println(sb);
}
public static String Reverse(String word){
String temp = "";
char[] arr = word.toCharArray();
for(int i = arr.length-1;i>=0;i--){
temp = temp+arr[i];
}
return temp;
}
char* rev(char* str)
{
int end= strlen(str)-1;
int start = 0;
while( start<end )
{
str[start] ^= str[end];
str[end] ^= str[start];
str[start]^= str[end];
++start;
--end;
}
return str;
}
=========================
Wondering how it works?
First operation:
x1 = x1 XOR x2
x1: 1 0 0
x2: 1 1 1
New x1: 0 1 1
Second operation
x2 = x2 XOR x1
x1: 0 1 1
x2: 1 1 1
New x2: 1 0 0
//Notice that X2 has become X1 now
Third operation:
x1 = x1 XOR x2
x1: 0 1 1
x2: 1 0 0
New x1: 1 1 1
//Notice that X1 became X2
public static string getReverse(string str)
{
char[] ch = str.ToCharArray();
string reverse = "";
for (int i = str.Length - 1; i > -1; i--)
{
reverse += ch[i];
}
return reverse;
}
//using in-built method reverse of Array
public static string getReverseUsingBulidingFunction(string str)
{
char[] s = str.ToCharArray();
Array.Reverse(s);
return new string(s);
}
public static void Main(string[] args)
{
string str = "123";
Console.WriteLine("The reverse string of '{0}' is: {1}",str,getReverse(str));
Console.WriteLine("The reverse string of '{0}' is: {1}", str, getReverseUsingBulidingFunction(str));
Console.ReadLine();
}
Using multiple threads to swap the elements:
final char[] strArray = str.toCharArray();
IntStream.range(0, str.length() / 2).parallel().forEach(e -> {
final char tmp = strArray[e];
strArray[e] = strArray[str.length() - e - 1];
strArray[str.length() - e - 1] = tmp;
});
return new String(strArray);
Of course this is the most efficient way:
String reversed = new StringBuilder(str).reverse().toString();
But if you don't like using that then I recommend this instead:
public String reverseString(String str)
{
String output = "";
int len = str.length();
for(int k = 1; k <= str.length(); k++, len--)
{
output += str.substring(len-1,len);
}
return output;
}
static String ReverseString(String input) {
var len = input.Length - 1;
int i = 0;
char[] revString = new char[len+1];
while (len >= 0) {
revString[i] = input[len];
len--;
i++;
}
return new string(revString);
}
why can't we stick with the simplest loop and revere with character read and keep adding to the char array, I have come across with a whiteboard interview, where interviewer set restrictions on not to use StringBuilder and inbuilt functions.
This is the optimal way to reverse a string with O(log n) complexity.
public char[] optimisedArrayReverse(char[] chars) {
char[] reversedChars = chars;
int length = chars.length;
int center = (length / 2) - 1;
int reversedIndex = chars.length - 1;
if (center < 0) {
return chars;
}
for (int index = 0; index <= center; index++) {
//Swap values
char temp = reversedChars[index];
reversedChars[index] = chars[reversedIndex];
reversedChars[reversedIndex] = temp;
reversedIndex --;
}
return reversedChars;
}
public static String reverseString(String str)
{
StringBuilder sb = new StringBuilder();
for (int i = str.length() - 1; i >= 0; i--)
{
sb.append(str[i]);
}
return sb.toString();
}

Categories

Resources