Binary search divide array in 2 parts. But what if I want to divide the array in 4 parts ?
Here is my approach
while (low <= h){
quartal = (low + high) / 4;
if (array[quartal] == x) return quartal;
if (array[2*quartal] == x) return 2*quartal;
if (array[3*quartal] == x) return 3*quartal;
if (array[4*quartal] == x) return 4*quartal;
if (array[quartal] > x) high = quartal-1;
if (array[quartal] < x && array[2*quartal] > x){
low = quartal + 1;
high = 2*quartal-1;
}
if (array[2*quartal] < x && array[3*quartal] > x){
low = quartal + 1;
high = 2*quartal -1;
}
if (array[3*quartal] < x && array[4*quartal] > x){
low = 2*quartal + 1;
high = 3*quartal -1;
}
if (array[4*quartal] < x){
low = 3*quartal + 1;
}
that work but not for all values.
can someone tell me what wrong with my approach?
To answer your question:
Is your array sorted? Binary search only works on sorted arrays.
In the last if-statement, you check if array[4*quartal] < x. Note that this can lead to errors, as quartal is an integer, and therefore 4*quartal will not be equal to (low + high) but rather 4*floor((low+high)/4). Therefore, you may be dividing into 5 segments instead of 5 depending on if (low+heigh) is multiple of 4.
Because 4*quartal should be the end of the segment in your array which you are searching in, I would suggest replacing 4*quartal by (low+high).
I hope this does help.
In addition to what CodingTil has said.
You will have to do the following when doing your checks. Try to think of what would happen with edge cases like a length of 103 or just an array of [0,1]. In your code if we had an array length of 103, we would divide by 4 and get quartels of length 25.75. This can be problematic if we floor the quartel at the start as you'll miss out on values at index 101 and above. You'll have to adjust your other if statements in a similar manner.
if (array[floor(quartal)] == x) return floor(quartal);
if (array[floor(2*quartal)] == x) return floor(2*quartal);
if (array[floor(3*quartal)] == x) return floor(3*quartal);
if (array[high] == x) return high; // should be a whole number so no need to round
Your seventh if statement has an error (your eighth if statement will also have to be adjusted), it should read as follows. And I believe you'll be able to get rid of the ninth if statement altogether.
if (array[floor(2*quartal)] < x && array[floor(3*quartal)] > x){
low = floor(2*quartal) + 1;
high = floor(3*quartal) -1;
}
// high remains unchanged, as we are in the highest quartal
if (array[floor(3*quartal)] < x && array[floor(4*quartal)] > x){
low = floor(3*quartal) + 1;
}
In a sorted array, you can use binary search to perform many different kinds of operations:
to find the first element smaller than the target
to find the first element bigger than the target
or,
to find the first element smaller or equal than the target
to find the first element bigger or equal than the target
or even specific
to find the element closest to the target.
You can find answers to #2 and #5 in stack overflow, the answer of which are using mutations of binary search, however there is no fixed algorithm to answer those questions, specifically in adjusting the indices.
For example, in question 3, find the first smaller or equal element in sorted array than target:
Given int[] stocks = new int[]{1, 4, 3, 1, 4, 6};, I want to find the first element smaller than 5. It should return 4 after sorting and my code goes like:
private static int findMin(int[] arr, int target) {
Arrays.sort(arr);
int lo = 0;
int hi = arr.length - 1;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (arr[mid] == target) return mid;
if (arr[mid] > target) {
hi = mid - 1;
} else {
lo = mid;
}
}
return lo;
}
The logic here is:
if you find mid element equals to target, you just return the mid
if you find mid element bigger than the target, you just discard the mid and everything bigger than it
if you find mid element is smaller than the target, the mid element could be an answer, you want to keep it, but discard anything smaller than it.
If you run it, it actually goes into a infinite loop, but just tweak the start index of hi = arr.length - 1 to hi = arr.length;, it actually works well. I have no clue how to really set all the conditions up: how to write conditions, what to set start index of hi and lo and use lo<=hi or lo < hi.
Any help?
Basically in the above mentioned case ,you need the greatest element which is smaller than the given value, i.e you need to find floor of the given element.
This can be easily done using binary search in O(logn), time :
The cases which you need to consider are as follows:
If last element is smaller than x, than return the last element.
If middle point is floor, than return mid.
If element is not found in both of the above cases, than check if the element lies between mid and mid -1. If it is so than return mid-1.
Else keep iterating on left half or right half until you find a element that satisfies your condition. Select right half or left half based on the check that given value is greater than mid or less than mid.
Try the following:
static int floorInArray(int arr[], int low, int high, int x)
{
if (low > high)
return -1;
// If last element is smaller than x
if (x >= arr[high])
return high;
// Find the middle point
int mid = (low+high)/2;
// If middle point is floor.
if (arr[mid] == x)
return mid;
// If x lies between mid-1 and mid
if (mid > 0 && arr[mid-1] <= x && x < arr[mid])
return mid-1;
// If x is smaller than mid, floor
// must be in left half.
if (x < arr[mid])
return floorInArray(arr, low, mid - 1, x);
// If mid-1 is not floor and x is
// greater than arr[mid],
return floorInArray(arr, mid + 1, high,x);
}
In your while loop, you don't have a case set for when hi == lo
This case is applicable when you are iterating the last element or array has only 1 element.
Set the while loop as while(lo <= hi) and it will terminate when all elements are searched
Or set an if case inside loop for when hi is equal to lo.
if(hi == lo)
Rather than implementing your own binary search, you can just use Arrays.binarySearch(int[] a, int key), then adjust the returned value accordingly.
Returns index of the search key, if it is contained in the array; otherwise, (-(insertion point) - 1). The insertion point is defined as the point at which the key would be inserted into the array: the index of the first element greater than the key, or a.length if all elements in the array are less than the specified key. Note that this guarantees that the return value will be >= 0 if and only if the key is found.
Your rules didn't specify which index to return when there are multiple valid choices (#3 or #4 with multiple equal values, or #5 with equidistant values), so the code below has code making an explicit choice. You can remove the extra code, if you don't care about ambiguities, or change the logic if you disagree with my decision to resolve it.
Note that when return value is <0, returnValue = -insertionPoint - 1, which means that insertionPoint = -returnValue - 1, which in code below mean -idx - 1. Index prior to insertion point is therefore -idx - 2.
The methods may of course return out-of-range index values (-1 or arr.length), so caller always need to check for that. For closest() method, that can only happen if array is empty, in which case it returns -1.
public static int smaller(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx < 0) {
// target not found, so return index prior to insertion point
return -idx - 2;
}
// target found, so skip to before target value(s)
do {
idx--;
} while (idx >= 0 && arr[idx] == target);
return idx;
}
public static int smallerOrEqual(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx < 0) {
// target not found, so return index prior to insertion point
return -idx - 2;
}
// target found, so skip to last of target value(s)
while (idx < arr.length - 1 && arr[idx + 1] == target) {
idx++;
}
return idx;
}
public static int biggerOrEqual(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx < 0) {
// target not found, so return index of insertion point
return -idx - 1;
}
// target found, so skip to first of target value(s)
while (idx > 0 && arr[idx - 1] == target) {
idx--;
}
return idx;
}
public static int bigger(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx < 0) {
// target not found, so return index of insertion point
return -idx - 1;
}
// target found, so skip to after target value(s)
do {
idx++;
} while (idx < arr.length && arr[idx] == target);
return idx;
}
public static int closest(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx >= 0) {
// target found, so skip to first of target value(s)
while (idx > 0 && arr[idx - 1] == target) {
idx--;
}
return idx;
}
// target not found, so compare adjacent values
idx = -idx - 1; // insertion point
if (idx == arr.length) // insert after last value
return arr.length - 1; // last value is closest
if (idx == 0) // insert before first value
return 0; // first value is closest
if (target - arr[idx - 1] > arr[idx] - target)
return idx; // higher value is closer
return idx - 1; // lower value is closer, or equal distance
}
Test
public static void main(String... args) {
int[] arr = {1, 4, 3, 1, 4, 6};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
System.out.println(" | Index | Value |");
System.out.println(" | < <= ~ >= > | < <= ~ >= > |");
System.out.println("--+----------------------+---------------------+");
for (int i = 0; i <= 7; i++)
test(arr, i);
}
public static void test(int[] arr, int target) {
int smaller = smaller (arr, target);
int smallerOrEqual = smallerOrEqual(arr, target);
int closest = closest (arr, target);
int biggerOrEqual = biggerOrEqual (arr, target);
int bigger = bigger (arr, target);
System.out.printf("%d | %3d %3d %3d %3d %3d |%3s %3s %3s %3s %3s | %d%n", target,
smaller, smallerOrEqual, closest, biggerOrEqual, bigger,
(smaller < 0 ? "" : String.valueOf(arr[smaller])),
(smallerOrEqual < 0 ? "" : String.valueOf(arr[smallerOrEqual])),
(closest < 0 ? "" : String.valueOf(arr[closest])),
(biggerOrEqual == arr.length ? "" : String.valueOf(arr[biggerOrEqual])),
(bigger == arr.length ? "" : String.valueOf(arr[bigger])),
target);
}
Output
[1, 1, 3, 4, 4, 6]
| Index | Value |
| < <= ~ >= > | < <= ~ >= > |
--+----------------------+---------------------+
0 | -1 -1 0 0 0 | 1 1 1 | 0
1 | -1 1 0 0 2 | 1 1 1 3 | 1
2 | 1 1 1 2 2 | 1 1 1 3 3 | 2
3 | 1 2 2 2 3 | 1 3 3 3 4 | 3
4 | 2 4 3 3 5 | 3 4 4 4 6 | 4
5 | 4 4 4 5 5 | 4 4 4 6 6 | 5
6 | 4 5 5 5 6 | 4 6 6 6 | 6
7 | 5 5 5 6 6 | 6 6 6 | 7
Try Treesets. If your input is array, follow below steps:
convert array to hash set .
src:https://www.geeksforgeeks.org/program-to-convert-array-to-set-in-java/
2.convert hash set to Tree set.
Tree sets will store the values in sorted order with no duplicates.
Now, call Tree set methods like higher(),ceiling(),floor(),lower() methods as per your requirement.
I was trying to get a grasp of MiniMax algorithm, and have read up on it. My initial approach was to implement a simple MiniMax algorithm, and then to add alpha-beta pruning. However this is my current code:
public int miniMax(char[] node, int playerNum)
{
int victor = checkWin(node); // returns 0 if game is ongoing, 1 for p1, 2 for p2, 3 for tie.
if(victor != 0) //game over .
return score(victor);
if(playerNum == 2) //AI
{
int bestVal = Integer.MIN_VALUE;
int bestSpot = 0;
for(int i = 0; i < node.length; i++)
{
if(node[i] != '-')
continue;
node[i] = getSymbol(playerNum);
int value = miniMax(node, 1);
if(value > bestVal)
{
bestVal = value;
bestSpot = i;
}
node[i] = '-';
}
return bestSpot;
}
else
{
int bestVal = Integer.MAX_VALUE;
int bestSpot = 0;
for(int i = 0; i < node.length; i++)
{
if(node[i] != '-')
continue;
node[i] = getSymbol(playerNum);
int value = miniMax(node, 2);
if(value < bestVal)
{
bestVal = value;
bestSpot = i;
}
node[i] = '-';
}
return bestSpot;
}
}
And my score function
private int Score(int gameState)
{
if(gameState ==2) //O wins.
return 10;
else if(gameState==1) //X wins
return -10;
return 0;
}
Now, I have a working AI that tries to block my move and win, however sometimes it is making non-intelligent choices for instance this is the output I get if my input read from console is 6,7,8 in that order. It does not attempt to block my win. But in other cases it does.
| O | O | |
| | | |
| X | X | X |
In my second attempt I tried 4,3 and it blocked my winning move.
| | O | |
| X | X | O |
| | | |
I was wondering anyone could point out what is wrong with my implementation?
The behavior of the code for the shown examples is correct!
So why is the threat in the following position not blocked? Why does the program play move 1 instead of 6?
O . . O 1 2
. . . numbering available moves: 3 4 5
X X . X X 6
It is because if the game is lost on perfect play the program just plays the first available move.
The algorithm only cares about win or loss and not in how many moves.
See what happens if the threat is blocked:
O . . O . .
. . . . X . and X wins on his next move
X X O X X O
I'm trying to build a sudoku solver. I know my code is messy and there will probably be a much simpler way to do it, but I would like finish the algorithm the way I started.
The algorithm starts doing what I want (filling the blank spaces with the first number that could fit), but when it reaches a point with no options, I don't know how to go back and erase the last number I inserted to try with another combination. But I can't just erase the last number from the matrix because it could be a number that wasn't placed by the algorithm.
If someone could help I would really appreciate it.
public class Backtracking{
public static void Sudoku(int[][] sudokuTable){
if (isAnswer(sudokuTable)){
printSudoku(sudokuTable);
}else{
for (int j = 1; j <=9; j++){
if (canfit(sudokuTable, j)){
addToSudoku(sudokuTable, j);
printSudoku(sudokuTable);
Sudoku(sudokuTable);
}
}
}
}
public static void addToSudoku(int[][] sudokuTable, int n){
int i = 0;
int j = 0;
boolean done = false;
while (i < 9 && !done){
while (j < 9 && !done){
if (sudokuTable[i][j] == 0){
sudokuTable[i][j] = n;
done = true;
}
j++;
}
i++;
}
}
public static void printSudoku(int[][] sudokuTable){
for (int i = 0; i < 9; i++){
for (int j = 0; j < 9; j++){
System.out.print(sudokuTable[i][j] + " ");
}
System.out.println();
}
System.out.println();
}
public static boolean isAnswer(int[][] sudokuTable){
int sum = 0;
for (int i = 0; i < 9; i++){
for (int j = 0 ; j < 9; j++){
if (sudokuTable[i][j] > 9 || sudokuTable[i][j] < 1)
return false;
else
sum++;
}
}
if (sum != 405)
return false;
return true;
}
public static boolean canfit(int[][] sudokuTable, int n){
int i = 0;
int j = 0;
boolean pos = false;
boolean fit = true;
while (i < 9 && !pos){
while (j < 9 && !pos){
if (sudokuTable[i][j] == 0)
pos = true;
else
j++;
}
if (!pos)
i++;
}
for (int k = 0; k < 9; k++){
if (sudokuTable[i][k] == n && k != j)
fit = false;
}
if (fit){
for (int l = 0; l < 9; l++){
if(sudokuTable[l][j] == n && l != i)
fit = false;
}
}
if (fit){
if (i >= 0 && i < 3)
i = 0;
else if (i >=3 && i < 6)
i = 3;
else if (i >=6 && i < 9)
i = 6;
if (j >= 0 && j < 3)
j = 0;
else if (j >=3 && j < 6)
j = 3;
else if (j >=6 && j < 9)
j = 6;
for (int m = i; m < i+3; m++){
for (int o = j; o < j+3; o++){
if (sudokuTable[m][o] == n)
fit = false;
}
}
}
return fit;
}
Try to return true or false from your Sudoko method.
when isAnswer() method returns true, print table. Then return true from Sudoko() method.
Now inside your for loop, where you are calling Sudoko() method recursively, check if it returns true, or false. If it returns true, that means your choice is correct and it leads to a solution, you need not to do anything else. If it returns false, remove the number you set using addToSudoko() method. Make the table as it was before calling addToSudoko() method and continue iterating.
And if your for loop, loops for 9 times and none of the number has a suitable spot, that means if loop ends, return false.
Hope this helps
Actually you can backtracking moves by using an array, each time a move is wrong you just start to remove some moves and try a different move, however this has a problem:
the complexity of trying all possible moves is huge (how long does it takes to try all digits on a number with 81 digits? even if you cut computation time here and there , you will need all the time of the universe)
the main problem in sudoku is that you have no clue which was the wrong move if you move randomly.
Assume the following case sudoky with 2x2 cells:
+----+----++-----+-----+
| 1 | 2 || 3 | 4 |
+----+----++-----+-----+
| 4 | 3 || 1 | 2 |
+====+====++=====+=====+
| 2 | 1 || 4 | 3 |
+----+----++-----+-----+
| 3 | 4 || 2 | 1 |
+----+----++-----+-----+
If you use your algorithm in the following (unsolved) case:
+----+----++-----+-----+
| 1 | || | 4 |
+----+----++-----+-----+
| | || | |
+====+====++=====+=====+
| 2 | || | |
+----+----++-----+-----+
| | 4 || | 1 |
+----+----++-----+-----+
it is possible he will run into the following sequence
+----+----++-----+-----+
| 1 | || 2 | 4 |
+----+----++-----+-----+
| | || 2 | |
+====+====++=====+=====+
| 2 | || | |
+----+----++-----+-----+
| | 4 || | 1 |
+----+----++-----+-----+
Actually the added "twos" are both wrong, but when your algorithm find that those are wrong because you have 2 "twos" in the same column, you don't know which one was the wrong one (the first added, the second added, or both?)
A correct backtracking algorithm would works like this:
You start with a 81 cells arrays, and you start placing numbers (in sequence).
.
for(int i=0; i<81; i++)
array[i] = TryNumber();
.
then you check after each added number if that was correct.
.
if(SomeNumberNotCorrect())
break; // you know you can stop "tryingnumbers" so you can save on loop executions
.
But you don't know which was the wrong number
Now writing a correct algorithm that solves sudokus by attemps and do not run in million of years is pretty long and I cannot write it here but I don't think the way you choosen is the best. The best way is to apply the same strategies used by players. Just keep in mind that if you want an algorithm to resolve sudokus in a similiar way to how Chess is played by computer your algorithm would require much more time than a Chess game (infact a computer cannot analize chess moves more than 5-6 turns). But infact Sudokus can be resolved with much faster algorithms.
Instead I've already done in past a simple solver you could actually try to apply the same strategies a player would use to solve it:
In example:
For each cell, check if current Sector, Column and Line have already all numbers except 1, then you can add that number. And to check that for each cells you just need 81*81*81 moves.
When your solver do not find anymore solutions on a Sudoku, it is just because you have to develop as player a new strategy and then you need to apply it to your program, in short you will have a program that will be able to solve every sudoku (not very hard, and actually this is the reason that there are a lot of free sudoku solvers out there).
I'm working on a project for school that requires me to move a robot. How far the robot will move each second (variable t) is calculated by the function below.
The first function is easy. The 2nd and 3rd on the other are where I'm stuck. How would I write F(t-1)? Below is what I have so far.
if (t == 0) {
distance = 2;
} else if (t > 0 && <=6 || t > 12) {
// No clue on how to write the 2nd distance equation.
} else if (t >= 7 && <=12) {
// No clue on how to write the 3rd distance equation.
}
Recursion really isn't necessary to solve this.
Note that in each of the non-zero time cases, F(t) = F(t-1) + something.
So you can simply do:
double f = 2; /* Initial value at t=0 */
for (int t = 1; t <= maxT; ++t) { // maxT is the maximum value of t.
if (t <= 6 || t > 12) {
f += /* something for case 2 */;
} else {
f += /* something for case 3 */;
}
}
System.out.println(f);
You can do this with recursion, but you will get a StackOverflowError if maxT becomes modestly large; by contrast, using a loop will work for arbitrarily large maxT (modulo floating point errors).
As pointed out by #Andreas, you can do this without looping over all values of t:
double f = 2 * (maxT + 1);
for (int t = 7; t <= maxT && t <= 12; ++t) {
f += log(t) - 2;
}
and you can eliminate that loop too by precomputing the values.
This is a problem which involves the use of recursion. By and large, pay close attention to the notation Ft-1, since that refers to an evaluation of the specific function at t-1.
I won't write out all of the code, but I'll give you some of the basics:
When t = 0, return 2. This is your base case.
When t is between 0 and 6 inclusive or greater than 12, return an evaluation of the function at t-1 and add 2.
When t is between 7 and 12 both inclusive, return an evaluation of the function at t-1 and add log2(t).
Here's something to get you at least started in the right direction.
public double evaluateDistance(int t) {
if(t == 0) {
return 2;
} else if(t > 0 && t <= 6) || (t > 12) {
// Think about this - it would involve another call to evaluateDistance, but what is t again?
} else if(t >= 7 && t <= 12) {
// Another evaluation involving the function.
// For free, the change of base operation you'll need to get base-2 evaluation for the log:
return ??? + Math.log(t)/Math.log(2);
}
}
Think I figured it out. Sorry if I wasn't clear on what I needed, just needed to figure out how to write the equations in the function. Think I figured it out though.
public double move()
{
int t = 0;
if(t == 0) // After the first second, robot moves 2
{
distance = 2;
}
else if(t > 0 && t <= 6 || t > 12) // From seconds 0 to 6 and after 12, robot moves distance equation
{
distance = (2*t)+2;
}
else if(t >= 7 && t <= 12) // From seconds 7 to 12, robot moves distances equation
{
distance = (2*t)+(Math.log(t)/Math.log(2));
}
position = position + distance;
return position;
}
}