I need to write a method that takes 2d array \'int [][] m\' and a value \'val\' and check if val is in the array in the complexity of O(n) while n defined as the num
It is possible iff. the matrix m
is a square matrix of size n x n. Core idea is inspired by oleg.cherednik's answer. As soon as we find a row
in m
, such that m[row][0] >= val
, we know that val
must be in either row row
or row - 1
(since the same comparison on row - 1
was false
). Thus, we have to find our candidate rows (O(n)) and then analyze only those two rows (also O(n)). If m
is not square, but rectangular, the algorithm has a complexity of O(n + k), where n is the number of rows and k is the number of colums in m
. This leads to the following algorithm.
public class Test {
public static boolean contains(final int[][]m, final int value) {
int candidateRow = m.length;
for (int row = 1; row < m.length; ++row) {
if (m[row][0] == value) {
return true;
}
if (m[row][0] > value) {
candidateRow = row;
break;
}
}
for (int val : m[candidateRow - 1]) {
if (val == value) {
return true;
}
}
if (candidateRow < m.length) {
for (int val : m[candidateRow]) {
if (val == value) {
return true;
}
}
}
return false;
}
public static void main(String[] args) {
int [][] testArray = new int [][]{
{ 0, 2, 1, 2, 0, 5, 5, 5 },
{ 21, 21, 7, 7, 7, 21, 21, 21 },
{ 21, 21, 21, 21, 21, 21, 21, 21 },
{ 21, 21, 23, 42, 41, 23, 21, 21 },
{ 60, 56, 57, 58, 53, 52, 47, 51 },
{ 61, 65, 70, 72, 73, 78, 82, 98 },
{ 112, 121, 112, 134, 123, 100, 98, 111 },
{ 136, 136, 136, 134, 147, 150, 154, 134 }
};
for (int[] row : testArray) {
for (int val : row) {
System.out.print(contains(testArray, val) + " ");
}
System.out.println();
}
System.out.println();
System.out.println();
final int[] notInMatrix = { -1, 3, 4, 6, 8, 22, 30, 59, 71, 113, 135 };
for (int val : notInMatrix) {
System.out.print(contains(testArray, val) + " ");
}
System.out.println();
}
}
We can improve the acutal runtime by determining the candidate lines through a binary search algorithm so that candidate lines are found in O(log(n)) instead of O(n). The asymptotical runtime will still be O(n) for square matrices and O(log(n) + k) for non-square n x k matrices. The idea for this was taken from Saeed Bolhasani's answer.
private static int findCandidateRow(final int[][] m, final int value) {
int lower = 0;
int upper = m.length;
int middle = (upper + 1) / 2;
while (middle != m.length
&& middle != 1
&& (m[middle][0] < value || m[middle - 1][0] > value)) {
if (m[middle][0] < value) {
lower = middle;
} else {
upper = middle;
}
middle = lower + (upper - lower + 1) / 2;
}
return middle;
}