Related
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);
}
I'm trying to write an algorithm which adds two numbers that are stored as chars in two arrays. Unfortunately, it doesn't work. When I try to debug it, I see that the variables a and b get the value -1 which makes no sense. Any idea what might be the problem?
public class rechner2 {
public static void main(String[] args) {
final char[] zahl1 = {1, 2, 3};
final char[] zahl2 = {7, 8, 9};
//Add arrays zahl1 and zahl2.
char [] zwischenarray = add(zahl1, zahl2);
for (int i = 0; i < zwischenarray.length; i++) {
System.out.println(zwischenarray[i]);
}
}
private static char[] add(char[] zahl1, char[] zahl2) {
int len;
if (zahl1.length < zahl2.length) {
len = zahl2.length;
} else {
len = zahl1.length;
}
char[] finalresult = new char [len + 1];
int carryover = 0;
for (int i = 0; i < len; i++) {
int a = Character.getNumericValue(zahl1[i]);
int b = Character.getNumericValue(zahl2[i]);
int c = a + b + carryover;
if (c > 9) {
carryover = 1;
c = c - 10;
} else {
carryover = 0;
}
finalresult[i] = (char)c;
}
if (carryover == 1) {
finalresult[len + 1] = 1;
}
return finalresult;
}
}
in this code I believe 2 bug
instead of char , i guess better to us int
length of the array
here is the code:
public class rechner2 {
public static void main(String[] args) {
int[] zahl1 = {1,2,3};
int[] zahl2 = {7,8,9};
//Add arrays zahl1 and zahl2.
int [] zwischenarray = add(zahl1, zahl2);
for (int i = 0; i < zwischenarray.length; i++) {
System.out.println(zwischenarray[i]);
}
}
private static int[] add(int[] zahl1, int[] zahl2) {
int len;
if (zahl1.length < zahl2.length) {
len = zahl2.length;
} else {
len = zahl1.length;
}
int[] finalresult = new int [len + 1];
int carryover = 0;
for (int i = 0; i <= len-1; i++) {
int a = (zahl1[i]);
int b = (zahl2[i]);
int c = a + b + carryover;
if (c > 9) {
carryover = 1;
c = c - 10;
} else {
carryover = 0;
}
finalresult[i] = c;
}
if (carryover == 1) {
finalresult[len] = 1;
}
return finalresult;
}
}
Your code is conflicted: The numbers / characters in your array are actually integers, not "printable" or "human readable" characters. But, parts of your code are treating them as if they are "printable".
Let's go back decades, and use ASCII for the beginning of this explanation. ASCII has "Printable" and "Nonprintable" characters. The "Nonprintable" characters are known as "Control codes."
Control codes include codes that move the cursor on a display terminal or print head on a printing terminal. They include thing like CR (Carriage Return), LF (Line Feed), HT (Horizontal tab), and BS (Backspace). Others are used by data communications hardware to control the flow of data, or to report status.
Printable characters correspond to what you see on a terminal screen or printout. They include uppercase alphabetic, lower case alphabetic, digits, punctuation, and the space character. They are "human readable."
Look at the list of printable characters in the Wikipedia article. Take 5 as an example. It's represented as '53' in base ten, which corresponds to '35' in base sixteen, or '011 0101' in binary. Note that it is not the same as the binary number five, which would be '0000 0101'.
Java uses 16 bit Unicode, not ASCII, for its char type. The Java compiler allows arithmetic to be done on char data, as if it was the same as short.
These lines in your code expect your char variables and constants are printable characters:
int a = Character.getNumericValue(zahl1[i]);
int b = Character.getNumericValue(zahl2[i]);
In addition, that you specified zwischenarray as char tells the compiler to handle the contents as printable characters in this line:
System.out.println(zwischenarray[i]);
But, the rest of your code treats your char data as integer data types.
You have a bug in this line: finalresult[len + 1] = 1;. After that bug is fixed, how do you fix the rest of your code? There are different ways, and which is best depends on your intention.
For demonstration purpose, try this: Replace the following
int a = Character.getNumericValue(zahl1[i]);
int b = Character.getNumericValue(zahl2[i]);
int c = a + b + carryover;
with
int c = zahl1[i] + zahl2 [i] + carryover;
Also, put a cast in your output line:
System.out.println((short)zwischenarray[i]);
And run it. That will demonstrate you can do arithmetic on Java char data.
Now, remove the (short) cast in output line, and change all occurrences of char to short (or int). Your program still works.
This is because of the way you entered the values for zahl1 and zahl2. Your source code consists of printable characters and white space. By omitting the single quotes, you told the compiler to convert the values to binary integers. For example, your source code 9 became binary 0000 1001 in the runtime code. If you wanted your 9 to remain as a printable character, you needed to enclose it in single quote marks: '9' .
By enclosing all the values in zahl1 and zahl2 in single quote marks, the use of Character.getNumericValue is appropriate. But, you would still need the (short) or (int) cast in your System.out. line to see your output.
Character.getNumericValue is returning -1 because the values passed are outside of the range it was designed to work with.
Here are two ways to convert a base 10 digit represented as a binary integer to the equivalent printable character:
finalresult[i] = (char) (c + '0');
But, my preference is for this:
final String digit = "0123456789";
finalresult[i] = digit.charAt (c);
I want to exhaustively test a String matching algorithm, named myAlgo(Char[] a, Char[] b)
The exhaustive test includes a no. of different char letters, alplhabet " l ", in an "n" long array. The test then computes all combinations, while comparing it with all combinations of another array with similar properties (Like truth tables),e.g.
I have not been able to either compute something that would generate every combination of the array of size n and alphabet l, niether have I been able to make code that is able to combine the computation into iterative testcases (test all the combinations of the two arrays compared), though with code that would be able to generate the combinations, making a nested for-loop should do the required testing.
My goal is to break my algorithm by making it compute something it should not compute.
Test(char[] l, int n)
l = [a;b] //a case could be
n = 2 //a case could be
myAlgo([a;a],[a;a]); //loops over my algorithm in the following way
myAlgo([a;b],[a;a]);
myAlgo([b;a],[a;a]);
myAlgo([b;b],[a;a]);
myAlgo([a;a],[a;b]);
myAlgo([a;b],[a;b]);
myAlgo([b;a],[a;b]);
myAlgo([b;b],[a;b]);
myAlgo([a;a],[b;a]);
myAlgo([a;b],[b;a]);
...
myAlgo([b;b],[b;b]);
My own solution (only works for a finite set of "l") and also starts printing wierd outputs on later iterations.
public class Test {
//aux function to format chars
public static String concatChar(char [] c){
String s = "";
for(char cc : c){
s += cc;
}
return s;
}
public static void main(String[] args) {
String ss1 = "AA"; //TestCases, n = 2
String ss2 = "AA";
char[] test1 = ss1.toCharArray();
char[] test2 = ss2.toCharArray();
Fordi fordi = new Fordi(); //my algorithm
TestGenerator tGen = new TestGenerator(); //my testGenerator
for(int i=0; i<Math.pow(4.0, 2.0);i++){ //to test all different cases
for(int j=0; j<Math.pow(4.0, 2.0);j++){
int k = fordi.calculate(test1, test2); //my algorithm
String mys1 = concatChar(test1); //to print result
String mys2 = concatChar(test2); //to print result
System.out.println(mys1 + " - " + mys2);
System.out.println(k);
test2 = tGen.countArray(test2); //"flip" one number
}
test2 = ss1.toCharArray();
test1 = tGen.countArray(test1); //"flip"
}
}
}
My arrayflipper code:
public char[] countArray(char[] a){
int i=0;
while(i<a.length){
switch (a[i]){
case 'A':
a[i]='B';
clearBottom(a,i);
return a;
case 'B':
a[i]='C';
clearBottom(a,i);
return a;
case 'C':
a[i]='D';
clearBottom(a,i);
return a;
case 'D':
i++;
break;
default:
System.out.println("Something went terribly wrong!");
}
}
return a;
}
public char[] clearBottom(char [] a, int i){
while(i >0){
i--;
a[i] = 'A';
}
return a;
}
As I understand it, your goal is to create all n-character long strings (stored individually as elements in an array) consisting of letters in the L letter alphabet?
One way to accomplish this is to order your letters (A=0, B=1, C=2, etc). Then you can, from a starting string of AAA...AAA (n-characters long) just keep adding 1. Essentially you implement an addition algorithm. Adding 1 would turn an A=0 into a B=1. For example, n=3 and L=3:
start: AAA (0,0,0).
Adding 1 becomes AAB (0,0,1)
Adding 1 again become AAC (0, 0, 2)
Adding 1 again (since we are out of letters, now we carry a bit over) ABA (0, 1, 0).
You can boil the process down to looking for the right-most number that is not maxed out and add 1 to it (then all digits to the right of that digit go back to zero). So in the string ABCCC, the B digit is the right-most not maxed out digit, it goes up by 1 and becomes a C, then all the maxed out digits to the right go back to 0 (A) leaving ACAAA as the next string.
Your algorithm just repeatedly adds 1 until all the elements in the string are maxed out.
Instead of using a switch statement, I recommend putting every character you want to test (A, B, C, D) into an array, and then using the XOR operation to calculate the index of each character from the iteration number in a manner similar to the following:
char[] l = new char[]{'A','B','C','D'};
int n = 2;
char[] test1 = new char[n];
char[] test2 = new char[n];
int max = (int)Math.pow(l.length, n);
for (int i = 0; i < max; i++) {
for (int k = 0; k < n; k++) {
test2[k] = l[(i % (int)Math.pow(l.length, k + 1)) / (int)Math.pow(l.length, k)];
}
for (int j = 0; j < max; j++) {
for (int k = 0; k < n; k++) {
test1[k] = l[(j % (int)Math.pow(l.length, k + 1)) / (int)Math.pow(l.length, k)];
}
int k = fordi.calculate(test1, test2);
System.out.println(new String(test1) + "-" + new String(test2));
System.out.println(k);
}
}
You can add more characters to l as well as increase n and it should still work. Of course, this can be further optimized, but you should get the idea. Hope this answer helps!
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 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();
}