Recursively decompressing a String - java

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);
}

Related

Palindrome in java

Here what I tried
sample input is "aabaa"
eg: in if condition val[0] = a[4]
if it is equal i stored it in counter variable if it is half of the length it original string it is palindrome
if it is not it is not a palindrome
I tried with my basic knowledge in java if there is any errors let me know
boolean solution(String inputString) {
int val = inputString.length();
int count = 0;
for (int i = 0; i<inputString.length(); i++) {
if(inputString.charAt(i) == inputString.charAt(val-i)) {
count = count++;
if (count>0) {
return true;
}
}
}
return true;
}
How about
public boolean isPalindrome(String text) {
String clean = text.replaceAll("\\s+", "").toLowerCase();
int length = clean.length();
int forward = 0;
int backward = length - 1;
while (backward > forward) {
char forwardChar = clean.charAt(forward++);
char backwardChar = clean.charAt(backward--);
if (forwardChar != backwardChar)
return false;
}
return true;
}
From here
In your version you compare first element with last, second with second last etc.
last element in this case is inputString.length()-1(so need to use 'inputString.charAt(val-i-1)' . If you iterate till end, then the count should be equal to length of the string.
for(int i = 0; i<inputString.length(); i++){
if(inputString.charAt(i) == inputString.charAt(val-i-1)){
count ++;
}
}
return (count==val); //true when count=val
Or alternatlively iterate till the mid point of the array, then count value is val/2.
for(int i = 0; i<inputString.length()/2; i++){
if(inputString.charAt(i) == inputString.charAt(val-i-1)){
count ++;
}
}
return (count==val/2); //true when count=val/2
There's no constraints in the question so let me throw in a more cheesy solution.
boolean isPalindrome(String in)
final String inl = in.toLowerCase();
return new StringBuilder(inl).reverse().toString().equals(inl);
}
A palindrome is a word, sentence, verse, or even a number that reads the same forward and backward. In this java solution, we’ll see how to figure out whether the number or the string is palindrome in nature or not.
Method - 1
class Main {
public static void main(String[] args) {
String str = "Nitin", revStr = "";
int strLen = str.length();
for (int i = (strLen - 1); i >=0; --i) {
revStr = revStr + str.charAt(i);
}
if (str.toLowerCase().equals(revStr.toLowerCase())) {
System.out.println(str + " is a Palindrome String.");
}
else {
System.out.println(str + " is not a Palindrome String.");
}
Method - 2
class Main {
public static void main(String[] args) {
int n = 3553, revNum = 0, rem;
// store the number to the original number
int orgNum = n;
/* get the reverse of original number
store it in variable */
while (n != 0) {
remainder = n % 10;
revNum = revNum * 10 + rem;
n /= 10;
}
// check if reversed number and original number are equal
if (orgNum == revNum) {
System.out.println(orgNum + " is Palindrome.");
}
else {
System.out.println(orgNum + " is not Palindrome.");
}

Shortening the representation of a string by adding the number of consecutive characters

Given a random character string not including (0-9), I need to shorten the representation of that string by adding the number of consecutive characters. For e.g: ggee will result in g2e2 being displayed.
I managed to implement the program and tested it (works correctly) through various inputs. I have run into the issue where I cannot seem to understand how the character "e" is displayed given the input above.
I have traced my code multiple times but I don't see when/how "e" is displayed when "i" is 2/3.
String input = new String("ggee");
char position = input.charAt(0);
int accumulator = 1;
for (int i = 1; i < input.length(); i++)
{
// Correction. Was boolean lastIndexString = input.charAt(i) == (input.charAt(input.length() - 1));
boolean lastIndexString = i == (input.length() - 1);
if (position == input.charAt(i))
{
accumulator++;
if (lastIndexOfString)
System.out.print(accumulator); // In my mind, I should be printing
// (input.charAt(i) + "" + accumulator); here
}
else //(position != input.charAt(i))
{
if (accumulator > 1)
{
System.out.print(position + "" + accumulator);
}
else
{
System.out.print(position + "");
}
position = input.charAt(i);
accumulator = 1;
if (lastIndexOfString)
System.out.print(input.charAt(i)); // This is always printing when
// I am at the last index of my string,
// even ignoring my condition of
// (position == input.charAt(i))
}
}
In Java 9+, using regular expression to find consecutive characters, the following will do it:
static String shorten(String input) {
return Pattern.compile("(.)\\1+").matcher(input)
.replaceAll(r -> r.group(1) + r.group().length());
}
Test
System.out.println(shorten("ggggeecaaaaaaaaaaaa"));
System.out.println(shorten("ggggee😀😀😀😁😁😁😁"));
Output
g4e2ca12
g4e2😀6😁8
However, as you can see, that code doesn't work if input string contains Unicode characters from the supplemental planes, such as Emoji characters.
Small modification will fix that:
static String shorten(String input) {
return Pattern.compile("(.)\\1+").matcher(input)
.replaceAll(r -> r.group(1) + r.group().codePointCount(0, r.group().length()));
}
Or:
static String shorten(String input) {
return Pattern.compile("(.)\\1+").matcher(input)
.replaceAll(r -> r.group(1) + input.codePointCount(r.start(), r.end()));
}
Output
g4e2ca12
g4e2😀3😁4
Basically you want each char with no of repeats.
*******************************************************************************/
public class Main
{
public static void main(String[] args) {
String s="ggggggeee";
StringBuilder s1=new
StringBuilder("") ;
;
for(int i=0;i<s.length();i++)
{
int count=0,j;
for( j=i+1;j<s.length();j++)
{
if(s.charAt(i)==s.charAt(j))
count++;
else
{
break;}
}
i=j-1;
s1=s1.append(s.charAt(i)+""+(count+1));
}
System.out.print(s1);
}}
Output

Replace nested string with some rules

There are 3 rules in the string:
It contains either word or group (enclosed by parentheses), and group can be nested;
If there is a space between word or group, those words or groups should append with "+".
For example:
"a b" needs to be "+a +b"
"a (b c)" needs to be "+a +(+b +c)"
If there is a | between word or group, those words or groups should be surround with parentheses.
For example:
"a|b" needs to be "(a b)"
"a|b|c" needs to be "(a b c)"
Consider all the rules, here is another example:
"aa|bb|(cc|(ff gg)) hh" needs to be "+(aa bb (cc (+ff +gg))) +hh"
I have tried to use regex, stack and recursive descent parser logic, but still cannot fully solve the problem.
Could anyone please share the logic or pseudo code on this problem?
New edited:
One more important rule: vertical bar has higher precedence.
For example:
aa|bb hh cc|dd (a|b) needs to be +(aa bb) +hh +(cc dd) +((a b))
(aa dd)|bb|cc (ee ff)|(gg hh) needs to be +((+aa +dd) bb cc) +((+ee +ff) (+gg +hh))
New edited:
To solve the precedence problem, I find a way to add the parentheses before calling Sunil Dabburi's methods.
For example:
aa|bb hh cc|dd (a|b) will be (aa|bb) hh (cc|dd) (a|b)
(aa dd)|bb|cc (ee ff)|(gg hh) will be ((aa dd)|bb|cc) ((ee ff)|(gg hh))
Since the performance is not a big concern to my application, this way at least make it work for me. I guess the JavaCC tool may solve this problem beautifully. Hope someone else can continue to discuss and contribute this problem.
Here is my attempt. Based on your examples and a few that I came up with I believe it is correct under the rules. I solved this by breaking the problem up into 2 parts.
Solving the case where I assume the string only contains words or is a group with only words.
Solving words and groups by substituting child groups out, use the 1) part and recursively repeating 2) with the child groups.
private String transformString(String input) {
Stack<Pair<Integer, String>> childParams = new Stack<>();
String parsedInput = input;
int nextInt = Integer.MAX_VALUE;
Pattern pattern = Pattern.compile("\\((\\w|\\|| )+\\)");
Matcher matcher = pattern.matcher(parsedInput);
while (matcher.find()) {
nextInt--;
parsedInput = matcher.replaceFirst(String.valueOf(nextInt));
String childParam = matcher.group();
childParams.add(Pair.of(nextInt, childParam));
matcher = pattern.matcher(parsedInput);
}
parsedInput = transformBasic(parsedInput);
while (!childParams.empty()) {
Pair<Integer, String> childGroup = childParams.pop();
parsedInput = parsedInput.replace(childGroup.fst.toString(), transformBasic(childGroup.snd));
}
return parsedInput;
}
// Transform basic only handles strings that contain words. This allows us to simplify the problem
// and not have to worry about child groups or nested groups.
private String transformBasic(String input) {
String transformedBasic = input;
if (input.startsWith("(")) {
transformedBasic = input.substring(1, input.length() - 1);
}
// Append + in front of each word if there are multiple words.
if (transformedBasic.contains(" ")) {
transformedBasic = transformedBasic.replaceAll("( )|^", "$1+");
}
// Surround all words containing | with parenthesis.
transformedBasic = transformedBasic.replaceAll("([\\w]+\\|[\\w|]*[\\w]+)", "($1)");
// Replace pipes with spaces.
transformedBasic = transformedBasic.replace("|", " ");
if (input.startsWith("(") && !transformedBasic.startsWith("(")) {
transformedBasic = "(" + transformedBasic + ")";
}
return transformedBasic;
}
Verified with the following test cases:
#ParameterizedTest
#CsvSource({
"a b,+a +b",
"a (b c),+a +(+b +c)",
"a|b,(a b)",
"a|b|c,(a b c)",
"aa|bb|(cc|(ff gg)) hh,+(aa bb (cc (+ff +gg))) +hh",
"(aa(bb(cc|ee)|ff) gg),(+aa(bb(cc ee) ff) +gg)",
"(a b),(+a +b)",
"(a(c|d) b),(+a(c d) +b)",
"bb(cc|ee),bb(cc ee)",
"((a|b) (a b)|b (c|d)|e),(+(a b) +((+a +b) b) +((c d) e))"
})
void testTransformString(String input, String output) {
Assertions.assertEquals(output, transformString(input));
}
#ParameterizedTest
#CsvSource({
"a b,+a +b",
"a b c,+a +b +c",
"a|b,(a b)",
"(a b),(+a +b)",
"(a|b),(a b)",
"a|b|c,(a b c)",
"(aa|bb cc|dd),(+(aa bb) +(cc dd))",
"(aa|bb|ee cc|dd),(+(aa bb ee) +(cc dd))",
"aa|bb|cc|ff gg hh,+(aa bb cc ff) +gg +hh"
})
void testTransformBasic(String input, String output) {
Assertions.assertEquals(output, transformBasic(input));
}
I tried to solve the problem. Not sure if it works in all cases. Verified with the inputs given in the question and it worked fine.
We need to format the pipes first. That will help add necessary parentheses and spacing.
The spaces generated as part of pipe processing can interfere with actual spaces that are available in our expression. So used $ symbol to mask them.
To process spaces, its tricky as parantheses need to be processed individually. So the approach I am following is to find a set of parantheses starting from outside and going inside.
So typically we have <left_part><parantheses_code><right_part>. Now left_part can be empty, similary right_part can be empty. we need to handle such cases.
Also, if the right_part starts with a space, we need to add '+' to left_part as per space requirement.
NOTE: I am not sure what's expected of (a|b). If the result should be ((a b)) or (a b). I am going with ((a b)) purely by the definition of it.
Now here is the working code:
public class Test {
public static void main(String[] args) {
String input = "aa|bb hh cc|dd (a|b)";
String result = formatSpaces(formatPipes(input)).replaceAll("\\$", " ");
System.out.println(result);
}
private static String formatPipes(String input) {
while (true) {
char[] chars = input.toCharArray();
int pIndex = input.indexOf("|");
if (pIndex == -1) {
return input;
}
input = input.substring(0, pIndex) + '$' + input.substring(pIndex + 1);
int first = pIndex - 1;
int closeParenthesesCount = 0;
while (first >= 0) {
if (chars[first] == ')') {
closeParenthesesCount++;
}
if (chars[first] == '(') {
if (closeParenthesesCount > 0) {
closeParenthesesCount--;
}
}
if (chars[first] == ' ') {
if (closeParenthesesCount == 0) {
break;
}
}
first--;
}
String result;
if (first > 0) {
result = input.substring(0, first + 1) + "(";
} else {
result = "(";
}
int last = pIndex + 1;
int openParenthesesCount = 0;
while (last <= input.length() - 1) {
if (chars[last] == '(') {
openParenthesesCount++;
}
if (chars[last] == ')') {
if (openParenthesesCount > 0) {
openParenthesesCount--;
}
}
if (chars[last] == ' ') {
if (openParenthesesCount == 0) {
break;
}
}
last++;
}
if (last >= input.length() - 1) {
result = result + input.substring(first + 1) + ")";
} else {
result = result + input.substring(first + 1, last) + ")" + input.substring(last);
}
input = result;
}
}
private static String formatSpaces(String input) {
if (input.isEmpty()) {
return "";
}
int startIndex = input.indexOf("(");
if (startIndex == -1) {
if (input.contains(" ")) {
String result = input.replaceAll(" ", " +");
if (!result.trim().startsWith("+")) {
result = '+' + result;
}
return result;
} else {
return input;
}
}
int endIndex = startIndex + matchingCloseParenthesesIndex(input.substring(startIndex));
if (endIndex == -1) {
System.out.println("Invalid input!!!");
return "";
}
String first = "";
String last = "";
if (startIndex > 0) {
first = input.substring(0, startIndex);
}
if (endIndex < input.length() - 1) {
last = input.substring(endIndex + 1);
}
String result = formatSpaces(first);
String parenthesesStr = input.substring(startIndex + 1, endIndex);
if (last.startsWith(" ") && first.isEmpty()) {
result = result + "+";
}
result = result + "("
+ formatSpaces(parenthesesStr)
+ ")"
+ formatSpaces(last);
return result;
}
private static int matchingCloseParenthesesIndex(String input) {
int counter = 1;
char[] chars = input.toCharArray();
for (int i = 1; i < chars.length; i++) {
char ch = chars[i];
if (ch == '(') {
counter++;
} else if (ch == ')') {
counter--;
}
if (counter == 0) {
return i;
}
}
return -1;
}
}

How do I convert a number to a letter in Java?

Is there a nicer way of converting a number to its alphabetic equivalent than this?
private String getCharForNumber(int i) {
char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
if (i > 25) {
return null;
}
return Character.toString(alphabet[i]);
}
Maybe something than can deal with numbers greater than 26 more elegantly too?
Just make use of the ASCII representation.
private String getCharForNumber(int i) {
return i > 0 && i < 27 ? String.valueOf((char)(i + 64)) : null;
}
Note: This assumes that i is between 1 and 26 inclusive.
You'll have to change the condition to i > -1 && i < 26 and the increment to 65 if you want i to be zero-based.
Here is the full ASCII table, in case you need to refer to:
Edit:
As some folks suggested here, it's much more readable to directly use the character 'A' instead of its ASCII code.
private String getCharForNumber(int i) {
return i > 0 && i < 27 ? String.valueOf((char)(i + 'A' - 1)) : null;
}
Rather than giving an error or some sentinel value (e.g. '?') for inputs outside of 0-25, I sometimes find it useful to have a well-defined string for all integers. I like to use the following:
0 -> A
1 -> B
2 -> C
...
25 -> Z
26 -> AA
27 -> AB
28 -> AC
...
701 -> ZZ
702 -> AAA
...
This can be extended to negatives as well:
-1 -> -A
-2 -> -B
-3 -> -C
...
-26 -> -Z
-27 -> -AA
...
Java Code:
public static String toAlphabetic(int i) {
if( i<0 ) {
return "-"+toAlphabetic(-i-1);
}
int quot = i/26;
int rem = i%26;
char letter = (char)((int)'A' + rem);
if( quot == 0 ) {
return ""+letter;
} else {
return toAlphabetic(quot-1) + letter;
}
}
Python code, including the ability to use alphanumeric (base 36) or case-sensitive (base 62) alphabets:
def to_alphabetic(i,base=26):
if base < 0 or 62 < base:
raise ValueError("Invalid base")
if i < 0:
return '-'+to_alphabetic(-i-1)
quot = int(i)/base
rem = i%base
if rem < 26:
letter = chr( ord("A") + rem)
elif rem < 36:
letter = str( rem-26)
else:
letter = chr( ord("a") + rem - 36)
if quot == 0:
return letter
else:
return to_alphabetic(quot-1,base) + letter
I would return a character char instead of a string.
public static char getChar(int i) {
return i<0 || i>25 ? '?' : (char)('A' + i);
}
Note: when the character decoder doesn't recognise a character it returns ?
I would use 'A' or 'a' instead of looking up ASCII codes.
Personally, I prefer
return "ABCDEFGHIJKLMNOPQRSTUVWXYZ".substring(i, i+1);
which shares the backing char[]. Alternately, I think the next-most-readable approach is
return Character.toString((char) (i + 'A'));
which doesn't depend on remembering ASCII tables. It doesn't do validation, but if you want to, I'd prefer to write
char c = (char) (i + 'A');
return Character.isUpperCase(c) ? Character.toString(c) : null;
just to make it obvious that you're checking that it's an alphabetic character.
if you define a/A as 0
char res;
if (i>25 || i<0){
res = null;
}
res = (i) + 65
}
return res;
65 for captitals;
97 for non captitals
Getting the alphabetical value from an int can be simply done with:
(char)('#' + i)
public static String abcBase36(int i) {
char[] ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
int quot = i / 36;
int rem = i % 36;
char letter = ALPHABET[rem];
if (quot == 0) {
return "" + letter;
} else {
return abcBase36(quot - 1) + letter;
}
}
You can convert the input to base 26 (Hexavigesimal) and convert each "digit" back to base 10 individually and apply the ASCII mapping. Since A is mapped to 0, you will get results A, B, C,..., Y, Z, BA, BB, BC,...etc, which may or may not be desirable depending on your requirements for input values > 26, since it may be natural to think AA comes after Z.
public static String getCharForNumber(int i){
// return null for bad input
if(i < 0){
return null;
}
// convert to base 26
String s = Integer.toString(i, 26);
char[] characters = s.toCharArray();
String result = "";
for(char c : characters){
// convert the base 26 character back to a base 10 integer
int x = Integer.parseInt(Character.valueOf(c).toString(), 26);
// append the ASCII value to the result
result += String.valueOf((char)(x + 'A'));
}
return result;
}
public static string IntToLetters(int value)
{
string result = string.Empty;
while (--value >= 0)
{
result = (char)('A' + value % 26 ) + result;
value /= 26;
}
return result;
}
To meet the requirement of A being 1 instead of 0, I've added -- to the while loop condition, and removed the value-- from the end of the loop, if anyone wants this to be 0 for their own purposes, you can reverse the changes, or simply add value++; at the beginning of the entire method.
Another variant:
private String getCharForNumber(int i) {
if (i > 25 || i < 0) {
return null;
}
return new Character((char) (i + 65)).toString();
}
This isn't exactly an answer, but some useful/related code I made. When you run it and enter any character in the command line it returns getNumericValue(char) ... which doesn't seem to be the same as the ASCII table so be aware. Anyways, not a direct answer to your question but hopefully helpful:
import java.lang.*;
import java.util.*;
/* charVal.java
*/
//infinite loops. whenever you type in a character gives you value of
//getNumericValue(char)
//
//ctrl+c to exit
public class charVal {
public static void main(String[] args) {
Scanner inPut = new Scanner(System.in);
for(;;){
char c = inPut.next().charAt(0);
System.out.printf("\n %s = %d \n", c, Character.getNumericValue(c));
}
}
}
Another approach starting from 0 and returning a String
public static String getCharForNumber(int i) {
return i < 0 || i > 25 ? "?" : String.valueOf((char) ('A' + i));
}
You can try like this:
private String getCharForNumber(int i) {
CharSequence css = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (i > 25) {
return null;
}
return css.charAt(i) + "";
}
public static void main(String[] args)
{
int rem,n=702,quo;
String s=" ";
while(n>0)
{
rem=(n-1)%26;
quo=(n-1)/26;
s=(char)(rem+97)+s;
if(quo==1)
{
s=(char)(97)+s;
break;
}
else
n=(n-1)/26;
}
System.out.print(s);
}
}
////We can also write the code like the below one. There is no much difference but it may help to understand the concept for some people.
public static void main(String[] args)
{
int rem,n=52,quo;
String s=" ";
while(n>0)
{
rem=n%26;
quo=n/26;
if(rem==0)
rem=26;
s=(char)(rem+96)+s;
if((quo==1 || quo==0) && n>26)
{
n=n/26;
s=(char)(n+96)+s;
break;
}
else
n=n/26-1;
}
System.out.print(s);
}
for(int i=0;i<ar.length();i++) {
char ch = ar.charAt(i);
System.out.println((char)(ch+16));;
}
The accepted answer best describes the solution. Nevertheless, it does not handle the case when you want to keep numbering over the value 27 like aa, ab, ...az, aaa, aab....
For doing so I achieved with the following:
protected String getAlphaNumber(int intValue) {
if (intValue == 0) {
return "";
}
intValue = Math.abs(intValue);
String prefix = "";
int charPosition = intValue % 26;
int blocks = intValue / 26;
if (charPosition == 0) { //the last letter, "z" (26)
blocks--;
charPosition = 26;
}
for (int i = 0; i < blocks; i++) {
prefix += "a";
}
return prefix + ((char) (charPosition + 96)); // "a"-"z" chars are located in the 97-122 indexes of the ASCII table, so shift all 96 positions.
}
import java.util.*;
class Integer2Letter
{
void main()
{
Scanner ob=new Scanner(System.in);
int n;
System.out.println("Enter an Integer");
n=ob.nextInt();//INPUT IN INTEGER FORMAT
if(n>0 && n<27)//RANGE CHECK
{
char ch= (char)(n+64);//IF N=1 THAN 64+1=65 WHICH EQUAL TO THE ASCII VALUE OF 'A'
System.out.println("the corresponding letter is="+ch);
}
else
{
System.out.println("Please enter the correct range");
}
}
}

How to increment a java String through all the possibilities?

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);
}
}
}
}

Categories

Resources