So the program has to count letters of a string. I am not allowed to use loops except of recursive ones.
The method has to look like this:
static int numberOf(String text, char characterToCount)
Input:
abcbabcba (String) and b (char)
Output:
4
That's what my Code looks like so far ( I get Stackoverflow ) :
static int numberOf(String text, char characterToCount) {
int i = 0;
int erg = 0;
if (text.length() != 0) {
if (i != text.length()) {
if (text.charAt(i) == characterToCount) {
i++;
erg++;
numberOf(text, characterToCount);
} else {
i++;
numberOf(text, characterToCount);
}
} else {
return erg;
}
}
return 0;
}
EDIT
I'm only allowed to use String.charAt and String.length
The problem is that you aren't reducing text when you call the method so the length is never reduced to 0. Here is what you should be doing. Note that you do not need to pass an index to the method. Just keep reducing the text by 1 each time and just check the first character for equality to the target character.
public static void main(String[] args) {
System.out.println(numberOf("ksjssjkksjssss", 's'));
}
static int numberOf(String text, char characterToCount) {
if (text.isEmpty()) {
return 0;
}
if (text.charAt(0) == characterToCount) {
// call method and add 1 since you found a character
return numberOf(text.substring(1), characterToCount) + 1;
}
// just call the method.
return numberOf(text.substring(1), characterToCount);
}
The above prints
8
Ok, here is my modified version to meet your requirements of using only String.length and String.charAt. The char is really 16 bits so I use the high order byte to store the current index. I increment that index for each recursive call to maintain the current position of the search. When I add 256 to the character I am really adding 1 to the high order byte.
static int numberOf(String text, char ch) {
// stop when index exceeds text length
if (ch >> 8 >= text.length()) {
return 0;
}
if (text.charAt((ch >> 8)) == (ch & 0xff)) {
return numberOf(text, (char)(ch + 256)) + 1;
}
return numberOf(text, (char)(ch + 256));
}
This will not work as written on some character sets that are wider than 8 bits.
WJS's answer looks good but if you want simpler solution, this might help as well.
The problem in your solution is that your update of i and erg in one call stack is not seen/used by the next recursive call stack, since they are local variables and every stack will have their own copy of i and erg. They are always initialized as 0 in every call of numberOf method.
If substring isn't allowed then one way would be to make use of an extra variable that holds the index of position in the text you are comparing.
But on doing so you'll probably have to modify the signature of your method (if you don't want to use a class level static variable). And since you've mentioned that your method has to have only two arguments (text, charToCount), one way to achieve this easily would be to make use of a helper method (containing extra index argument) and your method can call it.
static int numberOf(String text, char characterToCount) {
return helper(text, characterToCount, 0);
}
static int helper(String text, char charToCount, int index) {
if (text.isEmpty() || index == text.length()) return 0;
int countCharOnRight = helper(text, charToCount, index+1);
return (text.charAt(index) == charToCount) ? 1 + countCharOnRight : countCharOnRight;
}
What
static int numberOf(String text, char characterToCount) {
return numberOfRecursive(text, characterToCount, 0);
}
// Recursive helper function
static int numberOfRecursive(String text, char characterToCount, int index) {
if (index == text.length()) // Abort recursion
return 0;
if (text.charAt(index) == characterToCount) // check char at index, then check next recursively
return numberOfRecursive(text, characterToCount, index + 1) + 1;
else
return numberOfRecursive(text, characterToCount, index + 1);
}
Why
Most recursive problems require a helper function, that actually performs the recursive part. It will be called from the original function with initial values, here with our text, character and a starting position of 0.
Then, the recursive function needs an abort condition, which I provide by a bound check. We terminate if our recursion reached the end of the string.
Finally the recursive function does some calculation which it bases on a recursive call. Here we add 1 to our result, if the char at our index position is the one to count. If not, we continue counting without adding 1.
I hope I could help.
The idea of recursion is that you call the same function/method a lot of times after some conditions. A good approach is to call the same function but reduce the string to check each time.
Class
public class StringUtils {
public int numberOf(String text, char characterToCount) {
int count = 0;
if (text.length() != 0) {
if(text.charAt(0) == characterToCount) { //Only increment when is the same character
count++;
}
count = count + numberOf(text.substring(1, text.length()), characterToCount); //Do a substring but remove the first character
}
return count;
}
}
Test
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class StringUtilsTest {
#Test
public void should_count_all_the_ocurrences() {
//Given
StringUtils utils = new StringUtils();
String sentence = "</www></palabraRandom></www></palabraRandom></palabraRandom></www>";
//When
int output = utils.numberOf(sentence, '>');
//Then
assertEquals(6, output);
}
}
So I think I got my solution.
It's maybe not that well but it works. Thanks for your help :)
public class CountLetters {
public static void main(String[] args) {
print("Bitte geben Sie den Text ein: ");
String text = readString();
text = toLowerCase(text, 0);
print("Bitte geben Sie ein Zeichen ein: ");
String zeich = readString();
zeich = toLowerCase(zeich, 0);
if (zeich.length() > 1) {
throw new PR1Exception("Bitte nur einen Buchstaben eingeben. ");
}
char zeichen = zeich.charAt(0);
if (zeichen > 0 && zeichen < 65 && zeichen > 90 && zeichen < 97 && zeichen > 123) {
throw new PR1Exception("Bitte nur Buchstaben eingeben.");
}
int anzahl = numberOf(text, zeichen);
println("-> " + anzahl);
}
static String toLowerCase(String text, int i) {
String lowerText = "";
if (i == text.length()) {
return lowerText;
} else if (text.charAt(i) < 'a') {
return lowerText += (char) (text.charAt(i) - 'A' + 'a') + toLowerCase(text, i + 1);
} else {
return lowerText += text.charAt(i) + toLowerCase(text, i + 1);
}
}
static int numberOf(String text, char characterToCount) {
return hilfe(text, characterToCount, 0, 0);
}
static int hilfe(String t, char ch, int i, int a) {
if (t.length() == a) {
return i;
} else if (t.charAt(a) == ch) {
return hilfe(t, ch, i + 1, a + 1);
} else {
return hilfe(t, ch, i, a + 1);
}
}
You can use an index variable if it is reached to the end returns 0. Otherwise, return 1 if it is letter or 0.
public class Main {
public static void main(String[] args) {
System.out.println(numberOf("Hello World-1234", 'o'));
}
private static int numberOf(String text, char characterToCount) {
if (!text.isEmpty()) {
return numberOf(text.substring(1), characterToCount) + (text.charAt(0) == characterToCount ? 1 : 0);
}
return 0;
}
}
EDIT: Implementation without substring
public class Main {
public static void main(String[] args) {
System.out.println(numberOf("Hello World-1234", 'o'));
}
private static int numberOf(String text, char characterToCount) {
if (text.isEmpty()) {
return 0;
}
char[] chars = text.toCharArray();
char[] newChars = new char[chars.length - 1];
System.arraycopy(chars, 1, newChars, 0, newChars.length);
return numberOf(new String(newChars), characterToCount) + (chars[0] == characterToCount ? 1 : 0);
}
}
Related
I want to check if every word in an string has specific endings with various length. I can't use arrays & methods for this like endsWith(). The only methods im allowed to use are charAt() and length().
public class TextAnalyse {
public static void main(String[] args) {
System.out.println(countEndings("This is a test", "t"));
System.out.println(countEndings("Waren sollen rollen", "en"));
System.out.println(countEndings("The ending is longer then every single word", "abcdefghijklmn"));
System.out.println(countEndings("Today is a good day", "xyz"));
System.out.println(countEndings("Thist is a test", "t"));
System.out.println(countEndings("This is a test!", "t"));
System.out.println(countEndings("Is this a test?", "t"));
}
public static int countEndings(String text, String ending) {
int counter = 0;
int counting;
int lastStringChar;
for (int i = 0; i < text.length(); i++) {
lastStringChar = 0;
if (!(text.charAt(i) >= 'A' && text.charAt(i) <= 'Z' || text.charAt(i) >= 'a' && text.charAt(i) <= 'z') || i == text.length() - 1) {
if( i == text.length() - 1 ){
lastStringChar = 1;
}
counting = 0;
for (int j = 0; j + lastStringChar < ending.length() && i > ending.length(); j++) {
if (text.charAt(i - ending.length() + j + lastStringChar) == ending.charAt(j)) {
counting = 1;
} else {
counting = 0;
}
}
counter += counting;
}
}
return counter;
}
}
The actual results are that I get one counting less, I guess its because it dont check the last chars properly.
The most simple solution I can come up with is the following:
Check, if a word ends with a given suffix:
public static boolean endsWith(String word, String suffix) {
if(suffix.length() > word.length()) {
return false;
}
int textIndex = (word.length() - 1);
int suffixIndex = (suffix.length() - 1);
while(suffixIndex >= 0) {
char textChar = word.charAt(textIndex);
char suffixChar = suffix.charAt(suffixIndex);
if(textChar != suffixChar) {
return false;
}
textIndex--;
suffixIndex--;
}
return true;
}
Split the given in its' words and use the above method to count every word ending with the given ending:
public static int countEndings(String text, String ending) {
{
//maybe remove punctuation here...
//(if yes, use String.replace for example)
}
String[] words = text.split(" ");
int counter = 0;
for(String word: words) {
if(endsWith(word, ending)) {
counter++;
}
}
return counter;
}
Also consider to remove unwanted punctuation, like '!' or '?' (...) - the above implementation will not recognize count any word ending with t in the String test!!
I guess you are able to use regular expression.
If you want count words with ending, you can use the following code:
public static int countEndings(String text, String ending) {
final Matcher wordWithEndMatches = Pattern.compile("\\b[A-Za-z]*" + ending + "\\b").matcher(text);
int count = 0;
while(wordWithEndMatches.find()) {
count++;
}
return count;
}
I have this assignment that needs me to decompress a previously compressed string.
Examples of this would be
i4a --> iaaaa
q3w2ai2b --> qwwwaaibb
3a --> aaa
Here's what I've written so far:
public static String decompress(String compressedText)
{
char c;
char let;
int num;
String done = "";
String toBeDone = "";
String toBeDone2 = "";
if(compressedText.length() <= 1)
{
return compressedText;
}
if (Character.isLetter(compressedText.charAt(0)))
{
done = compressedText.substring(0,1);
toBeDone = compressedText.substring(1);
return done + decompress(toBeDone);
}
else
{
c = compressedText.charAt(0);
num = Character.getNumericValue(c);
let = compressedText.charAt(1);
if (num > 0)
{
num--;
toBeDone = num + Character.toString(let);
toBeDone2 = compressedText.substring(2);
return Character.toString(let) + decompress(toBeDone) + decompress(toBeDone2);
}
else
{
toBeDone2 = compressedText.substring(2);
return Character.toString(let) + decompress(toBeDone2);
}
}
}
My return values are absolutely horrendous.
"ab" yields "babb" somehow.
"a" or any 1 letter string string yields the right result
"2a" yields "aaaaaaaaaaa"
"2a3b" gives me "aaaabbbbbbbbbbbbbbbbbbbbbbbbbbaaabbbbaaaabbbbbbbbbbbbbbbbbbbbbbbbbb"
The only place I can see a mistake in would probably be the last else section, since I wasn't entirely sure on what to do once the number reaches 0 and I have to stop using recursion on the letter after it. Other than that, I can't really see a problem that gives such horrifying outputs.
I reckon something like this would work:
public static String decompress(String compressedText) {
if (compressedText.length() <= 1) {
return compressedText;
}
char c = compressedText.charAt(0);
if (Character.isDigit(c)) {
return String.join("", Collections.nCopies(Character.digit(c, 10), compressedText.substring(1, 2))) + decompress(compressedText.substring(2));
}
return compressedText.charAt(0) + decompress(compressedText.substring(1));
}
As you can see, the base case is when the compressed String has a length less than or equal to 1 (as you have it in your program).
Then, we check if the first character is a digit. If so, we substitute in the correct amount of characters, and continue with the recursive process until we reach the base case.
If the first character is not a digit, then we simply append it and continue.
Keep in mind that this will only work with numbers from 1 to 9; if you require higher values, let me know!
EDIT 1: If the Collections#nCopies method is too complex, here is an equivalent method:
if (Character.isDigit(c)) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < Character.digit(c, 10); i++) {
sb.append(compressedText.charAt(1));
}
return sb.toString() + decompress(compressedText.substring(2));
}
EDIT 2: Here is a method that uses a recursive helper-method to repeat a String:
public static String decompress(String compressedText) {
if (compressedText.length() <= 1) {
return compressedText;
}
char c = compressedText.charAt(0);
if (Character.isDigit(c)) {
return repeatCharacter(compressedText.charAt(1), Character.digit(c, 10)) + decompress(compressedText.substring(2));
}
return compressedText.charAt(0) + decompress(compressedText.substring(1));
}
public static String repeatCharacter(char character, int counter) {
if (counter == 1) {
return Character.toString(character);
}
return character + repeatCharacter(character, counter - 1);
}
i need a litle bit help.
i need to write this method recursively:
public static int howManyChar (String s, char c)
and without using the substring method and loops..
any ideas?
i am stuck at this point.
public static int howManyChar (String s, char c)
{
int count = 0;
int lastChar = s.length()-1;
if (s.length()== 0)
return 0;
if (s.charAt(lastChar) == c)
{
count++;
}
i have succeeded using the substring method:
int count =0;
if (s.charAt(0)==c)
count++;
if (s.length()>1)
{
count+=howManyChar(s.substring(1), c);
}
return count;
but i want to write the code without using substring.
try this
public static int howManyChar (String s, char c) {
if (s.length()==0)
return 0;
return s.charAt(0) == c ? 1 : 0 + howManyChar(s.substring(1), c);
}
OR if you cannot use the substring method
public static int howManyChar (String s, char c, int pos) {
if (pos >= s.length())
return 0;
return s.charAt(pos) == c ? 1 : 0 + howManyChar(s, c, ++pos);
}
I have looked at some of the answers here, they are either too complicated for your question, use substring, or do not use basic recursion
your solution should be something like this.
function countChar(String a, char b, int i)
if(i==a.length)
return 0
else if(b ==a.charAt(i))
return 1 + function countChar(a, b, i+1)
else
return function countChar(a,b,i+1)
This part of the code is the loop.
function countChar(String a, char b, int i)
{
if(i==a.length)
{
return 0
}
else
{
//put here a print statement to see what happens.
// print charAt(i) or i itself
return function countChar(a, b, i+1) //<-- moving to the next index
}
}
Learn that loop. You should use charAt(i). Substring is not neccesssary..
In order to fulfil the requirement, you can wrap your method in another recursive one.
function howManyChar(String a, Char b)
{
countChar(a, b, 0);
}
public static int howManyChar (String s, char c)
{
index++;
if (s.length() == index)
return 0;
else if(s.charAt(index) == c)
return 1 + howManyChar(s, c);
else
return 0 + howManyChar(s, c);
}
Now this isn't the best soultion, I have a class level variable (index) holding the place in the string. But without using substring I can't think of a better way to do it.
I have a good solution without subscript...
public class test{
int counter=0;int last;
public static void main(String[] args){
test t1=new test(); //object of test
String line="This is a working code"; //line in which char to be counted
char c='q'; // char to be counted
t1.last=line.length()-1; //setting last
System.out.println("In sentence: "+line);
if(t1.count(line, c)!=-1)
System.out.println("The character "+c+" is "+t1.counter+" times"); //printing result
else
System.out.println("The character "+c+" is not found");
}
public int count (String line, char c){
if (last<0){ // case for empty string or nil char.
return counter; // recursion ends here and return counted
}
else if(line.charAt(last)==c)
{
counter++; //counting
}
last--; //shitin last;
count(line, c);
return -1; //if even a single times is not found then return -1;
}
}
It may help you...You may take line and char which is to be searched as input from Command prompt......Thank you....
I want to count number of words in my string using recursive method (java)
so far i wrote this code
public static int CountWords(String sen) {
int count = 0;
int i = sen.indexOf(" ");
if (sen.isEmpty()) {
return 0;
}else
if (i == sen.indexOf(" ")) {
return count++;
}
//sen.substring(0,sen.indexOf(" ")-1);
count++;
return count + CountWords(sen.substring(i + 1));
}
i always get 0 when i call the method
can anyone help me make this code run
How you're using indexOf is the problem. You're setting i to the result of calling indexOf, then seeing if it's equal to the result of calling indexOf on the same string with the same parameter. The result of the test i == sen.indexOf(" ") will always be true. That's why you always get 0.
String#indexOf returns -1 if the char it's looking for is not found. indexOf comes in very handy here.
Also you shouldn't need a local count variable. Introducing a variable here just makes the code harder to read, because the reader has to hunt around to figure out what the value of it is.
Assuming your input always has exactly one blank between words this could be done as:
public static int countWords(String s) {
if (s.isEmpty()) return 0;
if (s.indexOf(" ") == -1) return 1;
return 1 + countWords(s.substring(s.indexOf(" ") + 1));
}
For multiple blanks between words you can check for a blank and skip past it:
public static int countWords(String s) {
if (s.isEmpty()) return 0;
if (s.indexOf(' ') == -1) return 1;
if (s.charAt(0) == ' ') return countWords(s.substring(1));
return 1 + countWords(s.substring(s.indexOf(' ') + 1));
}
This should work, I think:
public static int countWords(String sen) {
int i = sen.indexOf(" ");
if (sen.isEmpty()) {
return 0;
} else if (i == -1) {
return 1;
} else return 1 + countWords(sen.substring(i + 1));
}
Some notes on what is happening:
Java naming conventions dictate you should start method names with a lower case letter
The line if (i == sen.indexOf(" ")) is redunant - you just assigned i to be that before, so it'll always evaluate to true.
And therefore, your recursion never gets called. You need to change it so that if sen isn't empty and contains at least one more space, countWords calls itself with sen minus the first word.
This method uses a String with no spaces as a base case. Then it removes everything up to and including the first space in the String and recurses.
It handles both the special case of an empty String and the case that a String passed to the method starts with a space appropriately.
public static int CountWords(String sen)
{ int i = sen.indexOf(" ");
if(sen.isEmpty()) return 0; // special case
if(i == -1) return 1; // base case
if(i != 0)
return 1 + CountWords(sen.substring(i+1));
else
return CountWords(sen.substring(1));
}
This will work -
public static int CountWords(String sen) {
if("".equals(sen)){
return 0;
}
int count = 0;
int i = sen.indexOf(" ");
String substr = sen.substring(0,i+1) ;
if (i != -1) {
count++;
}else{
if(sen.length()>0){
count++;
}
sen="";
}
//sen.substring(0,sen.indexOf(" ")-1);
return count + CountWords(sen.substring(substr.length()));
}
I need to increment a String in java from "aaaaaaaa" to "aaaaaab" to "aaaaaac" up through the alphabet, then eventually to "aaaaaaba" to "aaaaaabb" etc. etc.
Is there a trick for this?
You're basically implementing a Base 26 number system with leading "zeroes" ("a").
You do it the same way you convert a int to a base-2 or base-10 String, but instead of using 2 or 10, you use 26 and instead of '0' as your base, you use 'a'.
In Java you can easily use this:
public static String base26(int num) {
if (num < 0) {
throw new IllegalArgumentException("Only positive numbers are supported");
}
StringBuilder s = new StringBuilder("aaaaaaa");
for (int pos = 6; pos >= 0 && num > 0 ; pos--) {
char digit = (char) ('a' + num % 26);
s.setCharAt(pos, digit);
num = num / 26;
}
return s.toString();
}
The basic idea then is to not store the String, but just some counter (int an int or a long, depending on your requirements) and to convert it to the String as needed. This way you can easily increase/decrease/modify your counter without having to parse and re-create the String.
The following code uses a recursive approach to get the next string (let's say, from "aaaa" to "aaab" and so on) without the need of producing all the previous combinations, so it's rather fast and it's not limited to a given maximum string length.
public class StringInc {
public static void main(String[] args) {
System.out.println(next("aaa")); // Prints aab
System.out.println(next("abcdzz")); // Prints abceaa
System.out.println(next("zzz")); // Prints aaaa
}
public static String next(String s) {
int length = s.length();
char c = s.charAt(length - 1);
if(c == 'z')
return length > 1 ? next(s.substring(0, length - 1)) + 'a' : "aa";
return s.substring(0, length - 1) + ++c;
}
}
As some folks pointed out, this is tail recursive, so you can reformulate it replacing the recursion with a loop.
Increment the last character, and if it reaches Z, reset it to A and move to the previous characters. Repeat until you find a character that's not Z. Because Strings are immutable, I suggest using an array of characters instead to avoid allocating lots and lots of new objects.
public static void incrementString(char[] str)
{
for(int pos = str.length - 1; pos >= 0; pos--)
{
if(Character.toUpperCase(str[pos]) != 'Z')
{
str[pos]++;
break;
}
else
str[pos] = 'a';
}
}
you can use big integer's toString(radix) method like:
import java.math.BigInteger;
public class Strings {
Strings(final int digits,final int radix) {
this(digits,radix,BigInteger.ZERO);
}
Strings(final int digits,final int radix,final BigInteger number) {
this.digits=digits;
this.radix=radix;
this.number=number;
}
void addOne() {
number=number.add(BigInteger.ONE);
}
public String toString() {
String s=number.toString(radix);
while(s.length()<digits)
s='0'+s;
return s;
}
public char convert(final char c) {
if('0'<=c&&c<='9')
return (char)('a'+(c-'0'));
else if('a'<=c&&c<='p')
return (char)(c+10);
else throw new RuntimeException("more logic required for radix: "+radix);
}
public char convertInverse(final char c) {
if('a'<=c&&c<='j')
return (char)('0'+(c-'a'));
else if('k'<=c&&c<='z')
return (char)(c-10);
else throw new RuntimeException("more logic required for radix: "+radix);
}
void testFix() {
for(int i=0;i<radix;i++)
if(convert(convertInverse((char)('a'+i)))!='a'+i)
throw new RuntimeException("testFix fails for "+i);
}
public String toMyString() {
String s=toString(),t="";
for(int i=0;i<s.length();i++)
t+=convert(s.charAt(i));
return t;
}
public static void main(String[] arguments) {
Strings strings=new Strings(8,26);
strings.testFix();
System.out.println(strings.number.toString()+' '+strings+' '+strings.toMyString());
for(int i=0;i<Math.pow(strings.radix,3);i++)
try {
strings.addOne();
if(Math.abs(i-i/strings.radix*strings.radix)<2)
System.out.println(strings.number.toString()+' '+strings+' '+strings.toMyString());
} catch(Exception e) {
System.out.println(""+i+' '+strings+" failed!");
}
}
final int digits,radix;
BigInteger number;
}
I'd have to agree with #saua's approach if you only wanted the final result, but here is a slight variation on it in the case you want every result.
Note that since there are 26^8 (or 208827064576) different possible strings, I doubt you want them all. That said, my code prints them instead of storing only one in a String Builder. (Not that it really matters, though.)
public static void base26(int maxLength) {
buildWord(maxLength, "");
}
public static void buildWord(int remaining, String word)
{
if (remaining == 0)
{
System.out.println(word);
}
else
{
for (char letter = 'A'; letter <= 'Z'; ++letter)
{
buildWord(remaining-1, word + letter);
}
}
}
public static void main(String[] args)
{
base26(8);
}
I would create a character array and increment the characters individually. Strings are immutable in Java, so each change would create a new spot on the heap resulting in memory growing and growing.
With a character array, you shouldn't have that problem...
Have an array of byte that contain ascii values, and have loop that increments the far right digit while doing carry overs.
Then create the string using
public String(byte[] bytes, String charsetName)
Make sure you pass in the charset as US-ASCII or UTF-8 to be unambiguous.
Just expanding on the examples, as to Implementation, consider putting this into a Class... Each time you call toString of the Class it would return the next value:
public class Permutator {
private int permutation;
private int permutations;
private StringBuilder stringbuilder;
public Permutator(final int LETTERS) {
if (LETTERS < 1) {
throw new IllegalArgumentException("Usage: Permutator( \"1 or Greater Required\" \)");
}
this.permutation = 0;
// MAGIC NUMBER : 26 = Number of Letters in the English Alphabet
this.permutations = (int) Math.pow(26, LETTERS);
this.stringbuilder = new StringBuilder();
for (int i = 0; i < LETTERS; ++i) {
this.stringbuilder.append('a');
}
}
public String getCount() {
return String.format("Permutation: %s of %s Permutations.", this.permutation, this.permutations);
}
public int getPermutation() {
return this.permutation;
}
public int getPermutations() {
return this.permutations;
}
private void permutate() {
// TODO: Implement Utilising one of the Examples Posted.
}
public String toString() {
this.permutate();
return this.stringbuilder.toString();
}
}
Building on the solution by #cyberz, the following code is an example of how you could write a recursive call which can be optimized by a compiler that supports Tail Recursion.
The code is written in Groovy, since it runs on the JVM, its syntax closely resembles Java and it's compiler supports tail recursion optimization
static String next(String input) {
return doNext(input, "")
}
#TailRecursive
#CompileStatic
static String doNext(String input, String result) {
if(!self) {
return result
}
final String last = input[-1]
final String nonLast = self.substring(0, input.size()-1)
if('z' == last) {
return doNext(nonLast, (nonLast ? 'a' : 'aa') + result)
}
return doNext('', nonLast + (((last as Character) + 1) as Character).toString() + result)
}
Since none of the answers were useful to me, I wrote my own code:
/**
* Increases the given String value by one. Examples (with min 'a' and max 'z'): <p>
*
* - "aaa" -> "aab" <br>
* - "aab" -> "aac" <br>
* - "aaz" -> "aba" <br>
* - "zzz" -> "aaaa" <br>
*
* #param s
* #param min lowest char (a zero)
* #param max highest char (e.g. a 9, in a decimal system)
* #return increased String by 1
*/
public static String incString(String s, char min, char max) {
char last = s.charAt(s.length() - 1);
if (++last > max)
return s.length() > 1 ? incString(s.substring(0, s.length()-1), min, max) + min : "" + min + min;
else
return s.substring(0, s.length()-1) + last;
}
public static String incrementString(String string)
{
if(string.length()==1)
{
if(string.equals("z"))
return "aa";
else if(string.equals("Z"))
return "Aa";
else
return (char)(string.charAt(0)+1)+"";
}
if(string.charAt(string.length()-1)!='z')
{
return string.substring(0, string.length()-1)+(char)(string.charAt(string.length()-1)+1);
}
return incrementString(string.substring(0, string.length()-1))+"a";
}
Works for all standard string containing alphabets
I have approach using for loop which is fairly simple to understand. based on [answer]: https://stackoverflow.com/a/2338415/9675605 cyberz answer.
This also uses org.apache.commons.lang3.ArrayUtils. to insert letter on first position. you can create your own util for it. If someone finds helpful.
import org.apache.commons.lang3.ArrayUtils;
public class StringInc {
public static void main(String[] args) {
System.out.println(next("aaa")); // Prints aab
System.out.println(next("abcdzz")); // Prints abceaa
System.out.println(next("zzz")); // Prints aaaa
}
public static String next(String str) {
boolean increment = true;
char[] arr = str.toCharArray();
for (int i = arr.length - 1; i >= 0 && increment; i--) {
char letter = arr[i];
if (letter != 'z') {
letter++;
increment = false;
} else {
letter = 'a';
}
arr[i] = letter;
}
if (increment) {
arr = ArrayUtils.insert(0, arr, 'a');
}
return new String(arr);
}
It's not much of a "trick", but this works for 4-char strings. Obviously it gets uglier for longer strings, but the idea is the same.
char array[] = new char[4];
for (char c0 = 'a'; c0 <= 'z'; c0++) {
array[0] = c0;
for (char c1 = 'a'; c1 <= 'z'; c1++) {
array[1] = c1;
for (char c2 = 'a'; c2 <= 'z'; c2++) {
array[2] = c2;
for (char c3 = 'a'; c3 <= 'z'; c3++) {
array[3] = c3;
String s = new String(array);
System.out.println(s);
}
}
}
}