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);
}
}
Related
I do simple rownumber calculation in InputStream (calc number of NewLines #10)
for (int i = 0; i < readBytes ; i++) {
if ( b[ i + off ] == 10 ) { // New Line (10)
rowCount++;
}
}
Can I do it faster? Without iteration by one byte?
Probably I am looking for some class which able to use CPU specific instructions (simd/sse).
All code:
#Override
public int read(byte[] b, int off, int len) throws IOException {
int readBytes = in.read(b, off, len);
for (int i = 0; i < readBytes ; i++) {
hadBytes = true; // at least once we read something
lastByteIsNewLine = false;
if ( b[ i + off ] == 10 ) { // New Line (10)
rowCount++;
lastByteIsNewLine = (i == readBytes - 1); // last byte in buffer was the newline
}
}
if ( hadBytes && readBytes == -1 && ! lastByteIsNewLine ) { // file is not empty + EOF + last byte was not NewLine
rowCount++;
}
return readBytes;
}
On my system, just moving the lastByteIsNewLine and hasBytes parts out of the loop results in a ~10% improvement*:
public int read(byte[] b, int off, int len) throws IOException {
int readBytes = in.read(b, off, len);
for (int i = 0; i < readBytes ; i++) {
if ( b[ i + off ] == 10 ) {
rowCount++;
}
}
hadBytes |= readBytes > 0;
lastByteIsNewLine = (readBytes > 0 ? b[readBytes+off-1] == 10 : false);
if ( hadBytes && readBytes == -1 && ! lastByteIsNewLine ) {
rowCount++;
}
return readBytes;
}
* 6000ms vs 6700ms for 1,000 iterations on 10MB buffers read from a ByteArrayInputStream filled with arbitrary text.
I started with that other guy's improvements, and hoisted the array index calculation and the field access out of the for loop.
According to my JMH benchmark, this saved another 25%, with "that other guy's" implementation clocking 3.6 ms/op, and this version at 2.7 ms/op. (Here, one operation is reading a ~10 MB ByteArrayInputStream with around 5000 lines of random length).
public int read(byte[] buffer, int off, int len) throws IOException {
int n = in.read(buffer, off, len);
notEmpty |= n > 0;
int count = notEmpty && n < 0 && !trailingLineFeed ? 1 : 0;
trailingLineFeed = (n > 0) && buffer[n + off - 1] == '\n';
for (int max = off + n, idx = off; idx < max;) {
if (buffer[idx++] == '\n') ++count;
}
rowCount += count;
return n;
}
Things that really hurt performance: indexing backward over the array.
Things that don't matter: comparing values with the more readable '\n' instead of 10.
Surprisingly (to me anyway), using only one of these tricks by itself did not seem to improve performance. They only made a difference used together.
You can easily search in readBytes after converting it in String:
String stringBytes = new String(readBytes);
To get the amount of occurrences:
int rowCount = StringUtils.countMatches(stringBytes, "\n");
To only know if the \n is contained in readBytes:
boolean newLineFound = stringBytes.contains("\n");
Well, rather than trying to speed up that one specific portion (which I don't think you can), you can try using a different method. Here's a class which you can use to keep track of the number of rows while reading from an InputStream.
public class RowCounter {
private static final int LF = 10;
private int rowCount = 0;
private int lastByte = 0;
public int getRowCount() {
return rowCount;
}
public void addByte(int b) {
if (lastByte == LF) {
rowCount++;
}
lastByte = b;
}
public void addBytes(byte[] b, int offset, int length) {
if (length <= 0) return;
if (lastByte == LF) rowCount++;
int lastIndex = offset + length - 1;
for (int i = offset; i < lastIndex; i++) {
if (b[i] == LF) rowCount++;
}
lastByte = b[lastIndex];
}
}
Then when reading an InputStream, you can use it like this.
InputStream is = ...;
byte[] b = new byte[...];
int bytesRead;
RowCounter counter = new RowCounter();
while ((bytesRead = is.read(b)) != -1) {
counter.addBytes(b, 0, bytesRead);
}
int rowCount = counter.getRowCount();
or you can easily adapt it to whatever situation you need it for.
Given a string representing the starting number and a maximum number of changes allowed, create the largest palindromic string of digits possible or the string -1 if it's impossible to create a palindrome under the contstraints.
I wrote a code who answer on the questions, but i have an error that i dont know where it is, or if even the code work.
static String highestValuePalindrome(String s, int n, int k) {
for(int i =0 ; i < n ; i++){
char[] ch =s.toCharArray();
if(n==1)
return s ;
else if ((ch[i] != ch[n-i-1]) && (k != 0) ){
ch[i] = ch[n-i-1] = 9 ;
k--;
}
}
String str = new String(ch);
return str ;
}
Output Format
Print a single line with the largest number that can be made by changing no more than digits. If this is not possible, print -1.
Sample Input
n=4, k=1
3943
Sample Output
3993
Sample Input
n=6, k=3
092282
Sample Output
992299
Sample Input
n=4, k=1
0011
Sample Output
-1
First of all there is no need to pass n as a parameter because it's just the length of the string. Secondly, this is not the complete program. I have made many changes to the given code.
public class largestPalindorme {
public static void main(String[] args) {
System.out.println(highestValuePalindrome("0011", 1));
}
static String highestValuePalindrome(String s, int k) {
char[] ch = s.toCharArray();
int n = s.length(); // which is same as n which you passed as parameter
int minChangesRequired = MinumumChangesNeeded(s);
//if the changes required to make the given string a palindrome is less then k then only it will go inside or it will return -1
if (k >= minChangesRequired) {
int diff = 0;
if (k > minChangesRequired) {
diff = k - minChangesRequired;
for (int l = 0; l < diff; l++) {
ch[l] = '9';
ch[n - l - 1] = '9';
}
}
for (int i = diff; i < n - diff / 2; i++) {
if (ch[i] != ch[n - i - 1]) {
//if checks which number is greater
int greater = Integer.parseInt(String.valueOf(ch[i])) > Integer.parseInt(String.valueOf(ch[n - i - 1])) ? Integer.parseInt(String.valueOf(ch[i])) : Integer.parseInt(String.valueOf(ch[n - i - 1]));
//replaces the smaller number from the greater number.
if (Integer.parseInt(String.valueOf(ch[i])) != greater) {
ch[i] = ch[n - i - 1];
} else {
ch[n - i - 1] = ch[i];
}
}
}
String str = new String(ch);
return str;
}
return "-1";
}
//this function returns the minimum changes we need to do to make it a palindrome.
public static int MinumumChangesNeeded(String s) {
int count = 0;
char[] ch = s.toCharArray();
int n = s.length();
for (int i = 0; i < n / 2; i++) {
if (ch[i] != ch[n - i - 1]) {
count++;
}
}
return count;}}
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.
There is a vector of 1 and 0:
int[] vec = new int[6]{0,1,0,0,1,0};
I need to calculate total number of "0" positions between "1" positions. For instance, if <0,1,0,0,1,0> then the answer is 2. However, the problem is that the vector may contain the following values:
int[] vec = new int[6]{0,1,0,0,0,0}; // the answer is 0
or
int[] vec = new int[6]{1,0,0,1,0,1}; / the answer is 3
So far, I just made a simple algorithm for the 1st case (<0,1,0,0,1,0>).
int start = 0, end = 0;
for (int i=0; i<vec.length; i++)
{
if (vec[i] == 1 && start == 0)
start = i;
if (vec[i] == 1 && start != 0)
end = i;
}
int result = end - start - 1;
I need some help with the development of more generic algorithm that could handle all the above-mentioned cases.
You can iterate over the array from both ends to find the first and last 1. Then, if you found both, count the 0s between them.
int start = -1;
int end = vec.length;
int i = 0;
int j = vec.length-1;
while (i < j) {
if (vec[i] == 1 && start < 0)
start = i;
i++;
if (vec[j] == 1 && end >= vec.length)
end = j;
j--;
if (start >= 0 && end < vec.length)
break;
}
int count = 0;
if (start >= 0 && end < vec.length) {
for (i = start + 1; i < end; i++) {
if (vec[i] == 0)
count++;
}
}
It can probably be optimized into a single loop.
Sorry, initially I thought you wanted to count the number of segments rather than the actual number of zeroes.
You can count all the zeroes after the first one (n), keeping track of the number of zeroes since the last one seen (m). Then when you reach the end of the vector, your count of n is m zeroes too high.
int count = 0;
int zeroesSinceLastOne = 0;
bool firstOneSeen = false;
for(int i = 0, n = vector.size(); i < n; ++i)
{
while(!firstOneSeen && vector[i] == 0)
{
continue;
}
firstOneSeen = true;
if(vector[i] == 0)
{
++count;
++zeroesSinceLastOne;
}
else
{
zeroesSinceLast = 0;
}
}
return count - zeroesSinceLastOnce;
Disclaimer: untested. May give the wrong number or kill your cat.
Try this algo:
startIndex = -1;
endIndex = -1;
for i from 1 to vec.length():
if( 1 == vec[i])
startIndex = i
break;
for i from vec.length() to 1:
if( 1 == vec[i])
endIndex = i
break;
ans = endIndex - startIndex - no_of_ones_in_between
Say you have a sorted array of integers:
{3,4,4,6,10,15,15,19,23,23,24,30}
And you want to find the number of integers that fall within a range of 4 and 23.
{4,4,6,10,15,15,19,23,23}
Thus the result would be 9.
I wrote a binarysearch implementation, but I'm not sure how I would modify it to also take into account the fact that there can be multiple integers that match the upper bounds of the range.
I thought of adding a boolean in the method signature to ask whether to look for the upper bounds of the key, but I'm not sure if it can be done in a single method while keeping O(log(N)) complexity.
Or is there some other way of finding the # of items in that range in the sorted array in O(log(N)) time?
This is what I have so far:
int start = rangeBinarySearch(arr, 4, false);
int end = rangeBinarySearch(arr, 23, true); // true would indicate that I want the position of the last occurrence of the key.
int totalInRange = (Math.abs(end) - Math.abs(start) -1)
private static int rangeBinarySearch(int[] items, int key, boolean lastIndex) {
if(items == null)
throw new IllegalArgumentException();
int start = 0;
int end = items.length - 1;
while(start <= end) {
int mIndex = (start + end) / 2;
int middle = items[mIndex];
if(middle < key)
start = (mIndex +1);
else if(middle > key)
end = (mIndex -1);
else
return mIndex; // Possible something here to find the upper bounds?
}
return -(start +1);
}
Range binary search for the lower bound and the upper bound are different. Here different means they have different stopping criteria and return step.
For the lower bound (left range), you can call the following function to get the index in the sorted array where the value is larger or equal than it, -1 otherwise.
int binarySearchForLeftRange(int a[], int length, int left_range)
{
if (a[length-1] < left_range)
return -1;
int low = 0;
int high = length-1;
while (low<=high)
{
int mid = low+((high-low)/2);
if(a[mid] >= left_range)
high = mid-1;
else //if(a[mid]<i)
low = mid+1;
}
return high+1;
}
For the upper bound (right range), you can call the following function to get the index in the sorted array where the value is smaller or equal than it, -1 otherwise.
int binarySearchForRightRange(int a[], int length, int right_range)
{
if (a[0] > right_range)
return -1;
int low = 0;
int high = length-1;
while (low<=high)
{
int mid = low+((high-low)/2);
if(a[mid] > right_range)
high = mid-1;
else //if(a[mid]<i)
low = mid+1;
}
return low-1;
}
Finally, if you want to get the number of how many elements within this range, it's easy based on return values of these two above functions.
int index_left = binarySearchForLeftRange(a, length, left_range);
int index_right = binarySearchForRightRange(a, length, right_range);
if (index_left==-1 || index_right==-1 || index_left>index_right)
count = 0;
else
count = index_right-index_left+1;
Test: (with duplicates)
int a[] = {3,4,4,6,10,15,15,19,23,23,24,30};
int length = sizeof(arr)/sizeof(arr[0]);
int left_range = 4;
int right_range = 23;
int index_left = binarySearchForLeftRange(a, length, left_range); // will be 1
int index_right = binarySearchForRightRange(a, length, right_range); // will be 9
int count; // will be 9
if (index_left==-1 || index_right==-1 || index_left>index_right)
count = 0;
else
count = index_right-index_left+1;
EDIT: Of course, you can merge the first two functions into one by passing one extra flag to indicate it as lower bound or upper bound, though it will be much more clear if not. Your choice!
If you are not learning the algorithm use standart functions instead:
Arrays.binarySearch
You basicly need first occurence of your first element (4) and last occurence of last (23) and substract. But there is no need for (4) to be there, so read documentation of Arrays.binarySearch, it gives you where (4) would be.
If you are expecting lots of (4)s you have to write your own binSearch, that returns both first and last index:
find first occurence at index i
if there is previous one look at i/2, if there is (4) look at i/4 else look at 3*i/4
...
You need to perform two binary searches to find the lowest index before the rangeLow and the highestIndex after rangeHigh, that way you can count duplicates within the range.
This would give a time complexity of o(2 log n) as we perform the binary search twice.
private int searchArrayForNumbersInRange(int[] arr, int start, int end) {
int leftIndex = searchLeft(arr, start);
int rightIndex = searchRight(arr, end);
int count;
if (leftIndex < 0 || rightIndex < 0)
return -1;
if (rightIndex == leftIndex)
count = 1;
else {
count = rightIndex - leftIndex;
}
return count;
}
private int searchLeft(int[] arr, int start) {
int lo = 0;
int hi = arr.length - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (arr[mid] == start && arr[mid -1] < start) {
return mid - 1;
}
if (arr[mid] >= start)
hi = mid - 1;
else
lo = mid + 1;
}
return -1;
}
private int searchRight(int[] arr, int end) {
int lo = 0;
int hi = arr.length -1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (arr[mid] == end && arr[mid+1] > end)
return mid;
if (mid <= end)
lo = mid + 1;
else
hi = mid - 1;
}
return -1;
}