I've array of N integers in not-decreasing order. Need to find any specific element in array, if found then return the position of that array otherwise returns -1
public static int find(int[] v, int bb) {
int N = v.length;
if (N == 0) {
return -1;
}
int l = 0;
int r = N - 1;
while (l < r) {
int m = (l + r) / 2;
if (v[m] > bb) {
r = m - 1;
} else {
l = m;
}
}
if (v[l] == bb) {
return l;
}
return -1;
}
there's one bug I need to find out, which is about that this will not work for some inputs. I gave up.
Any suggestions ?
If you want to locate the index of the first specific numerical element within the array then you can do something like this:
public static int find(int[] v, int bb) {
int found = -1;
for (int i = 0; i < v.length; i++) {
if (v[i] == bb) {
found = i;
break;
}
}
return found;
}
If there are multiple values in the array that are the same as bb then the method above will only provide the first one found. If you want to return the index values for all values of bb found in the array then you would want to return an array of index values, for example:
public static int[] find(int[] v, int bb) {
List<Integer> list = new ArrayList<>();
int found = -1;
for (int i = 0; i < v.length; i++) {
if (v[i] == bb) {
found = i;
list.add(found);
}
}
if (found == -1) {
list.add(found);
}
return list.stream().mapToInt(d -> d).toArray();
}
The List Interface is used in the above example because it can grow dynamically since we have no idea how many values of bb are actually going to be contained within the Array. The List is converted to an int[] array before it is returned.
First of all, I think you should name your variables with a proper name, and not just with a single characters, it'll make your code easier to understand.
Second, you are using a binary serach algorithm for increasing ordered arrays, if you want that code to work correctly you have to use an increasing ordered array. Here you have a binary search method that should work with increasing ordered arrays:
public static int binarySeacrh(int [] list, int numSearched) {
boolean found = false;
int start = 0;
int end = list.length - 1;
int pos = -1;
while(start <= end && !found){
int middle=((start + end) / 2);
if (numSearched == list[middle]){
found = true;
pos = middle;
}
else if (list[middle] < numSearched){
start = middle + 1;
}else{
end = middle - 1;
}
}
return pos;
}
If you want to search for the position in a unordered array, you must use another type of serach algorithm or order the array first.
Related
I have made this code to rotate an array by k times. In this when I'm adding i=0 , it is showing an "ArrayOutOfBounds" exception, and when I'm changing the value of i by 1, it is showing wrong output. Why is it showing this exception? And is there any way I could correct this code?
public void rotate(int[] nums, int k)
{ int j=0, temp=0;
for(j=0;j<k;j++)
{
for(int i=0;i<nums.length;i++)
{
temp=nums[i-1];
nums[i-1]=nums[i];
nums[i]=temp;
}
}
}
}
At i=0 you are trying to access nums[i-1] = num[-1] which is an invalid position and hence an ArrayOutOfBound exception is thrown.
So, the modified version would be:
for (j=0; j<k; j++)
{
for (int i=1;i<nums.length;i++)
{
temp=nums[i-1];
nums[i-1]=nums[i];
nums[i]=temp;
}
}
But the above will rotate the array by k times towards the left not right as you are shifting the elements towards the left. So, to get the right rotation you need to shift the elements from the end of the array. Like:
for (j=0; j<k; j++)
{
for (int i=nums.length-1; 0<i; i--)
{
// shifting towards the right
temp=nums[i-1];
nums[i-1]=nums[i];
nums[i]=temp;
}
}
Edit (from comments above): If i is 0, you're trying to get an index of -1 which will raise an ArrayOutOfBounds exception. If i starts from 1, then you're not dealing with the first number.
Here's the function you can use to rotate integers to the right:
public void rotate(int[] nums, int k) {
int arrLen = nums.length;
// If the number of times you want to rotate is bigger than the size of the array, get the minimum number of rotations to get the same result.
while (k > n) {
k = k - arrLen;
}
k = arrLen - k;
k = k % arrLen;
int i, m, n, temp;
int g_c_d = gcd(k, arrLen);
// Move the value in the i-th index
for (i = 0; i < g_c_d; i++) {
temp = arr[i];
m = i;
while (true) {
n = m + k;
if (n >= arrLen) {
n = n - arrLen;
}
if (n == i) {
break;
}
arr[m] = arr[n];
m = n;
}
arr[m] = temp;
}
}
// Find the greatest common divisor of two numbers, a and b
public void gcd(int a, int b) {
if (b == 0) {
return a;
} else {
return gcd(b, a % b);
}
}
Let me briefly explain what it does. This is one of the most known algorithms: juggling. You divide the array into the n number of sets where n denotes the greatest common divisor of the length of the array and the number of times you want to rotate. Then, you move the numbers within sets.
This might be the most efficient in terms of time (as its time complexity is O(n)).
A better solution would be taking a copy of the given array with the values '0' then looping through the given array to obtain a new_index.
Formula for the New_index for the Clock-wise rotating array:
for(int i=0;i<nums.length;i++){
int new_index = (old_index+k)%(a.length)
copy[new_index] = a[old_index]
}
Now the entire function code would be:
public static void rotate(int[] a, int k)
{
int n = a.length;
int[] copy = new int[n];
// fill the values with zeroes
for(int i=0;i<n;i++){
copy[i]=0;
}
// rotate the array
for(int i=0;i<n;i++){
int new_index = (i+k)%n;
copy[new_index] = a[i];
}
// Now that the array is copied, copy the elements to the original array. Because they asked to rotate the given array.
for(int i=0;i<n;i++){
a[i]=copy[i];
}
}
function solution(arr, k) {
if(k == 0) return arr;
if(arr.length == k) return arr;
if(arr !== undefined && arr !== null){
let counter = k > arr.length ? k % arr.length : k;
let rotArray = [];
rotArray = arr.slice(arr.length - counter, arr.length).concat(arr.slice(0,arr.length - counter))
return rotArray;
}
return arr;
}
Their purpose is to return the number of comparisons between the keys and the array items.
Please let me know if there is anything that I should change, as I am new to Java and am not yet fully familiar with best practices.
public class BinaryVsLinear {
private static int linearSearch(int key, int[] array){
int count = 0;
for (int i = 0; i < array.length; i++){
count++;
if (array[i] == key){
i += array.length +1;
}
}
return count;
}
private static int binarySearch(int key, int[] array){
int count = 0, l = 0, r = array.length -1;
while (l <= r){
int m = (l+r)/2;
count++;
if (array[m] == key){
return count;
}
count++;
if (array[m] < key){
l = m + 1;
}
else{
r = m - 1;
}
}
return count;
}
Your code is correct, i.e., it counts how many comparisons will be executed both for linear and binary searches. As you is a novice, I would recommend some better practices when writing code, take a look.
public class BinaryVsLinear {
private static int linearSearch( int key, int[] array ) {
int count = 0;
for ( int i = 0; i < array.length; i++ ){
count++;
if ( key == array[i] ){
break;
}
}
return count;
}
private static int binarySearch( int key, int[] array ) {
// one variable per line
// use better names
int count = 0;
int left = 0;
int right = array.length -1;
while ( left <= right ){
int middle = ( left + right ) / 2;
count++;
if ( array[middle] == key ){
return count;
}
count++;
if ( key > array[middle] ){
left = middle + 1;
} else{
right = middle - 1;
}
}
return count;
}
}
I added some spaces, change some variable names to better names, etc. It is a matter of preference, but you must always pay attention to the readability of your code.
Java: i want to compare 2 arrays, i want to find out if the first n entries in the array s comes before the first n entries in array t in dictionary order, in other words if n = 4 then ('b''i''n''a''r''y') is less than ('b''i''n''d'). because the 4th element of binary 'a' comes before the 4th element of bind 'd'
i'm really struggling with this
#Override
public boolean lessThan(char[] s, char[] t, int n) {
for (int i = 0; i < n; i ++){
if (s[i] > t[i]){
return true;
}
}
return false;
}
Checking the ASCII char of each char should work.
public boolean lessThan(char[] s, char[] t, int n) {
boolean isLess = true;
for (int i = 0; i < n; i++) {
if((int) t[i] > (int) s[i]){
isLess = false;
}
}
return isLess;
}
Build strings and compare them
return new String(s, 0, n).compareTo(new String(t, 0, n) < 0;
I have implemented the select/median of medians algorithm using the following as a reference http://www.ics.uci.edu/~eppstein/161/960130.html (this has previously been linked here Median of Medians in Java).
My code seems to work for small arrays (~100) and even works for arrays of size 100001 http://pastebin.com/mwRc4Hig (answer 5008), but then fails on an input array of size 10001 http://pastebin.com/YwVBmgDk (answer 4960, my code outputs 4958).
Note that the correct answers for the texts above are equivalent to sorting the array and returning the element at array[array.length / 2], regardless of whether the array size is even or odd.
I'm not sure how to debug this issue. The functionality seems arbitrary and I'm just lost. Here below is my code:
public class MedianOfMedians {
public static void main(String[] args) {
MedianOfMedians mds = new MedianOfMedians();
mds.run();
}
private void run() {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] numArray = new int[n];
for (int i = 0; i < n; i++) {
numArray[i] = in.nextInt();
}
int median = select(numArray, numArray.length / 2);
System.out.print(median);
}
private int select(int[] numArray, int k) {
if (numArray.length <= 10) {
int[] sorted = insertionSort(numArray);
return sorted[k];
}
int divCount = (numArray.length % 5 == 0) ? numArray.length / 5 - 1 : numArray.length / 5;
int[] medOfMed = new int[divCount + 1];
int counter = 0;
int[] subArray;
while (counter <= divCount) {
subArray = splitByFive(counter, divCount, numArray);
medOfMed[counter] = select(subArray, subArray.length / 2);
counter++;
}
int M = select(medOfMed, numArray.length / 10);
List<Integer> lt = new ArrayList<>();
List<Integer> eq = new ArrayList<>();
List<Integer> gt = new ArrayList<>();
for (int i : numArray) {
if (i < M) {
lt.add(i);
} else if (i == M) {
eq.add(i);
} else {
gt.add(i);
}
}
if (k < lt.size()) {
return select(createArray(lt), k);
} else if (k > lt.size() + eq.size()) {
return select(createArray(gt), k - lt.size() - eq.size());
} else {
return M;
}
}
private int[] splitByFive(int splitIter, int divisions, int[] toSplit) {
int numToCopy;
if (splitIter == divisions) {
numToCopy = toSplit.length - (5 * splitIter);
} else {
numToCopy = 5;
}
int[] subArray = new int[numToCopy];
System.arraycopy(toSplit, splitIter * 5, subArray, 0, numToCopy);
return subArray;
}
private int[] createArray(List<Integer> list) {
int[] result = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
result[i] = list.get(i);
}
return result;
}
private int[] insertionSort(int[] numArray) {
for (int i = 1; i < numArray.length; i++) {
int j = i;
while (j - 1 >= 0 && numArray[j] < numArray[j - 1]) {
int temp = numArray[j];
numArray[j] = numArray[j - 1];
numArray[j - 1] = temp;
j--;
}
}
return numArray;
}
}
I don't have time to debug your code, but maybe I can offer a debugging technique for you to try yourself that's useful for recursive algorithms like this.
If there is an input that the algorithm fails on (and there is, as you found) then there is a smallest such input -- and the smaller this input, the easier it is to figure out what's going wrong. Because the algorithm is recursive, you have a nice way to isolate the first place that things go wrong: you can test that the result you are about to return from select() is correct (using a slow, trusted method like copying the data to a temporary buffer, sorting it and then grabbing the half-way element) just before returning the value. Doing this will be much easier if you rearrange the function to use just a single return statement, e.g.:
private int select(int[] numArray, int k) {
int knownCorrectAnswer = selectSlowlyButDefinitelyCorrectly(numArray, k);
int willReturn;
if (numArray.length <= 10) {
int[] sorted = insertionSort(numArray);
willReturn = sorted[k]; // Just remember what we will return
} else { // Need to add else branch here now
...
if (k < lt.size()) {
willReturn = select(createArray(lt), k);
} else if (k > lt.size() + eq.size()) {
willReturn = select(createArray(gt), k - lt.size() - eq.size());
} else {
willReturn = M;
}
} // End of inserted else branch
if (willReturn == knownCorrectAnswer) {
return willReturn;
} else {
yell("First problem occurs with numArray=<...> and k=<...>!");
}
}
yell() should print out the entire problem instance and halt the program (e.g. by throwing an exception). The nice thing about this setup is that you know that when yell() gets called, every call to select() that has already completed was correct -- since if it wasn't, yell() would have already been called and the program would have halted before now. So the output produced by yell() is guaranteed to be the first (not necessarily the smallest, but often that also) subproblem in which things went wrong.
I am currently writing some code that is supposed to solve a sudoku puzzle for an assignment. The code I currently have written should be isolating the row and column where we need to insert a value, and then testing values 1-9 to see which ones already appear in either the row or the column. The problem is, the binary search is not detecting some numbers and I do not know why. Here is my code. All you need to no is that A.grid is an array containing the unsolved puzzle, and the set value method is one that I have written to plug a value into the array with the fromat setValue(xLocation, yLocation, value)
int currentVal = 0;
int j;
int [] currentRow = new int [9];
int [] currentCol = new int [9];
for (i = 0; i<9 ; i++) {
for (j = 0; j<9 ; j++){
currentVal=A.grid[i][j];
boolean keepGoing = true;
int newVal=1;
if (currentVal==0) {
for( int k = 0; k < 9; k++)
{currentCol[k] = A.grid[k][j];
}
currentRow = A.grid[i];
log(Arrays.toString(currentRow));
log(Arrays.toString(currentCol));
log("");
while (keepGoing) {
int indexRow=Arrays.binarySearch(currentRow, newVal);
int indexCol=Arrays.binarySearch(currentCol, newVal);
log(indexRow);
log(indexCol);
log("");
if (indexRow<0 && indexCol<0) {
keepGoing = false;
}
newVal++;
}
A.setValue(j, i, newVal-1);
Thanks!
I'm not sure if this is your only problem, but you need to make sure that your arrays are sorted if you're going to use a binary search algorithm. Otherwise, you're going to get garbage results.
That being said, why do you think you need to do a binary search on arrays with only 9 elements? It would very likely be faster just to do the search yourself manually and forget about using a binary search at all.
int indexRow = -1;
for (int z = 0; z < 9; ++z)
{
if (currentRow[z] == newVal)
{
indexRow = z;
break;
}
}
// indexRow is now the index of newVal in currentRow
For that matter, it would probably be clearer if that whole routine was wrapped up in a separate function:
int search(int[] source, int val)
{
for (int z = 0; z < source.length; ++z)
{
if (source[z] == val)
{
// z is the position of val in the source array
return z;
}
}
// Return -1 if val is not present
return -1;
}
You would then replace your binarySearch() calls with calls to search().
I hope this helps!