Search in circular sorted martix and run complexity - java

The method is given NxN matrix always powers of 2 and a number,it will return true if the num is found example for 4x4 size:
this is what i wrote:
public class Search {
public static boolean Search (int [][] matrix, int num)
{
int value = matrix.length / 2;
int first_quarter_pivot = matrix[value-1][0]; // represents highest number in first quarter
int second_quarter_pivot = matrix[value-1][value]; // represents highest number in second quarter
int third_quarter_pivot = matrix[matrix.length-1][value]; // represents highest number in third quarter
int fourth_quarter_pivot = matrix[matrix.length-1][0]; // represents highest number in fourth quarter
boolean isBoolean = false;
int i=0;
int j;
// if the num is not in the range of biggest smallest number it means he can`t be there.
if(!(num >= first_quarter_pivot) && (num <= fourth_quarter_pivot)) {
return false;
}
// if num is one of the pivots return true;
if((num == first_quarter_pivot || (num ==second_quarter_pivot))
|| (num == third_quarter_pivot) || (num == fourth_quarter_pivot ))
return true;
// if num is smaller than first pivot it means num is the first quarter,we limit the search to first quarter.
// if not smaller move to the next quarter pivot
if(num < first_quarter_pivot){{
j =0;
do
if(matrix[i][j] == num) {
isBoolean = true;
break;
}
else if((j == value)) {
j = 0;
i++;
}
else if(matrix[i][j] != num){
j++;
}
while(isBoolean != true) ;
}
return isBoolean;
}
// if num is smaller than second pivot it means num is the second quarter,we limit the search to second quarter.
// if not smaller move to the next quarter pivot
if(num < second_quarter_pivot){{
j = value;// start (0,value) j++ till j=value
do
if(matrix[i][j] == num) {
isBoolean = true;
break;
}
else if((j == matrix.length-1)) {
j = value;
i++;
}
else if(matrix[i][j] != num){
j++;
}
while(isBoolean != true) ;
}
return isBoolean;
}
// if num is smaller than third pivot it means num is the third quarter,we limit the search to third quarter.
// if not smaller move to the next quarter pivot
if(num < third_quarter_pivot){{
i = value;
j = value;// start (0,value) j++ till j=value
do
if(matrix[i][j] == num) {
isBoolean = true;
break;
}
else if((j == matrix.length-1)) {
j = value;
i++;
}
else if(matrix[i][j] != num){
j++;
}
while(isBoolean != true) ;
}
return isBoolean;
}
// if num is smaller than fourth pivot it means num is the fourth quarter,we limit the search to fourth quarter.
// number must be here because we verfied his existence in the start.
if(num < fourth_quarter_pivot){
i = value;
j = 0;// start (0,value) j++ till j=value
do
if(matrix[i][j] == num) {
isBoolean = true;
break;
}
else if((j == value)) {
j = 0;
i++;
}
else if(matrix[i][j] != num){
j++;
}
while(isBoolean != true) ;
}
return isBoolean;
}
}
What i tried to do:
find in which quarter the wanted number is in,after that check
the same quarter by moving j++ until it hits the limit,than i++
until found
with the limits changing for each quarter,i cant understand if run time complexity is O(n^2) or lower? and will it be better do create one dimensional array and and move on the quarter this way: move right until limit,one down,move left until limit and il have a sorted array and just binear search

If you can map an array to a matrix, you can use a normal binary search.
You can define the translation table to achieve that like this:
X = [0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 3, 3, 2, 2, 3, 3, ...]
Y = [0, 1, 1, 0, 2, 3, 3, 2, 2, 3, 3, 2, 0, 1, 1, 0, ...]
The final program looks like this.
static final int MAX_N = 64;
static final int MAX_NN = MAX_N * MAX_N;
static final int[] DX = {0, 0, 1, 1};
static final int[] DY = {0, 1, 1, 0};
static final int[] X = new int[MAX_NN];
static final int[] Y = new int[MAX_NN];
static { // initialize X and Y
for (int i = 0; i < MAX_NN; ++i) {
int x = 0, y = 0;
for (int t = i, f = 0; t > 0; ++f) {
int mod = t & 3;
x += DX[mod] << f; y += DY[mod] << f;
t >>= 2;
}
X[i] = x; Y[i] = y;
}
}
public static boolean Search(int [][] matrix, int num) {
int n = matrix.length, nn = n * n;
int lower = 0;
int upper = nn - 1;
while (lower <= upper) {
int mid = (lower + upper) / 2;
int value = matrix[X[mid]][Y[mid]];
if (value == num)
return true;
else if (value < num)
lower = mid + 1;
else
upper = mid - 1;
}
return false;
}
and
public static void main(String[] args) {
int[][] matrix = {
{1, 3, 7, 9},
{6, 4, 15, 11},
{36, 50, 21, 22},
{60, 55, 30, 26},
};
// case: exists
System.out.println(Search(matrix, 1));
System.out.println(Search(matrix, 60));
System.out.println(Search(matrix, 11));
// case: not exists
System.out.println(Search(matrix, 0));
System.out.println(Search(matrix, 70));
System.out.println(Search(matrix, 20));
}
output:
true
true
true
false
false
false

Related

How to find all the solutions for a NQueens problem given that one queen is fixed at some column?

This is all about the famous NQueens problem. My program works fine (backtrack approach). It finds all the solutions for a given board size.
Code is shown below.
I'm trying to modify the code so that I can find all the solutions for a given column of the first queen. I don't want to change the position of first queen. For an example it will provide me with the solution of
[2, 0, 3, 1, 4] and [2, 4, 1, 3, 0]
when I set the first queen at 2, board size 5 (third column, index starts from zero).
I tried this by setting different values for k (and board[k] as well) but doesn't quite reach the goal.
Any hints will be appreciated.
Here is my code. Removed details about place method since it shouldn't be changed to achieve my new goal.
public class NQueensAllSolutions
{
// Board size
static int size = 8;
// One dimensional array to store the column number for all queens.
static int[] board = new int[size];
// This method will check the validity for a new queen. works fine.
static boolean place(int k)
{
.
.
}
public static void main(String[] args)
{
int k;
long t=0; // for counting total found solutions
k = 0;
board[k] = -1;
while(k >= 0) {
board[k]++;
while(board[k] < size && !(place(k))) board[k]++;
if(board[k] < size) {
if(k == size-1) { // a solution is found.
t++;
//System.out.println("\n\nTotal: "+t+" --> "+Arrays.toString(board));
}
else {
k++; board[k] = -1;
}
}
else {
k--; // backtrack.
}
}
System.out.println("\n\nTotal: "+t);
}
}
Just keep k greater than 0 in the while loop:
import java.util.Arrays;
public class Queens
{
static int size = 5;
static int[] board = new int[size];
static boolean isValid(int k)
{
int c1 = board[k];
int c2 = board[k];
for(int r=k-1;r>=0;r--)
{
c1--;
c2++;
if(board[r] == board[k] || board[r] == c1 || board[r] == c2)
return false;
}
return true;
}
public static void main(String[] args)
{
int t = 0;
// Set the first queen position
board[0] = 2;
int k = 1;
board[k] = -1;
// k must stay greater than 0
while(k >= 1) {
board[k]++;
while(board[k] < size && !isValid(k))
board[k]++;
if(board[k] < size) {
if(k == size-1) {
t++;
System.out.println("Solution "+t+" --> "+Arrays.toString(board));
}
else {
k++;
board[k] = -1;
}
}
else {
k--;
}
}
}
}
Output:
Solution 1 --> [2, 0, 3, 1, 4]
Solution 2 --> [2, 4, 1, 3, 0]
UPDATE
Here is a generalized version that can force a queen at position (fixedRow, fixedCol).
The key change is the new getNextCol() method, which is used to get the next possible column for a queen. On row fixedRow, the only possible column is fixedCol. On the other rows, all columns are possible.
import java.util.Arrays;
public class Queens
{
static int size = 5;
static int fixedRow = 2;
static int fixedCol = 0;
static int[] board = new int[size];
static boolean isValid(int k)
{
int c1 = board[k];
int c2 = board[k];
for(int r=k-1;r>=0;r--)
{
c1--;
c2++;
if(board[r] == board[k] || board[r] == c1 || board[r] == c2)
return false;
}
return true;
}
static int getNextCol(int k, int col)
{
if(k == fixedRow) {
// Only one possible move on this row
return col == -1 ? fixedCol : size;
}
else {
// Try the next column
return col+1;
}
}
public static void main(String[] args)
{
int t = 0;
int k = 0;
board[k] = -1;
while(k >= 0) {
board[k] = getNextCol(k, board[k]);
while(board[k] < size && !isValid(k))
board[k] = getNextCol(k, board[k]);
if(board[k] < size) {
if(k == size-1) {
t++;
System.out.println("Solution "+t+" --> "+Arrays.toString(board));
}
else {
k++;
board[k] = -1;
}
}
else {
k--;
}
}
}
}
Output:
Solution 1 --> [1, 3, 0, 2, 4]
Solution 2 --> [4, 2, 0, 3, 1]

How do i make it so every number that is next to a zero divides by two?

Everything I have tried so far divides the code by 2 and it does it twice for some reason.
CSP-ARRAY
An array inhabitant represents cities and their respective populations. For example, the following arrays shows 8 cities and their respective populations:[3, 6, 0, 4, 3, 2, 7, 1]Some cities have a population of 0 due to a pandemic zombie disease that is wiping away the human lives. After each day, any city that is adjacent to a zombie-ridden city will lose half of its population.Write a program to loop though each city population and make it lose half of its population if it is adjacent (right or left) to a city with zero people until all cities have no humans left.
package Arrays;
public class Project {
public static void main(String[] args){
int i = 0;
boolean hi = false;
boolean hi1 = false;
boolean hi2 = false;
boolean hi3 = false;
boolean hi4 = false;
boolean hi5 = false;
boolean hi6 = false;
boolean hi7 = false;
int[] a = {3, 6, 0, 4, 3, 2, 7, 1};
if(a[0]==0) {
hi=true;
}
if(a[1]==0) {
hi1=true;
}
if(a[2]==0) {
hi2=true;
}
if(a[3]==0) {
hi3=true;
}
if(a[4]==0) {
hi4=true;
}
if(a[5]==0) {
hi5=true;
}
if(a[6]==0) {
hi6=true;
}
if(a[7]==0) {
hi7=true;
}
int z=1;
while(hi!=false || hi1!=false || hi2!=false || hi3!=false || hi4!=false || hi5!=false || hi6!=false || hi7!=false) {
if(hi=true){
a[1]=a[1]/2;
}
if(hi1=true){
a[0]=a[0]/2;
a[2]=a[2]/2;
}
if(hi2=true){
a[1]=a[1]/2;
a[3]=a[3]/2;
}
if(hi3=true){
a[2]=a[2]/2;
a[4]=a[4]/2;
}
if(hi4=true){
a[3]=a[3]/2;
a[5]=a[5]/2;
}
if(hi5=true){
a[4]=a[4]/2;
a[6]=a[6]/2;
}
if(hi6=true){
a[5]=a[5]/2;
a[7]=a[7]/2;
}
if(hi7=true){
a[6]=a[6]/2;
}
System.out.println("Day "+i+": ["+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+", "+a[4]+", "+a[5]+", "+a[6]+", "+a[7]+"] ");
i++;
}
}
}
I think it is pretty simple. Just go through the array and check previous and next value.
public static void calc(int[] arr) {
for(int i = 1; i < arr.length; i++)
if(arr[i] > 0 && arr[i - 1] == 0)
arr[i] /= -2;
for(int i = arr.length - 2; i >= 0; i--)
if(arr[i] < 0)
arr[i] = -arr[i];
else if(arr[i] > 0 && arr[i + 1] == 0)
arr[i] /= 2;
}
I am also new to Java, but here is my attempt.
import java.util.Arrays;
public class Project {
public static void main(String[] args) {
int[] a = {3, 6, 0, 4, 3, 2, 7, 1};
zombieApocalypse(a);
}
public static void zombieApocalypse(int[] array) {
boolean keepGoing = true;
int j = 1;
while (keepGoing) {
int[] arrayCopy = array;
//first element
if (array[0] == 0) {
arrayCopy[1] = array[1] / 2;
}
//element in the middle
for (int i = 1; i < array.length - 1; i++) {
if (array[i] == 0) {
arrayCopy[i - 1] = array[i - 1] / 2;
arrayCopy[i + 1] = array[i + 1] / 2;
}
}
//last element
if (array[array.length - 1] == 0) {
arrayCopy[array.length - 1] = array[array.length - 1] / 2;
}
System.out.println("Day " + j);
//copies clone back to original array
array = arrayCopy;
System.out.println(Arrays.toString(array));
j++;
int counter = 0;
//for each element checking if every city is zero
for (int element : array) {
counter = counter + element;
}
//if each element value in every city is zero, we stop
if (counter == 0) {
keepGoing = false;
}
}
}
}
This is what you were going for.
import java.util.Arrays;
public class Project {
public static void main(String[] args) {
int i = 0;
boolean hi = false;
boolean hi1 = false;
boolean hi2 = false;
boolean hi3 = false;
boolean hi4 = false;
boolean hi5 = false;
boolean hi6 = false;
boolean hi7 = false;
int[] a = {3, 6, 0, 4, 3, 2, 7, 1};
//the line of code below this comment is never used ever, what is it for?
int z = 1;
while ((((!hi || !hi1) || (!hi2 || !hi3)) || (!hi4 || !hi5)) || (!hi6 || !hi7)){
if (hi) {
a[1] = a[1] / 2;
}
if (hi1) {
a[0] = a[0] / 2;
a[2] = a[2] / 2;
}
if (hi2) {
a[1] = a[1] / 2;
a[3] = a[3] / 2;
}
if (hi3) {
a[2] = a[2] / 2;
a[4] = a[4] / 2;
}
if (hi4) {
a[3] = a[3] / 2;
a[5] = a[5] / 2;
}
if (hi5) {
a[4] = a[4] / 2;
a[6] = a[6] / 2;
}
if (hi6) {
a[5] = a[5] / 2;
a[7] = a[7] / 2;
}
if (hi7) {
a[6] = a[6] / 2;
}
System.out.println("Day " + i + Arrays.toString(a));
i++;
/*if you want to update the boolean values after they are changed, then you have to include it within the block of code
that is changing it. (if they are outside of this block of code, how will they ever update?)
*/
if (a[0] == 0) {
hi = true;
}
if (a[1] == 0) {
hi1 = true;
}
if (a[2] == 0) {
hi2 = true;
}
if (a[3] == 0) {
hi3 = true;
}
if (a[4] == 0) {
hi4 = true;
}
if (a[5] == 0) {
hi5 = true;
}
if (a[6] == 0) {
hi6 = true;
}
if (a[7] == 0) {
hi7 = true;
}
}
}
}
For each day iteration, you find the cities that have 0 population and push those indices to an array and let's name this array "indices". Then loop through this array and divide the population half only neighbor of these indices. I write in javascript.
const inhabitants = (Arr) => {
let day = 0;
let A = Arr;
// allEqual checks if the all elements in array is 0
// when allEqual is true loop is over
const allEqual = (arr) => arr.every((v) => v === arr[0]);
while (!allEqual(A)) {
// find the array[i]= 0 and push the "i" in indices
let indices = [];
for (let i = 0; i < A.length; i++) {
if (A[i] === 0) {
indices.push(i);
}
}
// just divide the neighbor elements of element 0
for (let j = 0; j < indices.length; j++) {
if (indices[j] > 0) {
A[indices[j] - 1] = Math.floor(A[indices[j] - 1] / 2);
}
if (indices[j] + 1 < A.length) {
A[indices[j] + 1] = Math.floor(A[indices[j] + 1] / 2);
}
}
day++;
console.log(`population on day ${day}`, A);
}
};

Sum Experiment array / loop dilemma

I am writing a program and I can't seem to make the IF action loop and check all of the arrays in the main. My job is to figure out whether there exists any pair of numbers (i.e., any two elements) in this ascending sorted array that will add up to 20. All you need to do is to sum the values these two pointers point to and see if they are equal to 20, if so, output. otherwise, inspect the sum, if the sum is greater than 20,decrement the second pointer and if the sum is less than 20, increment the first pointer. cannot use the nested for loop approach!! Not sure how to fix this... i've been at it for hours and have handwritten it with no luck. thank you!!
// if val of arr at index i is smaller than at arr j, then return
// smaller value
// This function will inspect the input to find any pair of values that
// add up to 20
// if it find such a pair, it will return the *index* of the smallest
// value
// if it does not find such as pair, it will return -1;
public class SumExperiment {
public static int check_sum(int[] array) {
int i = array[0];
int y = array.indexOf(array.length); // need value # index of array.length to begin
//loop to repeat action
for (int arraysChecked = 0; arraysChecked < 5; arraysChecked++ )
{
if ( i + y == 20)
{
return i;
// System.out.print(array[i]);
}
else if ( i + y > 20)
{
y--; //index #y
}
else if (i + y < 20)
{
i++; //index #x
}
if ( i + y != 20)
{
return -1;
}
arraysChecked++;
}
return -1; //because must return int, but this isn't correct
}
public static void main(String[] args) {
int[] array1 = new int[] { 5, 7, 8, 9, 10, 15, 16 };
if (check_sum(array1) != 0)
System.err.println("TEST1 FAILED");
int[] array2 = new int[] { 3, 5, 8, 9, 10, 15, 16 };
if (check_sum(array2) != 1)
System.err.println("TEST2 FAILED");
int[] array3 = new int[] { 3, 4, 6, 9, 10, 14, 15 };
if (check_sum(array3) != 2)
System.err.println("TEST3 FAILED");
int[] array4 = new int[] { 6, 7, 8, 9, 10, 15, 16 };
if (check_sum(array4) != -1)
System.err.println("TEST4 FAILED");
System.out.println("Done!!!");
}
}
I think you are getting confused between the values in the array and the indices of the values. Here is a working version with variable names that make it easier to understand what's going on:
public static int check_sum(int[] array) {
int leftIndex = 0;
int rightIndex = array.length - 1;
for (int arraysChecked = 0 ; arraysChecked < 5 ; arraysChecked++) {
if (leftIndex == rightIndex) {
return -1;
}
int smallerValue = array[leftIndex];
int largerValue = array[rightIndex];
int sum = smallerValue + largerValue;
if (sum == 20) {
// Returns INDEX of smaller value
return leftIndex;
} else if (sum > 20) {
rightIndex--;
} else if (sum < 20) {
leftIndex++;
}
// NO NEED FOR THIS: arraysChecked++; (for loop does it for you)
}
}

Java: How to implement 3 sum?

I'm studying the 3 Sum to implement it on my own, and came across the following implementation with the rules:
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note: Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
The solution set must not contain duplicate triplets.
For example, given array S = {-1 0 1 2 -1 -4},
A solution set is:
(-1, 0, 1)
(-1, -1, 2)
And implementation (sorts the array, iterates through the list, and uses another two pointers to approach the target):
import java.util.*;
public class ThreeSum {
List<List<Integer>> threeSum(int[] num) {
Arrays.sort(num);
List<List<Integer>> res = new LinkedList<>();
for (int i=0; i<num.length-2; i++) {
if (i==0 || (i>0 && num[i] != num[i-1])) { //HERE
int lo = i+1;
int hi = num.length-1;
int sum = 0 - num[i];
while (lo < hi) {
if (num[lo] + num[hi] == sum) {
res.add(Arrays.asList(num[i], num[lo], num[hi]));
while (lo < hi && num[lo] == num[lo+1]) lo++; //HERE
while (lo < hi && num[hi] == num[hi-1]) hi--; //HERE
lo++; hi--;
} else if (num[lo] + num[hi] < sum) lo++;
else hi--;
}
}
}
return res;
}
//Driver
public static void main(String args[]) {
ThreeSum ts = new ThreeSum();
int[] sum = {-1, 0, 1, 2, -1, -4};
System.out.println(ts.threeSum(sum));
}
}
And my question is (located where commented: //HERE), what's the reason for checking num[i] != num[i-1], num[lo] == num[lo+1], and num[hi] == num[hi-1]? Supposedly they are supposed to skip the same result, but what does that mean? Examples would really help.
Thank you in advance and will accept answer/up vote.
Imagine you have {-1,-1,0,1,2,4} and considering triplet num[0], num[2], num[3] (-1,0,1).
lo=0 here. To exclude triplet num[1], num[2], num[3] with the same values, we should increment lo and pass over duplicate
This will prevent the list to have duplicate triplet.
For example, with you test :
int[] sum = {-1, 0, 1, 2, -1, -4};
will be sorted like :
sum = {-4, -1, -1, 0, 1, 2};
You see that you have -1 twice. Without these test, you would test twice if -1 = 0 + 1. This is not usefull so the algo simply search the next different value.
You could remove duplicate in the sorted List to prevent these test.
Thanks to MBo, we can't remove duplicate since we can have triplet with same value (but with different index)
All the three sentences is used to avoid the duplicate output.
Consider a sorted list {-2, -2 , 1, 1}
If there is no checking for num[i] != num[i-1], the output of the program would be(-2, 1, 1)and(-2, 1, 1), which are two duplicate triplets.
The checking for num[lo] != num[lo + 1]and num[hi] != num[hi - 1] are for the same reason.
Consider a sorted list
{-2,-1,-1,0,3}
If there is no checking for num[lo], you will get (-2,-1,3) and (-2,-1,3) as the output.
Still, I want to recommend a better solution for this problem. You can numerate the sum of two numbers in the list and find the 3rd number by hash or binary search. It will helps you to gain a O(n^2logn) time complexity rather than O(n^3). (I was wrong, the time complexity of this algorithm is O(n^2), sorry for that.)
Following program finds pairs of three integer with O(N*2)
Sort the input Array
and iterate each element in for loop and check for sum in program which is developed for Two sum.
Two sum in linear time after sorting ->
https://stackoverflow.com/a/49650614/4723446
public class ThreeSum {
private static int countThreeSum(int[] numbers) {
int count = 0;
for (int i = 0; i < numbers.length; i++) {
int front = 0, rear = numbers.length - 1;
while (front < rear) {
if (numbers[front] + numbers[rear] + numbers[i] == 0) {
System.out.printf(String.format("Front : {%d} Rear : {%d} I : {%d} \n", numbers[front],
numbers[rear], numbers[i]));
front++;
rear--;
count++;
} else {
if (Math.abs(numbers[front]) > Math.abs(numbers[rear])) {
front++;
} else {
rear--;
}
}
}
}
return count;
}
public static void main(String[] args) {
int[] numbers = { 1, 3, 5, 7, 12, 16, 19, 15, 11, 8, -1, -3, -7, -8, -11, -17, -15 };
Arrays.sort(numbers);
System.out.println(countThreeSum(numbers));
}
}
It's worked with any NSum (3Sum, 4Sum, 5Sum, ...) and quite fast.
public class ThreeSum {
private static final int RANDOM_RANGE = 20;
private Integer array[];
private Integer arrayIndex[];
private int result[];
private int bagLength;
private int resultIndex = 0;
private void generateData(int size) {
array = new Integer[size];
Random random = new Random();
for (int i = 0; i < size; i++) {
array[i] = random.nextInt(RANDOM_RANGE) - (RANDOM_RANGE/2);
}
}
private void markArrayIndex(int size) {
arrayIndex = new Integer[size];
for (int i = 0; i < size; i++) {
arrayIndex[i] = i;
}
}
private void prepareBeforeCalculate(int size, int sumExpected, int bagLength) {
this.bagLength = bagLength;
result = new int[bagLength];
generateData(size);
markArrayIndex(size);
}
void calculate(int size, int sumExpected, int bagLength) {
prepareBeforeCalculate(size, sumExpected, bagLength);
Arrays.sort(arrayIndex, (l, r) -> array[l].compareTo(array[r]));
System.out.println(Arrays.toString(array));
long startAt = System.currentTimeMillis();
if (sumExpected > 0) findLeft(sumExpected, 0, 0, array.length);
else findRight(sumExpected, 0, 0 - 1, array.length - 1);
System.out.println("Calculating in " + ((System.currentTimeMillis() - startAt) / 1000));
}
private void findLeft(int total, int indexBag, int left, int right) {
while (left < array.length && array[arrayIndex[left]] < 0 && indexBag < bagLength) {
navigating(total, arrayIndex[left], indexBag, left, right);
left++;
}
}
private void findRight(int total, int indexBag, int left, int right) {
while (right >= 0 && array[arrayIndex[right]] >= 0 && indexBag < bagLength) {
navigating(total, arrayIndex[right], indexBag, left, right);
right--;
}
}
private void navigating(int total, int index, int indexBag, int left, int right) {
result[indexBag] = index;
total += array[index];
if (total == 0 && indexBag == bagLength - 1) {
System.out.println(String.format("R[%d] %s", resultIndex++, toResultString()));
return;
}
if (total > 0) findLeft(total, indexBag + 1, left + 1, right);
else findRight(total, indexBag + 1, left, right - 1);
}
private String toResultString() {
int [] copyResult = Arrays.copyOf(result, result.length);
Arrays.sort(copyResult);
int iMax = copyResult.length - 1;
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(array[copyResult[i]]);
if (i == iMax)
return b.append(']').toString();
b.append(", ");
}
}
}
public class ThreeSumTest {
#Test
public void test() {
ThreeSum test = new ThreeSum();
test.calculate(100, 0, 3);
Assert.assertTrue(true);
}
}

Finding snake sequence in XY graph - Java

I am working on a problem to try to find what is called a Snake Sequence in a typical XY graph (aka grid). A Snake sequence is defined as a sequence of numbers where each new number, which can only be located to the right or down of the current number, is either plus or minus one. For example, if you are in the center of the graph, you can either move right (if that number is + or - 1) or move down (if that number is + or - 1). The goal of the problem is to find the longest path (aka Snake Sequence) through the graph (keeping in mind you can only chart a path to a new cell whose value is +- 1 with the current cell).
So, for the following XY graph, the longest snake sequence is: 9, 8, 7, 6, 5, 6, 7
9, 6, 5, 2
8, 7, 6, 5
7, 3, 1, 6
1, 1, 1, 7
Below is my code, which does not seem to work.
Question: How would you solve this problem above? (I offer my code showing what I have thus far, but it does not work)
import java.util.ArrayList;
public class SnakeSequence {
private final int maxX = 3;
private final int maxY = 3;
private final int[][] board = new int[][]{
{1, 2, 3, 4},
{2, 1, -1, 5},
{3, 0, -1, 6},
{6, 2, 1, 7}
};
private ArrayList<Integer> findSequence(int xPos,
int yPos, ArrayList<Integer> currentPath) {
currentPath.add(board[yPos][xPos]);
ArrayList<Integer> pathRight = new ArrayList<Integer>(currentPath);
ArrayList<Integer> pathDown = new ArrayList<Integer>(currentPath);
if (xPos < maxX || yPos < maxY) {
if (yPos < maxY && (board[yPos + 1][xPos] + 1 == board[yPos][xPos] ||
board[yPos + 1][xPos] - 1 == board[yPos][xPos])) {
pathDown = findSequence(xPos, yPos + 1, currentPath);
}
if (xPos < maxX && (board[yPos][xPos + 1] + 1 == board[yPos][xPos] ||
board[yPos][xPos + 1] - 1 == board[yPos][xPos])) {
pathRight = findSequence(xPos + 1, yPos, currentPath);
}
if (pathDown.size() > pathRight.size()) {
return pathDown;
} else {
return pathRight;
}
}
return currentPath;
}
private void getSequence() {
ArrayList<Integer> currentPath = new ArrayList<Integer>();
ArrayList<Integer> result;
result = findSequence(0, 0, currentPath);
for (int i = 0; i < result.size(); i++) {
System.out.println(result.get(i));
}
}
public static void main(String[] args) {
SnakeSequence sequence = new SnakeSequence();
sequence.getSequence();
}
}
You can imagine your table as an oriented graph, then you problem is just to find the longest path.
Fortunatly for you, only moving down and right is allowed, so your graph is acyclic, so you can use algorithms like critical path method.
This is how your graph would look like:
However, you want to find longest path between any two cells. To do that, I would compute for each cell the longest path starting at that cell. It is simmilar to what you do, but you compute same thing more times. Consider this:
6 -> 5
| |
v v
7 -> 6
At both 5 and 7 you compute how long is the path from 6 at down right, and that is useless repeated computation. In worst case scenario, this could lead to exponential time consumption, while the problem can be resolved in linear time!
Moreover, there is no guarantee that the longest path will start at (0,0).
(one possible) Solution:
Compute longest path from each cell, starting from bottom-right to upper-left. At each cel.. remember how long the longest path from that cell is, and witch way from that cell the path leads. (I will measure path length by number of cells on it). So for example, for the only 8 in your grapth, we would remeber [length=8, direction=right].
Why so complicated? Because it is now extramly easy to compute longest path at a cell, if we know the longest path of the cells to the right and down. Example (I made up):
The correct data for 2 now would be [length=4, direction=down] because can't go from 2 to 4.
You can also keep globally longest path and it's start. After the computation is complete, just walk the longest path from that start through the direction and write the numbers, position or whatever you need.
Apologies for my Java (I am primarily a c# programmer) but here is one solution. I separated out the algorithm that discovers the snakes from the algorithm (implementing the interface ISnakeProcessor) that processes each one. That way you could enhance the code to, e.g., collect the snake with the largest sum of values, or collect all the longest snakes, in case there are more than one, by adding more ISnakeProcessor classes.
import java.util.*;
import java.lang.*;
class Rextester
{
public static void main(String args[])
{
SnakeSequence sequence = new SnakeSequence();
sequence.getSequence();
}
}
interface ISnakeProcessor
{
void process(List<Pair<Integer, Integer>> snake);
}
class SnakeSequence {
private final int[][] board;
public SnakeSequence()
{
this(new int[][]{
{1, 2, 3, 4},
{2, 1, -1, 5},
{3, 0, -1, 6},
{6, 2, 1, 7}
});
}
public SnakeSequence(int[][] board)
{
this.board = board;
}
public boolean isValid(int iRow, int iCol)
{
if (iRow < 0 || iRow >= board.length)
return false;
if (iCol < 0 || iCol >= board[iRow].length)
return false;
return true;
}
private boolean continuesInRow(int iRow, int iCol)
{
if (!isValid(iRow, iCol) || !isValid(iRow+1, iCol))
return false;
int myVal = board[iRow][iCol];
if (board[iRow+1][iCol] == myVal - 1 || board[iRow+1][iCol] == myVal + 1)
return true;
return false;
}
private boolean continuesInCol(int iRow, int iCol)
{
if (!isValid(iRow, iCol) || !isValid(iRow, iCol+1))
return false;
int myVal = board[iRow][iCol];
if (board[iRow][iCol+1] == myVal - 1 || board[iRow][iCol+1] == myVal + 1)
return true;
return false;
}
private boolean isHead(int iRow, int iCol)
{
if (!isValid(iRow, iCol))
return false;
if (isValid(iRow-1, iCol) && continuesInRow(iRow-1, iCol))
return false;
if (isValid(iRow, iCol-1) && continuesInRow(iRow, iCol-1))
return false;
return true;
}
private boolean isTail(int iRow, int iCol)
{
if (!isValid(iRow, iCol))
return false;
if (continuesInRow(iRow, iCol))
return false;
if (continuesInCol(iRow, iCol))
return false;
return true;
}
private void testHead()
{
System.out.println("Dumping list of heads");
for (int iRow = 0; iRow < board.length; iRow++)
{
for (int iCol = 0; iCol < board[iRow].length; iCol++)
{
boolean head = isHead(iRow, iCol);
boolean tail = isTail(iRow, iCol);
if (head && tail)
System.out.print(" B");
else if (head)
System.out.print(" H");
else if (tail)
System.out.print(" T");
else
System.out.print(" -");
}
System.out.println("");
}
}
private void walkSnake(ISnakeProcessor processor, int iRow, int iCol, ArrayList<Pair<Integer, Integer>> snake)
{
snake.add(new Pair<Integer, Integer>(iRow, iCol));
boolean isTail = true;
if (continuesInRow(iRow, iCol))
{
walkSnake(processor, iRow+1, iCol, snake);
isTail = false;
}
if (continuesInCol(iRow, iCol))
{
walkSnake(processor, iRow, iCol+1, snake);
isTail = false;
}
if (isTail)
{
processor.process(snake);
}
snake.remove(snake.size() - 1);
}
private void walkSnakes(ISnakeProcessor processor)
{
ArrayList<Pair<Integer, Integer>> snake = new ArrayList<Pair<Integer, Integer>>();
for (int iRow = 0; iRow < board.length; iRow++)
for (int iCol = 0; iCol < board[iRow].length; iCol++)
if (isHead(iRow, iCol))
walkSnake(processor, iRow, iCol, snake);
}
class LongestSnakeFinder implements ISnakeProcessor
{
private final SnakeSequence parent;
ArrayList<Pair<Integer, Integer>> longest = new ArrayList<Pair<Integer, Integer>>();
public LongestSnakeFinder(SnakeSequence parent)
{
this.parent = parent;
}
public void process(List<Pair<Integer, Integer>> snake)
{
if (snake.size() > longest.size())
{
longest.clear();
longest.addAll(snake);
}
}
public void dumpLongest()
{
System.out.format("The first encountered longest snake has length %d:\n", longest.size());
for (int i = 0; i < longest.size(); i++)
{
int iRow = longest.get(i).getFirst();
int iCol = longest.get(i).getSecond();
System.out.format(" (%d,%d): %d\n", iRow, iCol, parent.getValue(iRow, iCol));
}
}
}
public int getNRows() { return board.length; }
public int getNCols(int iRow) { return board[iRow].length; }
public int getValue(int iRow, int iCol) { return board[iRow][iCol]; }
public void getSequence() {
testHead();
LongestSnakeFinder finder = new LongestSnakeFinder(this);
walkSnakes(finder);
finder.dumpLongest();
}
}
class Pair<F, S> {
private F first; //first member of pair
private S second; //second member of pair
public Pair(F first, S second) {
this.first = first;
this.second = second;
}
public F getFirst() {
return first;
}
public S getSecond() {
return second;
}
}
Example run here: http://rextester.com/AKUFNL43897
Update - cleaned code a little. New sample run here: http://rextester.com/AVOAIY11573
And, the output:
Dumping list of heads
H - - -
- - B -
T - T -
B H T T
The first encountered longest snake has length 7:
(0,0): 1
(0,1): 2
(0,2): 3
(0,3): 4
(1,3): 5
(2,3): 6
(3,3): 7
Is this what you want?
Here is one simple way to correct your solution and avoid copying of path on every step
import java.util.ArrayList;
import java.util.Collections;
public class SnakeSequence {
private final int maxX = 3;
private final int maxY = 3;
private final int[][] board = new int[][]{
{1, 2, 3, 4},
{2, 1, -1, 5},
{3, 0, -1, 6},
{6, 2, 1, 7}
};
private ArrayList<Integer> findSequence(int xPos,
int yPos) {
ArrayList<Integer> pathRight = new ArrayList<Integer>();
ArrayList<Integer> pathDown = new ArrayList<Integer>();
if (yPos < maxY && (board[yPos + 1][xPos] + 1 == board[yPos][xPos] ||
board[yPos + 1][xPos] - 1 == board[yPos][xPos])) {
pathDown = findSequence(xPos, yPos + 1);
}
if (xPos < maxX && (board[yPos][xPos + 1] + 1 == board[yPos][xPos] ||
board[yPos][xPos + 1] - 1 == board[yPos][xPos])) {
pathRight = findSequence(xPos + 1, yPos);
}
ArrayList<Integer> ans;
if (pathDown.size() > pathRight.size()) {
ans = pathDown;
} else {
ans = pathRight;
}
ans.add(board[yPos][xPos]);
return ans;
}
private void getSequence() {
ArrayList<Integer> result;
result = findSequence(0, 0);
Collections.reverse(result);
for (int i = 0; i < result.size(); i++) {
System.out.println(result.get(i));
}
}
public static void main(String[] args) {
SnakeSequence sequence = new SnakeSequence();
sequence.getSequence();
}
}
But this way it can work much faster for big arrays due to no recalculating the longest path every time you visiting the same number during recursion. Actually, in this version each number is visited at most twice. It's achieved through saving best solution for every node. Separate storage of path and it length allows not to copy path when it's not needed.
import java.util.ArrayList;
import java.util.Collections;
public class SnakeSequence {
private final int maxX = 3;
private final int maxY = 3;
private final int[][] board = new int[][]{
{1, 2, 3, 4},
{2, 3, -1, 5},
{3, 2, -1, 6},
{6, 1, 2, 3}
};
int[][] pathLength;
ArrayList<ArrayList<ArrayList<Integer>>> paths;
private ArrayList<Integer> findSequence(int xPos,
int yPos) {
if(pathLength[yPos][xPos] >= 0)
{
ArrayList<Integer> ans = new ArrayList<Integer>();
int length = pathLength[yPos][xPos];
ArrayList<Integer> path = paths.get(yPos).get(xPos);
for(int i = 0; i < length; i++)
ans.add(path.get(i));
return ans;
}
ArrayList<Integer> pathRight = new ArrayList<Integer>();
ArrayList<Integer> pathDown = new ArrayList<Integer>();
if (yPos < maxY && (board[yPos + 1][xPos] + 1 == board[yPos][xPos] ||
board[yPos + 1][xPos] - 1 == board[yPos][xPos])) {
pathDown = findSequence(xPos, yPos + 1);
}
if (xPos < maxX && (board[yPos][xPos + 1] + 1 == board[yPos][xPos] ||
board[yPos][xPos + 1] - 1 == board[yPos][xPos])) {
pathRight = findSequence(xPos + 1, yPos);
}
ArrayList<Integer> ans;
if (pathDown.size() > pathRight.size()) {
ans = pathDown;
} else {
ans = pathRight;
}
ans.add(board[yPos][xPos]);
paths.get(yPos).set(xPos,ans);
pathLength[yPos][xPos] = ans.size();
return ans;
}
private void getSequence() {
ArrayList<Integer> result;
pathLength = new int[maxX + 1][maxY + 1];
paths = new ArrayList<ArrayList<ArrayList<Integer>>>();
for(int y = 0; y <= maxY; y++)
{
ArrayList<ArrayList<Integer>> line = new ArrayList<ArrayList<Integer>>();
for(int x = 0; x <= maxX; x++)
{
line.add(null);
pathLength[y][x] = -1;
}
paths.add(line);
}
result = findSequence(0, 0);
Collections.reverse(result);
for (int i = 0; i < result.size(); i++) {
System.out.println(result.get(i));
}
}
public static void main(String[] args) {
SnakeSequence sequence = new SnakeSequence();
sequence.getSequence();
}
}
Simple Recursive solution :
import java.util.ArrayList;
import java.util.List;
public class MaximumLengthSnakeSequence {
static int max = -1;
static List<Integer> maxListTemp = new ArrayList<>();
public static void main(String args[]) {
int count = 0;
int n = 4;
int m = 4;
int mat[][] = { { 9, 6, 5, 2 }, { 8, 7, 6, 5 }, { 7, 3, 1, 6 }, { 1, 1, 1, 7 }, };
List<Integer> maxList = new ArrayList<>();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
List<Integer> list = new ArrayList<>();
list.add(mat[i][j]);
List<Integer> testList = recur(i, j, count, mat, n, m, list);
if (maxList.size() < testList.size()) {
maxList = new ArrayList<>(testList);
}
maxListTemp.clear();
}
}
System.out.println("max is " + maxList);
}
static List<Integer> recur(int i, int j, int count, int mat[][], int n, int m, List<Integer> list) {
int curData = mat[i][j];
int rightData = 0;
int downData = 0;
if (j + 1 < n && i < m) {
rightData = mat[i][j + 1];
if (Math.abs(curData - rightData) == 1) {
list.add(rightData);
recur(i, j + 1, count + 1, mat, n, m, list);
list.remove(list.size() - 1);
}
}
if (count > max) {
max = count;
}
if (maxListTemp.size() < list.size()) {
maxListTemp = new ArrayList<>(list);
}
if (i + 1 < m && j < n) {
downData = mat[i + 1][j];
if (Math.abs(curData - downData) == 1) {
list.add(downData);
recur(i + 1, j, count + 1, mat, n, m, list);
list.remove(list.size() - 1);
}
}
return maxListTemp;
}
}

Categories