Java - insert "-" between contiguous digits in string - java

I am trying to create new string by inserting "-" between contiguous numbers in a string, for e.g if the input string is "bea345ful" the output string should be like "bea3-4-5ful" but if input string is "be3u4t5ful" I don't need to insert "-" since none of the digits are contiguous.
I am able to make it work with following code but it fails when there are contiguous digits at end of string for e.g. "be3u4t5f67" in that case it throws StringIndexOutOfBoundsException which I understand is happening because my code is not handling this condition. Any suggestions how to fix it?
public static String insertDash(String str){
String result = "";
for (int i = 0; i < str.length(); i ++) {
if (Character.isDigit(str.charAt(i)) && Character.isDigit(str.charAt(i + 1))) {
result+=str.charAt(i) + "-";
} else {
result+=str.charAt(i);
}
} return result;

The stop condition of your loop should be i < str.length() - 1.
Without the change, at the last iteration, i is equal to str.length() - 1 and therefore accessing the element at index str.length() - 1 + 1 (with str.charAt(i + 1)) triggers the exception.
After the for loop, simply append the last character to result.

Related

Recursion: Longest Palindrome Substring

This is a very common problem in which we would have to find the longest substring which is also a palindrome substring for the given input string.
Now there are multiple possible approaches to this and I am aware about Dynamic programming solution, expand from middle etc. All these solutions should be used for any practical usecase.
I was experimenting with using recursion to solve this problem and trying to implement the simple idea.
Let us assume that s is the given input string and i and j represent any valid character indexes of input string. So if s[i] == s[j], my longest substring would be:
s.charAt(i) + longestSubstring(s, i + 1, j - 1) + s.charAt(j)
And if these two characters are not equal then:
max of longestSubstring(s, i + 1, j) or longestSubstring(s, i, j - 1)
I tried to implement this solution below:
// end is inclusive
private static String longestPalindromeHelper(String s, int start, int end) {
if (start > end) {
return "";
} else if (start == end) {
return s.substring(start, end + 1);
}
// if the character at start is equal to end
if (s.charAt(start) == s.charAt(end)) {
// I can concatenate the start and end characters to my result string
// plus I can concatenate the longest palindrome in start + 1 to end - 1
// now logically this makes sense to me, but this would fail in the case
// for ex: a a c a b d k a c a a (space added for visualization)
// when start = 3 (a character)
// end = 7 (again end character)
// it will go in recursion with start = 4 and end = 6 from now onwards
// there is no palindrome substrings apart from the single character
// substring (which are palindrome by itself) so recursion tree for
// start = 3 and end = 7 would return any single character from b d k
// let's say it returns b so result would be a a c a b a c a a
// this would be correct answer for longest palindrome subsequence but
// not substring because for sub strings I need to have consecutive
// characters
return s.charAt(start)
+ longestPalindromeHelper(s, start + 1, end - 1) + s.charAt(end);
} else {
// characters are not equal, increment start
String s1 = longestPalindromeHelper(s, start + 1, end);
String s2 = longestPalindromeHelper(s, start, end - 1);
return s1.length() > s2.length() ? s1 : s2;
}
}
public static String longestPalindrome(String s) {
return longestPalindromeHelper(s, 0, s.length() - 1);
}
public static void main(String[] args) throws Exception {
String ans = longestPalindrome("aacabdkacaa");
System.out.println("Answer => " + ans);
}
For a moment let us forgot about time complexity or runtime. I am focused towards making it work for simple case above.
As you can see in the comments I got the idea why this is failing but I tried hard to rectify the problem following the exactly same approach. I don't want to use loops here.
What could be the possible fix for this following same approach?
Note: I am interested in the actual string as answer and not the length. FYI I had a look at all the other questions and it seems no one is following this approach for correctness so I am trying.
Once you have a call wherein s[i] == s[j], you could flip a boolean flag or switch to a modified method that communicates to child calls that they can no longer use the "don't match, try i + 1 and j - 1" branch (else condition). This ensures you're looking at substrings, not subsequences, for the remainder of the recursion.
Secondly, for the substring variant, even if s[i] == s[j], you should also try i + 1 and j - 1 as if these characters didn't match, because one or both of these characters might not be part of the final best substring between i and j. In the subsequence version, there's never any reason not to add any matching characters to the current palindromic subsequence for the range i to j, but that's not always the case with substrings.
For example, given input "aabcbda" and we're at a call frame where i = 1 and j = length - 1, we need to maximize over three possibilities:
The best substring includes both 'a' characters. Call the subroutine with the flag that says we have to consume from both ends on down and can no longer try skipping characters.
The best substring might still include s[i] but not s[j], try j - 1.
The best substring might still include s[j] but not s[i], try i + 1.
Another observation: it might make more sense to pass best indices up the helper call chain, then grab the longest palindromic substring based on these indices at the very end in the wrapper function.
On a similar note, if you're struggling, you might simplify the problem and return the longest palindromic substring length using your recursive method, then switch to getting the actual substring itself. This makes it easier to focus on the subsequence logic without the return value complicating things as much.
It is much easier to use loops here, rather than recursion, something like this:
public static void main(String[] args) {
System.out.println(longestPalindrome("abbqa")); // bb
System.out.println(longestPalindrome("aacabdkacaa")); // aca
System.out.println(longestPalindrome("aacabdkaccaa")); // acca
}
public static String longestPalindrome(String str) {
String palindrome = "";
for (int i = 0; i < str.length(); i++) {
for (int j = i; j < str.length(); j++) {
String substring = str.substring(i, j);
if (isPalindrome(substring)
&& substring.length() > palindrome.length()) {
palindrome = substring;
}
}
}
return palindrome;
}
public static boolean isPalindrome(String str) {
for (int i = 0; i < str.length() / 2; i++) {
if (str.charAt(i) != str.charAt(str.length() - i - 1)) {
return false;
}
}
return true;
}

Java : Index out of bound exception when creating a string with no matching consecutive characters

This is my function which takes a string as input for example aabbaaa. I am deleting the character if the next one to it is the same. In this way I am removing consecutive occurrences of a character i.e the string will become aba. But it is throwing me indexoutofbounds exception.
static int alternatingCharacters(String s)
{
StringBuilder sb = new StringBuilder(s);
try
{
for(int i = 0; i < sb.length(); i++)
{
while (sb.charAt(i) == sb.charAt(i+1) && i+1<sb.length())
{
sb=sb.deleteCharAt(i);
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
return 0;
System.out.println(sb);
}
Irrespective of the exception, this is a very inefficient way to delete chars from the string.
Every time you invoke sb.deleteCharAt(i), it has to shift all of the characters to the right of i along by 1. In the worst case, this has quadratic time complexity.
Instead, it is much more efficient simply to move the characters, and then trim the end:
StringBuilder sb = new StringBuilder(s);
if (!s.isEmpty()) {
int len = 1;
for (int i = 1; i < sb.length(); ++i) {
if (sb.charAt(i) != sb.charAt(len - 1)) {
sb.setCharAt(len++, sb.charAt(i));
}
}
sb.setLength(len);
}
This has linear time complexity.
You can do it a little more directly, too, by operating directly on a char[]:
if (!s.isEmpty()) {
char[] cs = s.toCharArray();
int len = 1; // Start at 1, since the first character isn't equal to the one before it.
for (int i = 1; i < cs.length; ++i) {
if (cs[i] != cs[len-1]) {
cs[len++] = cs[i];
}
}
s = new String(cs, len);
}
while (sb.charAt(i) == sb.charAt(i+1) && i+1<sb.length())
In this line, sb.charAt(i) == sb.charAt(i+1) is evaluated before i+1<sb.length(), which means that you check that a following character exists only after you try to retrieve it.
Swap the two conditions, so that the check is performed before.
The index goes out of bounds because of the i+1
The for(int i = 0; i < sb.length(); i++) makes i vary from 0 to length - 1 due to the less than symbol.
This is correct because a String or N characters will start at index 0 and finish at index N-1.
When you do i+1 in the for loop, when it reaches the last character at index i, i+1 goes out of the character array bounds.
Your problem, as mentioned in the comments, is the while loop - so you should first check i + 1 < sb.length() and then check sb.charAt(i) == sb.charAt(i + 1).
Also - two other things:
Remove the println statement as this makes it not compile
No point returning an int (and hardcoded to 0), so change it to String
Example:
static String alternatingCharacters(String s) {
StringBuilder sb = new StringBuilder(s);
try {
for (int i = 0; i < sb.length(); i++) {
while (i + 1 < sb.length() && sb.charAt(i) == sb.charAt(i + 1)) {
sb = sb.deleteCharAt(i);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
Online Demo
Your problem is that you are iterating till sb.length() and then inside the loop in the while condition you are using :
while (sb.charAt(i) == sb.charAt(i+1) && i+1<sb.length())
And the sentence sb.charAt(i+1) is what icauses the IndexOutOfBoundException because there's no such index in the string.
When the loop reaches the last element, you call sb.charAt(i+1) in the while which is placed before i+1<sb.length() so it will be always executed.
What you need to do is to swap the two conditions in the while loop: while(i+1<sb.length() && sb.charAt(i) == sb.charAt(i+1)).
Index out of bounds is generally caused when you are referencing an index that doesn't exist. Also remember that the index count starts from 0 not 1. On the last loop sb.charAt(i+1) would be 7 + 1 = 8, which doesn't exist since your upper boundary is sb.Length(), to fix this just make your upper boundary for(int i = 0; i < sb.length() - 1; i++)
Loop and delete will cause certainly IndexOutOfBoundsException
StringBuilder sb = new StringBuilder("hello"); // length is 5
sb.deleteCharAt(2); // length is 4
And you still iterate until reaching 5, this will cause the exception
You can use Regex to build a clean solution:
"aaabbcccc".replaceAll("([a-z])\\1{1,}", "$1"); // the result will be abc

Java - Adding Asterisks between a user inputted string

I'm working on a class assignment with a few individual parts, which I have all done with the exception of this one. I need to get a string input from the user and create a loop (preferably a for loop) that inserts asterisks between each character. I'm completely stumped on this one so if someone could just give me some help to get started it would be appreciated.
Edit: I've come up with this so far
} else if (choice.equalsIgnoreCase("C")) {
System.out.print("Enter text here: ");
String orig = input.nextLine();
// To use for asterisk insertion
int x = 1;
int y = 2;
for (int length = orig.length(); length > 0;) {
orig = orig.substring(0,x) + "*" + orig.substring(y);
x = x + 2;
y = y + 2;
}
}
It compiles just fine but when I test it and enter some text it comes up with
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 5
You could use a for loop on the characters of the String (see below), but I would just do this:
str = str.replaceAll("(?<=.)(?=.)", "*");
The regex in the search parameter matches the point between any two characters, achieved by using a look-behind and a look-ahead, each asserting that there's a character there.
If you must use a loop, the simplest code is probably:
String result = input.isEmpty() ? "" : input.substring(0, 1);
for (int i = 1; i < input.length(); i++)
result += "*" + input.charAt(i);
The somewhat complicated first line caters for the edge case of the user entering a blank. The for loop already caters for blank input, because the terminating condition will always be false for blank, so it won't iterate at all.

Find all substrings of a string - StringIndexOutOfBoundsException

I created class Word. Word has a constructor that takes a string argument and one method getSubstrings which returns a String containing all substring of word, sorted by length.
For example, if the user provides the input "rum", the method returns a
string that will print like this:
r
u
m
ru
um
rum
I want to concatenate the substrings in a String, separating them with a newline ("\n"). Then return the string.
Code:
public class Word {
String word;
public Word(String word) {
this.word = word;
}
/**
* Gets all the substrings of this Word.
* #return all substrings of this Word separated by newline
*/
public String getSubstrings()
{
String str = "";
int i, j;
for (i = 0; i < word.length(); i++) {
for (j = 0; j < word.length(); j++) {
str = word.substring(i, i + j);
str += "\n";
}
}
return str;
}
But it throws exception:
java.lang.StringIndexOutOfBoundsException: String index out of range: -1
at java.lang.String.substring(String.java:1911)
I stuck at this point. Maybe, you have other suggestions according this method signature public String getSubstrings().
How to solve this issue?
Analysis of Exception:
From Java7 Docs of StringIndexOutOfBoundsException
public class StringIndexOutOfBoundsException extends IndexOutOfBoundsException
Thrown by String methods to indicate that an index is either negative or greater than the size of the string.
From Java 7 Docs of substring
public String substring(int beginIndex,int endIndex)
Returns a new string that is a substring of this string. The substring begins at the specified beginIndex and extends to the character at index endIndex - 1. Thus the length of the substring is endIndex-beginIndex.
I guess this: length of the substring is endIndex-beginIndex comes into String index out of range: -1. I have tested with multiple cases holding my assumption true but appreciate any other proof.
For -1: "rum".substring(2,1); will give you String index out of range: -1
Parameters:
beginIndex - the beginning index, inclusive.
endIndex - the ending index, exclusive.
Cause of StringIndexOutOfBoundsException:
In the given code snippet, substring is trying to fetch string which has endIndex more than the total length of String (i+j will exceed the total length of string):
str = word.substring(i, i + j);
Consider the case when i=2 and j=2 for word "rum"
then str=word.substring(2, 4);
would not be possible
Solution similar to code snippet given in Question:
This should solve the problem:
public String getSubstrings()
{
String str="",substr = "";
for (int i = 0; i < word.length(); i++) {
for (int j = 0; i+j <= word.length(); j++) { //added i+j and equal to comparison
substr = word.substring(j, i + j); //changed word.substring(i, i + j) to word.substring(j, i + j)
if("".equals(substr))continue; //removing empty substrings
str += substr; //added concatenation + operation
str += "\n";
}
}
return str+word;
}
Test Case:
For word="rum", this will give output:
r
u
m
ru
um
rum
Your logic seems convoluted , the source of exception:
str = word.substring(i, i + j);
Consider your i and j both equals word.length()-1 , then the substring() will fail.
You can simply do :
public String getSubstrings(String word){
StringBuilder sub= new StringBuilder();
for( int i = 0 ; i < word.length() ; i++ )
{
for( int j = 1 ; j <= word.length() - i ; j++ )
{
sub .append(word.substring(i, i+j)).append("\n");
}
}
return sub.toString();
}
Note: Consider using StringBuilder instead of String if you will do lots of concatenation on String.
I realize I'm a little late to this party, and I'm a very new programmer, myself -- but I was running into the same error last night while trying to write a similar method.
For me, it helped to rename the counter variables of the nested for loops to names that described what they are keeping track of. For the outer loop, I used int subLength, and for the inner loop, I used int position (starting position). I'm sure there are other ways of doing this, but I was happy with my solution. Here is some pseudocode that I hope will help someone else who looks this question up:
for each possible substring length 1 up to and including the original word length:
generate substrings starting at the 0th position, and then starting at each
proceeding letter up to but not including (word.length() - (subLength - 1))

Why am I getting java.lang.StringIndexOutOfBoundsException?

I want to write a program that prints words incrementally until a complete sentence appears. For example : I need to write (input), and output:
I
I need
I need to
I need to write.
Here is my code:
public static void main(String[] args) {
String sentence = "I need to write.";
int len = sentence.length();
int numSpace=0;
System.out.println(sentence);
System.out.println(len);
for(int k=0; k<len; k++){
if(sentence.charAt(k)!='\t')
continue;
numSpace++;
}
System.out.println("Found "+numSpace +"\t in the string.");
int n=1;
for (int m = 1; m <=3; m++) {
n=sentence.indexOf('\t',n-1);
System.out.println("ligne"+m+sentence.substring(0, n));
}
}
and this is what I get:
I need to write.
16
Found 0 in the string.
Exception in thread "main" java.lang.StringIndexOutOfBoundsException:
String index out of range: -1 at
java.lang.String.substring(String.java:1937) at
split1.Split1.main(Split1.java:36) Java Result: 1 BUILD SUCCESSFUL
(total time: 0 seconds)
I don't understand why numSpace doesn't count the occurrences of spaces, nor why I don't get the correct output (even if I replace numSpace by 3 for example).
You don't have a \t character, so indexOf(..) returns -1
You try a substring from 0 to -1 - fails
The solution is to check:
if (n > -1) {
System.out.prinltn(...);
}
Your loop looking for numSpace is incorrect. You are looking for a \t which is a tab character, of which there are none in the string.
Further, when you loop in the bottom, you get an exception because you are trying to parse by that same\t, which will again return no results. The value of n in n=sentence.indexOf('\t',n-1); is going to return -1 which means "there is not last index of what you are looking for". Then you try to get an actual substring with the value of -1 which is an invalid substring, so you get an exception.
You are mistaken by the concept of \t which is an escape sequence for a horizontal tab and not for a whitespace character (space). Searching for ' ' would do the trick and find the whitespaces in your sentence.
This looks like homework, so my answer is a hint.
Hint: read the javadoc for String.indexOf paying attention to what it says about the value returned when the string / character is not found.
(In fact - even if this is not formal homework, you are clearly a Java beginner. And beginners need to learn that the javadocs are the first place to look when using an unfamiliar method.)
The easiest way to solve this I guess would be to split the String first by using the function String.split. Something like this:
static void sentence(String snt) {
String[] split = snt.split(" ");
for (int i = 0; i < split.length; i++) {
for (int j = 0; j <= i; j++) {
if (i == 1 && j == 0) System.out.print(split[j]);
else System.out.printf(" %s", split[j]);
}
}
}
As other people pointed out. You are counting every characters except tabs(\t) as a space. You need to check for spaces by
if (sentence.charAt(k) == ' ')
\t represents a tab. To look for a space, just use ' '.
.indexOf() returns -1 if it can't find a character in the string. So we keep looping until .indexOf() returns -1.
Use of continue wasn't really needed here. We increment numSpaces when we encounter a space.
System.out.format is useful when we want to mix literal strings and variables. No ugly +s needed.
String sentence = "I need to write.";
int len = sentence.length();
int numSpace = 0;
for (int k = 0; k < len; k++) {
if (sentence.charAt(k) == ' ') {
numSpace++;
}
}
System.out.format("Found %s in the string.\n", numSpace);
int index = sentence.indexOf(' ');
while(index > -1) {
System.out.println(sentence.substring(0, index));
index = sentence.indexOf(' ', index + 1);
}
System.out.println(sentence);
}
Try this, it should pretty much do what you want. I figure you have already finished this so I just made the code real fast. Read the comments for the reasons behind the code.
public static void main(String[] args) {
String sentence = "I need to write.";
int len = sentence.length();
String[] broken = sentence.split(" "); //Doing this instead of the counting of characters is just easier...
/*
* The split method makes it where it populates the array based on either side of a " "
* (blank space) so at the array index of 0 would be 'I' at 1 would be "need", etc.
*/
boolean done = false;
int n = 0;
while (!done) { // While done is false do the below
for (int i = 0; i <= n; i++) { //This prints out the below however many times the count of 'n' is.
/*
* The reason behind this is so that it will print just 'I' the first time when
* 'n' is 0 (because it only prints once starting at 0, which is 'I') but when 'n' is
* 1 it goes through twice making it print 2 times ('I' then 'need") and so on and so
* forth.
*/
System.out.print(broken[i] + " ");
}
System.out.println(); // Since the above method is a print this puts an '\n' (enter) moving the next prints on the next line
n++; //Makes 'n' go up so that it is larger for the next go around
if (n == broken.length) { //the '.length' portion says how many indexes there are in the array broken
/* If you don't have this then the 'while' will go on forever. basically when 'n' hits
* the same number as the amount of words in the array it stops printing.
*/
done = true;
}
}
}

Categories

Resources