I am creating a custom binary search function and am running into issues. I have looked through the code for a good while now, however, I cannot figure out why nothing is returning. Please let me know what you think. Thank you!
a is the array, b is the result that is returned in the end, and t is the target value. Pos is the current position and min and max are the minimum and maximum positions.
public static int binarySearch(int a[], int t){
int min = 0;
int max = a.length;
if (a[0] == t){
return 0;
}
int b = -1;
for (int pos = min; a[pos] != t;){
pos = (max - min) / 2;
if (a[pos] == t){
b = pos;
} else {
if(t > a[pos]){
min = pos + 1;
} else {
min = pos - 1;
}
}
}
return b;
}
Two small issues
pos = (max - min) / 2;
It looks like you're trying to find the average of the values, but are instead finding half the difference
Instead to find the average, use pos = (max - min) / 2 + min;
Also when moving the max down, you accidentally move the min up instead
min = pos - 1; should instead be max = pos - 1;
I see three issues with your code :
Your loop condition is not enough to determine the termination of the whole process . Your loop condition is a[pos] != t and you only increase or decrease the pos which will cause ArrayIndexOutOfBoundsExceptioneventually if the element we search can't be found inside the array.
Your if-else is not correct , cause you only update the value for the min and not the max too.
Instead of 'moving' the value pos by half each time, you just set it the average of min and max which is not correct.
Combine all the above and you will get this result :
public static int binarySearch(int a[], int t) {
int min = 0;
int max = a.length;
if (a[0] == t) {
return 0;
}
int b = -1;
for (int pos = min; a[pos] != t;) {
pos = min + (max - min) / 2;
if (pos >= a.length || pos <= 0) {
break;
}
if (a[pos] == t) {
b = pos;
} else {
if (t > a[pos]) {
min = pos + 1;
} else {
max = pos - 1;
}
}
}
return b;
}
Related
Trying to understand this question a bit more. Currently I need to return the sum of all the values that lie with a range either low or high within an array. Currently I have got this far (see code below), however I am stuck on what to do next. Any help?
public static int sumrange(int[] data, int low, int high) {
int sum = 0;
if (data == null || data.length == 0) {
return 0;
}
for (int i = 0; i < data.length;) {
if (i < low) {
sum = sum + data[i];
return sum;
}else if (i > high)
sum = sum + data[i];
return sum;
}
return 0;
}
void check(int start, int* count, int size, int * set)
{
if(start == size) {
(*count) += 1;
return;
}
for(int i = start; i < size ; i++)
{
if((set[start] == 0) && (((i+1) % (start +1) == 0) || (start + 1) % (i+1) == 0 ))
{
set[start] = 1;
check(start +1, count, size, set);
set[start] = 0;
}
}
}
int countArrangement(int n){
int* set = (int *)malloc(sizeof(int) * n);
memset(set, 0, sizeof(int) * n);
int count = 0;
check(0, &count, n, set);
return count;
}
this is the code translated from java to c but the problem is , when n is greater than 6 then the result is wrong
for 7 it increase by one but after that the result is always smaller than the expected value, I am not able to understand what am i missing at.
Your answer
1
2
3
8
10
36
42
128
216
600
660
3456
3744
9408
18900
Expected answer
1
2
3
8
10
36
41
132
250
700
750
4010
4237
10680
24679
that java code
public class Solution {
int count = 0;
public int countArrangement(int N) {
boolean[] visited = new boolean[N + 1];
calculate(N, 1, visited);
return count;
}
public void calculate(int N, int pos, boolean[] visited) {
if (pos > N)
count++;
for (int i = 1; i <= N; i++) {
if (!visited[i] && (pos % i == 0 || i % pos == 0)) {
visited[i] = true;
calculate(N, pos + 1, visited);
visited[i] = false;
}
}
}
}
Can you just point out the missing part?
this is the code translated from java to c
Well, not really.
You have not made a one-to-one translation. The C code is (perhaps by mistake) using a completely different algorithm.
Start by making a one-to-one translation. Once you have that working, you can start playing with algorithm changes. But don't do both in the same step.
A one-to-one translation would be more like:
void calculate(int N, int pos, int * visited, int* count)
{
if (pos > N)
(*count)++;
for (int i = 1; i <= N; i++) {
if (!visited[i] && (pos % i == 0 || i % pos == 0)) {
visited[i] = 1;
calculate(N, pos + 1, visited, count);
visited[i] = 0;
}
}
}
int countArrangement(int n)
{
int* set = calloc(n+1, sizeof *set);
int count = 0;
calculate(n, 1, set, &count);
free(set);
return count;
}
Notice how the C code for calculate is almost identical to the java version. No change of algorithm - only a few changes required due to language differences.
I am trying to get the first occurrence of the number 5.The answer should be 2 in this case but i am getting 3 here.
public static void main(String[] args) {
int A[] = {1, 3, 5, 5, 5, 17, 20};
int index = BinarySearch(A, 5);
System.out.println(index);
}
public static int BinarySearch(int[] A, int x) {
int low = 0;
int high = A.length - 1;
while (low <= high) {
//(low + high) / 2
int mid = low + (high-low)/2; // more optimal -> low + (high-low)/2 (avoid integer overflow)
if (x == A[mid]) {
return mid;
} else if (x < A[mid]) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
When you find the value you are looking for, you return the mid index immediately without checking if there are smaller indices having the same value.
You have to continue searching :
public static int BinarySearch(int[] A, int x) {
int low = 0;
int high = A.length - 1;
int mid = -1;
while (low <= high) {
mid = low + (high-low)/2;
if (x <= A[mid]) { // this ensures you keep searching for the first index having
// the number you are looking for
//
// changing x <= A[mid] to x < A[mid] will give you the
// last index having the number you are looking for instead
high = mid - 1;
} else {
low = mid + 1;
}
}
if (mid >= 0 && x == A[mid]) {
return mid;
}
return -1;
}
I have been having trouble on Problem 14 on Project Euler. I don't understand why my code(Java) isn't working and any help would be appreciated.
public class Calculate {
public static void main(String[] args){
System.out.println(calc());
}
public static int calc(){
int max = 0;
int maxI = 0;
for (int i = 0; i < 1000000; i++){
if (seqLen(i) >= max){
max = seqLen(i);
maxI = i;
}
}
return maxI;
}
public static int seqLen(int seed){
if (seed <= 0) return 0;
if (seed == 1) return 1;
int len = 1;
if (seed % 2 == 0){
len += seqLen(seed/2);
}
else{
len += seqLen((3*seed)+1);
}
return len;
}
}
Thanks!
You run into an overflow with your int variables.
The maximum number appearing in this computation (when using a brute force approach) is 56991483520.
Java's int maximum value is 2^31-1 == 2147483647, which is obviously smaller.
So change your variables etc to use long. Here the max value is 2^63-1 == 9223372036854775807, which will be fitting for all values.
You are breaking the int limit.
Using long:
public static long calc() {
long max = 0;
long maxI = 0;
for (long i = 0; i < 1000000; i++) {
long len = seqLen(i);
if (len >= max) {
max = len;
maxI = i;
}
}
return maxI;
}
public static long seqLen(long seed) {
if (seed <= 0) {
return 0;
}
if (seed == 1) {
return 1;
}
long len = 1;
if (seed % 2 == 0) {
len += seqLen(seed / 2);
} else {
len += seqLen((3 * seed) + 1);
}
return len;
}
public void test() {
System.out.println(seqLen(13));
System.out.println(calc());
}
Gives you the correct result of 837799.
Note that there are better/more efficient algorithms than this one.
Actually, you don't have to check from 1 to 499999.
You only need to check from 500000 to 999999
because the next step of any even number between 500000 and 999999
is going to be some integer from 1 to 499999.
That means that an integer from 1 to 499999 cannot be the answer.
So change the for loop to the following
for (int i = 500000; i < 1000000; i++) {
}
And "i" doesn't have to be long
while "seed" has to be long.
I'm basically trying to rewrite math.pow, I have the following obviously I'm not getting the concept of returning values. What exactly am I doing wrong?
public static int power(int x, int n)
{
if (n == 0) return 1;
int i,total;
for(i = 0; i < n-1 ;i++);
{
total = (x * total);
}
return total;
}
You need to initialize total to 1.
int total = 1;
You can just rewrite everything to:
public static int power(int x, int n)
{
int total = 1;
for(int i = 0; i < n; i++) // i can be declared here directly
{
total = (x * total);
}
return total; // total remains 1 if n = 0
}
public static int power(int x, int n)
{
int total = 1; // Initialized total to 1
for(int i = 0; i < n; i++)
{
total = x*total;
}
return total;
}
instead of i < n-1 you should use i <= n-1 or i < n and int total=1. hope it will work.
also remove ; from the for loop end. rewriting the code
public static int power(int x, int n){
int total=1;
for(int i = 0;i < n;i++)
total *= x;
return total;
}
For one, it looks like you meant:
if (n == 0) return 1;
check the power, not the base number.
You're not initialisign total either, using total = x would fix things i think.
The variable total starts at 0. So calling total = x*total will always be 0.
You need to initialize total to x.
Here is a solution with log(n) complexity instead of linear. Be careful with overflow though.
int pow(int x, int n) {
int res = 1;
while(n > 0) {
if(n % 2 == 1) {
res = res * x;
}
x = x * x;
n = n / 2;
}
return res;
}