public String delDel(String str) {
if (str.length() < 4)
return str;
if (str.substring(1,4).equals("del"))
return str.substring(0, 1) + str.substring(4, str.length());
else
return str;
}
If I run delDel("adel"), it returns a, however, the length of adel is 4, which means the last character string index is 3, why isn't str.substring(4, str.length() out of bounds?
The below code is the implementation of the substring method of String class in java:
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}
As can be seen, the beginIndex is only checked not be be less than zero, and the endIndex is only checked against the "value.length" of the string to be large than it. Then, if this condition passes, then the requested substring would be created by below Code:
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
In your case, because the count would become zero(4-4), then 'this.value = "".value;'
There is a more complex version of substring() that takes both start and end index numbers: substring(int start, int end) returns a string of the chars beginning at the start index number and running up to but not including the end index.
String str = "Hello";
String a = str.substring(2, 4); // a is "ll" (not "llo")
String b = str.substring(0, 3); // b is "Hel"
String c = str.substring(4, 5); // c is "o" -- the last char
The c example above uses substring(4, 5) to grab the last char. The 5
is one more than the index of the last char. However, this does not go
out of bounds because of the substring() "up to but not including" use
of the end index. Incidentally, the length of the resulting substring
can always be computed by subtracting (end - start) -- try it with the
examples above.
Related
what can be a possible way to check length of a string is equal to the number appended at its last. I am attaching a code I wrote any help is appreciated.
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
String str = "abcd10";
String[] part = str.split("(?<=\\D)(?=\\d)");
String strPart1 = part[0];
int n = str.length();
// Traverse string from end and find the number
// stored at the end.
// x is used to store power of 10.
int num = 0, x = 1, i = n-1;
for (i=n-1; i>=0; i--) {
char c = str.charAt(i);
if ('0' <= c && c <= '9') {
num = (c - '0')*x + num;
x = x * 10;
System.out.println("true");
} else break;
}
}
}
You could use Integer.parseInt(String) with the second String from your part array (10 in your post). Then check if the length of the first element matches. Something like,
String[] part = str.split("(?<=\\D)(?=\\d)");
int len = Integer.parseInt(part[1]);
if (len == part[0].length()) {
System.out.printf("Yes. The length of %s is %d.%n", part[0], len);
} else {
System.out.printf("No. The length of %s(%d) is not %d.%n",
part[0], part[0].length(), len);
}
You've already split the string into two parts, which are both stored in part. So part[0] should be "abcd" while part[1] should be "10". So all you need to do is convert part[1] to an integer and compare that value to the length of part[0] like so,
int num = Integer.parseInt(part[1]);
if(num == part[0].length()){
System.out.println("true");
}
Use a counter and increment it within your if
int digitCount = 0;
if ('0' <= c && c <= '9') {
digitCount++;
...
}
and finally(after evaluating n, i.e post for loop) check
if(num == (n-digitCount)) {
System.out.println("Yes the length is same as the number at last.");
} else ..not
I am trying to copy the elements from src (Array 1) to tgt (Array 2) using recursion. Len is an integer value that determines how many of the elements should be transferred. For example, if len is 4, I take 4 elements out of Array 1 and transfer them to Array 2.
Start is the starting location of array src, and this value is transferred to location start2 of array tgt. Then I recursively copy the remaining len-1 elements. Returning out of bound exception.
public void arraycopy(double[] src, int start, double[] tgt, int start2, int len){
if(len < 1) return;
if(len > src.length) return;
tgt[start2] = src[start];
arraycopy(src, start + 1, tgt, start2 + 1, len);
}
First, you are not treating len as the number of characters to copy. You are treating it as an ending index with this condition:
if(start < len){
You can change it to
if (len > 0)
but at that point, len is already greater than 0 because the base case len < 1 is already past. You can remove that if condition entirely.
Second, pass len - 1 in the recursive call:
arraycopy(src, start+1, tgt, start2+1, len - 1);
Third, if len is greater than the source array's length:
if (len > src.length) return;
then all you do is return, leading to an uncopied array and a confused caller. I would remove this line entirely. You can let Java throw the ArrayIndexOutOfBoundsException, passing it to the caller. If you must perform the bounds check, then test it yourself properly, for both the source and destination arrays.
if (start < 0 || start + len > src.length || start2 < 0 || start2 + len > tgt.length) {
throw new IllegalArgumentException("Out of bounds");
}
You don't have to pass two position integer. One is enough.
Check out the code. And also pass the actual length not (len-1)
public static void arraycopy(double[] src, int start, double[] tgt, int len){
if (len != src.length) return;
if (start<len){
tgt[start] = src[start];
arraycopy(src, start+1, tgt, len);
}
}
I have to say that my first attempt had some definite confusion mixed in. Thanks to rgettman^ I was able to make my code more concise and have it pass all my tests!
public void arraycopy(double[] src, int start, double[] tgt, int start2, int len){
if (start < 0 || start + len > src.length || start2 < 0 || start2 + len > tgt.length) return;
if (len > 0){
tgt[start2] = src[start];
arraycopy(src, start+1, tgt, start2+1, len-1);
}
}
public class RecursiveArrayCopyAlgorithm {
public static void main(String[] args) {
String str = "ABCD";
char[] chars = str.toCharArray();
char[] charElements = new char[chars.length];
int charLen = chars.length-1;
int charInitialIndex = 0;
RecursiveArrayCopyAlgorithm testSearch = new RecursiveArrayCopyAlgorithm();
char[] charObjs = testSearch.callLinear(charLen, charInitialIndex, chars, charElements);
for (int i = 0; i < charObjs.length; i++) {
System.out.println(charObjs[i]);
}
}
private char[] callLinear(int charLen, int index,char[] ch, char[] charElements) {
int index1 = charLen;
if(index1 < 0) {
return charElements;
}
if(index1 >= 0) {
charElements[index] = ch[index1];
}
return callLinear(charLen-1, index+1, ch, charElements);
}
}
I need help in figuring out how to return the sum of all numbers in a 2d array entered from a keyboard which are divisible by three. I have my compute sum method that will return one test case correctly, however it does not calculate correctly for every case given. Any suggestions would be very helpful. I will load my code including the while loop to make it easier to find where I am calculating wrong.
try
{
InputStreamReader stream = new InputStreamReader (System.in);
BufferedReader scan = new BufferedReader(stream);
inputParser = Integer.parseInt(input);
int i = 0;
while(inputParser != 0)
{
input = scan.readLine();
inputParser = Integer.parseInt(input);
if(inputParser == 0)
{
inputParser = 0;
}
else
{
numbers1[i] = inputParser;
i++;
}
}
sum = computeSumDivisibleBy3(numbers1,0,numbers1.length-1);
System.out.println("The sum of the numbers divisible by 3 is " + sum);
}
catch(NumberFormatException exception)
{
System.out.println("Please enter integers only");
}
here is the method to calculate the sum divisible by 3
//instead of this original method, I've implemented yours just below this and it returns correctly
public static int computeSumDivisibleBy3(int[] numbers, int startIndex, int endIndex){
if (startIndex == endIndex)
return numbers[endIndex];
else{
int sum1 = computeSumDivisibleBy3(numbers, startIndex, endIndex-1);
if (numbers[endIndex] % 3 == 0)
return sum1 + numbers[endIndex];
else
return sum1;
}
}
//newly implemented code
public static int computeSumDivisibleBy3(int[] numbers, int startIndex, int endIndex){
if (startIndex == numbers.length-1)
return numbers[startIndex] % 3 == 0 ? numbers[startIndex] : 0;
else{
return (numbers[startIndex] % 3 == 0 ? numbers[startIndex] : 0) + computeSumDivisibleBy3( numbers, ++startIndex, endIndex );
}
}
// is startIndex really needed? you only ever use it unnecessarily, so, no.
public static int computeSumDivisibleBy3(int[] numbers, int startIndex, int endIndex){
// End condition, good, but the return value doesn't make any sense
// You always return the last one in the array, even it's not divisible by 3
//if (startIndex == endIndex)
// return numbers[endIndex];
// How about this instead (taking the removal of startIndex into consideration)
if( index == numbers.length - 1) {
return (numbers[index] % 3 == 0 ? numbers[index] : 0);
}
// now, on to regular operations
// all that's needed is to return the current element, or zero, plus the recursive result
return (numbers[index] % 3 == 0 ? numbers[index] : 0) + computeSumDivisibleBy3( numbers, ++index );
// or, if you'd prefer an if statement
int cur = 0;
if( current element % 3 is 0 ) {
cur = current element
}
return cur + recurse( numbers, ++index );
//else{
// int sum1 = computeSumDivisibleBy3(numbers, startIndex, endIndex-1);
// if (numbers[endIndex] % 3 == 0)
// return sum1 + numbers[endIndex];
// else
//return sum1;
}
}
Below is the source of hashCode() for String:
public int hashCode()
{
int h = hash;
if (h == 0 && count > 0)
{
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++)
{
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
off is initialized to offset, which is 0 (I looked everywhere in the source and each assignment made it 0 and that's all). Then in the for loop, val is iterated through via off instead of i. Why is this? Why not just use i and eliminate the need for offset to begin with? I assume there's a good reason for offset existing. Any insight?
The substring function creates a new String that has a value of offset other than 0.
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);
}
This constructor is called.
// Package private constructor which shares value array for speed.
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
So offset isn't always 0.
In Java, strings can be defined as substrings of a parent string, to save space if you make many substrings of a huge string (such as to parse it). In that case they use an offset to determine where in the parent string they start.
offset and count were used in older versions for substrings char array sharing. In current version sharing is not used anymore and these fields were removed. See hashCode impl from 1.7.0_15
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
public boolean isPalindrome3(String input, int index, int length)
{
if(index > (length-1-index))
return true;
else if(input.charAt(index)!=input.charAt(length-1-index))
return false;
else
return isPalindrome3(input, index + 1, length);
}
Here initially i pass the input string, 0, input.length()
If you don't have to use recursion, here's a much more efficient check for palindrome:
public boolean isPalindrome3(String input)
{
for (int start = 0, end = input.length() - 1; start < end; ) {
if (input.charAt(start++) != input.charAt(end--)) {
return false;
}
}
return true;
}
I would write it like this:
public boolean isPalindrome(String str, int offset)
{
int rightOffset = str.length() - offset - 1;
if (offset <= rightOffset)
{
char c1 = str.charAt(offset);
char c2 = str.charAt(rightOffset);
if (c1 != c2) return false;
return isPalindrome(str, offset + 1);
} else
{
return true;
}
}
Differences with your code:
Do not pass the length, because that is a String property
unwrap the character comparation
nice code formatting
improved efficiency, by creating a local variable rightOffset.
public static String reverseString(String s) {
byte[] array = s.getBytes();
byte swap;
for( int i = 0, j = array.length - 1; i < array.length / 2; i++, j--) {
swap = array[ j ];
array[ j ] = array[ i ];
array[ i ] = swap;
}
return (new String(array));
}
if(myString.equals(reverseString(myString)))
// is palindrome