What does that mean? The length of the string is too long or there is error in my code?
public class Program {
public static String flipEndChars(String s) {
if(s.charAt(0) == s.charAt(s.length())){
return "Two's a pair.";
}
else if(s.length()<3){
return "incompatible";
}
else
return s.charAt(s.length()) + s.substring(1,s.length()) + s.charAt(0);
}
}
the issue is with this part :
s.charAt(s.length())
It's trying to access a character beyond the length of your string. The indexation is zero based, so the last character of a string is always at index s.length() - 1
String.charAt(int) returns the char at the specified index, where 0 is the first character, 1 is the second character, 2 is the third, and so on.
"hello".charAt(0) returns the character h.
String.length() returns the length of the string.
"hello".length() returns 5. So if you call "hello.charAt(5)", this will get the 6th character in the String "hello", which does not exist. This will throw an IndexOutOfBoundsException.
I hope this helps.
Related
In a well know recursion isPalindrome method
public static boolean isPalindrome(String s){
if(s.length() == 0 || s.length() == 1)
return true;
if(s.charAt(0) == s.charAt(s.length()-1))
return isPalindrome(s.substring(1, s.length()-1));
return false;
}
}
there is one line that I dont quite understand. If, for example we pass the string anna to the isPalindrome method, what does this line of code
return isPalindrome(s.substring(1, s.length()-1));
do to the string when s has a value of nn ?
In my understanding number 1 (index 1) is for second letter n, and s.length()-1 is equal 2-1 = 1, but not including that index position, so that must be index 0 ??
Does it return an empty string or something else ?
When the value of s is nn, as we step through the statements, this will happen:
s.length() is 2, so the first if condition doesn't match
s.charAt(0) is n, and s.charAt(1) is n, so the second if matches
Return the result of isPalindrome with parameter s.substring(1, 1), which is the text range from position 1 until before the position 1, in other words, an empty string
In the recursive call with empty string as input, isPalindrome will match the first condition on length, and return true
For the record, this is a very inefficient way to check a palindrome in Java,
because substring creates new strings, which is slow.
A more efficient recursive solution is possible by adding start and end index parameters, and moving them inward, until their difference becomes 0 or 1.
The return isPalindrome(s.substring(1, s.length() - 1)); will "loop" by sending the string value that you have without the first and last characters — or from the second till the second-last (a.k.a. penultimate). Then it will compare again that string; then it will "loop" again by using the same routine.
I think your "confusion" may lie in the fact that s.length() will return how many characters s have (counting naturally from 1..N); but s.substring(...) works with indexes, and they start with 0 (not at 1). In that "fashion", the last character will be the length minus one.
Example:
String example = "Five"; // ["F", "i", "v", "e"]
// 0 1 2 3 <--- indexes
// Length is four (it has 4 characters)
In java, I have a String named string with the value "A".
i.e. String string = "A";
Its size is 1 and we know that characters in a string are 0 indexed. They are represented as a Char array.
Then, why does NOT string.substring(1); give me an exception?
If you look at code of substring(int beginIndex) :
public String substring(int beginIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}
There is no condition to specify that if length is 1 and index is 1, an exception should be thrown. Infact, a new empty string is returned.
System.out.println("A".substring(1).equals("")); returns true because of last line in the method.
Based on the JavaDocs for String#subString(int)
Throws: IndexOutOfBoundsException - if beginIndex is negative or larger than the length of this String object".
A String with a single character has a size of 1, therefore 1 == length
As you can se in the code of substring
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
it will only throw an exception if then lenght of the spring is lower then ie begin index.
In your case the begin index is equals the length and thats why you do not get an exception.
Others have quoted the rule, but I wanted to point out the implications. If you say s.substring(n), then n can be anywhere from 0 to s.length(), inclusive. That means that if s has length len, there are len+1 (rather than len) possible ways to call s.substring with one parameter. This makes sense, because if you have the string "abcde", for example, and you're using substring(n) to get a suffix of the string, there are six possible suffixes: "abcde", "bcde", "cde", "de", "e", "".
This is helpful in practice, because you can code things like
while (<something>) {
if (s.beginsWith(prefix)) {
... do some other stuff ...
s = s.substring(prefix.length());
// This sets "s" to the remainder of the string, after the prefix.
// It works even if there is no more text in the string, i.e.
// prefix.length() == s.length(), so that the remaining text is "".
}
In my experience, the ability to have things work this way is very beneficial. It avoids forcing to you write special logic to handle this boundary case, since the boundary case's handling is consistent with the non-boundary cases.
I have a method which takes a string parameter and split the string by # and after splitting it prints the length of the array along with array elements. Below is my code
public void StringSplitTesting(String inputString) {
String tokenArray[] = inputString.split("#");
System.out.println("tokenArray length is " + tokenArray.length
+ " and array elements are " + Arrays.toString(tokenArray));
}
Case I : Now when my input is abc# the output is tokenArray length is 1 and array elements are [abc]
Case II : But when my input is #abc the output is tokenArray length is 2 and array elements are [, abc]
But I was expecting the same output for both the cases. What is the reason behind this implementation? Why split() method is behaving like this? Could someone give me proper explanation on this?
One aspect of the behavior of the one-argument split method can be surprising -- trailing nulls are discarded from the returned array.
Trailing empty strings are therefore not included in the resulting array.
To get a length of 2 for each case, you can pass in a negative second argument to the two-argument split method, which means that the length is unrestricted and no trailing empty strings are discarded.
Just take a look in the documentation:
Trailing empty strings are therefore not included in the resulting
array.
So in case 1, the output would be {"abc", ""} but Java cuts the trailing empty String.
If you don't want the trailing empty String to be discarded, you have to use split("#", -1).
The observed behavior is due to the inherently asymmetric nature of the substring() method in Java:
This is the core of the implementation of split():
while ((next = indexOf(ch, off)) != -1) {
if (!limited || list.size() < limit - 1) {
list.add(substring(off, next));
off = next + 1;
} else { // last one
//assert (list.size() == limit - 1);
list.add(substring(off, value.length));
off = value.length;
break;
}
}
The key to understanding the behavior of the above code is to understand the behavior of the substring() method:
From the Javadocs:
String java.lang.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.
Examples:
"hamburger".substring(4, 8) returns "urge" (not "urger")
"smiles".substring(1, 5) returns "mile" (not "miles")
Hope this helps.
I am trying to solve a problem which goes like this:-
Given a string, return a "rotated left 2" version where the first 2 chars are moved to the end. The string length will be at least 2.
left2("Hello") → "lloHe"
left2("java") → "vaja"
left2("Hi") → "Hi"
I have written two functions for this:-
public String left2(String str)
{
String str1 = str;
if(str.length()>2)
str1 = str.substring(2)+str.substring(0,2);
return str1;
}
public String left2(String str)
{
return str.substring(2)+str.substring(0,2);
}
Both of the functions are correct. I wanted to know that if the first parameter of substring() function is an index, then am I not getting an overflow error in the second function? I am asking this because Java doesn't end in a NULL character so I think there be an error in the second function.
That's because your Substring logic works only if the text length is greater than 2. See here:
if(str.length()>2)
str1 = str.substring(2)+str.substring(0,2);
This is the source code for substring method in java:
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > count) {
throw new StringIndexOutOfBoundsException(endIndex);
}
if (beginIndex > endIndex) {
throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
}
return ((beginIndex == 0) && (endIndex == count)) ? this :
new String(offset + beginIndex, endIndex - beginIndex, value);
}
From experience, documentation may lie, but code doesn't. StringIndexOutOfBoundsException is thrown only if
a. beginIndex is less than 0(that is, is negative) or
b. endIndex is greater than count or
c. beginIndex is greater than endIndex.
The reason the second function
return str.substring(2)+str.substring(0,2);
works is that you never tried passing a string that is shorter than two characters. If you did, you would have received an exception (demo).
The reason this works when you pass a string of two characters is that the index that you pass is allowed to be equal to the length of the string (in this case, 2). When you pass an index that equals the length of the string to substring that takes one parameter, you get an empty string. When you pass an index that equals the length of the string to two-parameter substring, it takes the string up to and including the last character.
public static int getIndexOf(char ch, String str) {
if (str == null || str.equals("")) {
return 0;
//base case
}else{
char first = str.charAt(0);
if (ch != first) {
return -1;
//returns -1 when the character cannot be found within the string
}else{
int rest = str.length() - 1;
if (str.charAt(rest) == ch) {
return rest;
}
return lastIndexOf(ch, str.substring(0, rest));
//recursive case
}
}
}
This my method which returns the index of the input character of the input string. However, when I run it in the interaction plane, it returns wrong number. For example, when I enter 'a' and "peach", it is supposed to return 2, but it returns -1. This method should return -1 only when the character cannot be found in the string. Can anyone tell me how to deal with it?
Thank you!
Well why don't you step through the logic and see what happens.
getIndexOf('a', "peach")
Method goes in, string isn't null or empty so it falls through to the next line of code.
char first = str.charAt(0); // this is 'p'
if (ch != first) { // is 'p' equal to 'a'? no. so return -1
return -1;
And then the rest of your logic will never execute. Can you see how to fix this problem?
your following portion of code means that it will check for the first character of the string if it is matching otherwise it will return -1.
char first = str.charAt(0);
if (ch != first) {
return -1;
this says that if character at 0th index doesn't match then send -1 so as 'p' in "peach" isn't matching with 'a' so it is return -1.
did you get it?
The output's not wrong, the implementation is!
Think in words first. If the desired character is the first character in the string, then the result is zero. Otherwise it's (1 + the index in the string that remains after cutting off the first character). Now code the words:
return (str.charAt(0) == ch) ? 0 : 1 + getIndexOf(ch, str.substring(1));
This doesn't yet handle the case where the character is not in the string at all. Here the charAt(0) call will eventually throw IndexOutOfBoundsException because str doesn't have one!
The cleanest way to handle this case is to catch the exception. So you's have two functions: mustGetIndexOf, which is the recursive relation above, and getIndexOf, which calls the one above inside a try {} catch() {}, returning -1 in that case.
Of course if you don't want to allow the exception, you can test the recursive call's result with if for the special case of -1. The code is uglier, but it will work. Whenever a -1 is seen, return -1 again. This propagates the -1 all the way back to the caller. The exception "unwinds" the recursive calls on the stack in a similar manner, just with one chop instead of the gradual call-by-call way your if statements will do it.
I won't give you full code so you can continue to learn.