I want to find the Complexity of my function and i am not sure if it's O(n) or maybe something else
public static boolean find(int [][] mat, int x)
{
int i = 1;
int j = 0;
int k = 0;
int row = 0;
int col = 0;
int n = mat.length;
while(i < n)//(see method discription)stage 1. loops over maxuim of n/2 times = O(n)
{
i = i * 2;
if(x == mat[i-1][i-1])
return true;
else if (x < mat[i-1][i-1])
{
k = i / 2;
row = col = i-1;
break; //bigger value then x found, x is within the max and min values of the matrix. moving on to find a match.
}
}
if (i > n)//x is bigger then max value of mat
return false;
for (j = k; j > 1; j = j / 2)//stage 2. locking on the right 2x2 matrix. runs k times. k<n O(n)
{
if(x == mat[row-j][col] || x == mat[row][col-j])
return true;
else if(x < mat[row-j][col])
row = row - j;
else if (x < mat[row][col-j])
col = col - j;
}
//checking if x is within this 2x2 matrix
if(x == mat[row][col-1])
return true;
else if(x == mat[row-1][col])
return true;
else if(x == mat[row-1][col-1])
return true;
else
return false;
}
I would say O(log2(n)):
first loop does log2(n) max iterations
second loop depends on k < log2(n) and does max log2(k) operations
Related
I am trying to solve this question:
Given an integer array, adjust each integers so that the difference of
every adjacent integers are not greater than a given number target.
If the array before adjustment is A, the array after adjustment is B,
you should minimize the sum of `| A[i]-B[i] |. You can assume each number in the array is a positive integer and not greater than 100.
`
I see a dp solution but I don't quite understand the recurrence equation.
public static int MinAdjustmentCost(ArrayList<Integer> A, int target) {
// write your code here
if (A == null || A.size() == 0) {
return 0;
}
// D[i][v]: 把index = i的值修改为v,所需要的最小花费
int[][] D = new int[A.size()][101];
int size = A.size();
for (int i = 0; i < size; i++) {
for (int j = 1; j <= 100; j++) {
D[i][j] = Integer.MAX_VALUE;
if (i == 0) {
// The first element.
D[i][j] = Math.abs(j - A.get(i));
} else {
for (int k = 1; k <= 100; k++) {
// 不符合条件
if (Math.abs(j - k) > target) {
continue;
}
int dif = Math.abs(j - A.get(i)) + D[i - 1][k];
D[i][j] = Math.min(D[i][j], dif);
}
}
}
}
int ret = Integer.MAX_VALUE;
for (int i = 1; i <= 100; i++) {
ret = Math.min(ret, D[size - 1][i]);
}
return ret;
}
Could someone explain it to me?
You need to minimize the cost of the adjustment, which is the value you increase/decrease every element such that the difference between every adjacent elements is less than or equal to target. The dp solution is to try every possible value and minimize the cost on the valid ones (when abs(A[i]-A[i-1]) <= target)
First thing is to fill the cost for adjusting first element to 1-100 which is done here:
for (int i = 0; i < size; i++) {
for (int j = 1; j <= 100; j++) {
D[i][j] = Integer.MAX_VALUE; // fill with MAX_VALUE because we want to minimize
if (i == 0) {
// for the first element we just set the cost of adjusting A[i] to j
D[i][j] = Math.abs(j - A.get(i));
}
Now you have D[0][j] as the cost to adjust the first element to be j. Then for every other element, you loop again (from k = 1 to k = 100) for other elements and try to change A[i] to j. And then you check if abs(k-j) is valid (less than or equal to target) then you can adjust A[i] to be j and A[i-1] to be k so you minimize on D[i][j].
Here D[i][j] means the cost of changing A[i] to j and D[i-1][k] is the cost of changing A[i-1] to k. so for every k and j if they are valid (abs(k-j)<=target) then you add them together and minimize the value saved in D[i][j] so you can use it for next element, which is done here:
else {
for (int k = 1; k <= 100; k++) {
// if abs(j-k) > target then changing A[i] to j isn't valid (when A[i-1] is k)
if (Math.abs(j - k) > target) {
continue;
}
// otherwise, calculate the the cost of changing A[i] to j and add to it the cost of changing A[i-1] to k
int dif = Math.abs(j - A.get(i)) + D[i - 1][k];
// minimize D[i][j]
D[i][j] = Math.min(D[i][j], dif);
}
}
At the end, you need to loop from 1 to 100 at the last element and check which is the minimum value over all, which is done here:
int ret = Integer.MAX_VALUE;
for (int i = 1; i <= 100; i++) {
ret = Math.min(ret, D[size - 1][i]);
}
I think if you split the initialization code and the DP calculation code it would be easier to understand, for example:
// fill the initial values
for (int i = 0; i < size; ++i) {
for (int j = 1; j <= 100; ++j) {
// on the first element just save the cost of changing
// A[i] to j
if (i == 0) {
DP[i][j] = abs(j-A.get(i));
} else {
// otherwise intialize with MAX_VALUE
D[i][j] = Integer.MAX_VALUE;
}
}
}
for (int i = 1; i < size; i++) {
for (int j = 1; j <= 100; j++) {
for (int k = 1; k <= 100; k++) {
// if abs(j-k) isn't valid skip it
if (Math.abs(j - k) > target) {
continue;
}
// if it is valid, calculate the cost of changing A[i] to j
// and add it to the cost of changing A[i-1] to k then minimize
// over all values of j and k
int dif = Math.abs(j - A.get(i)) + D[i - 1][k];
D[i][j] = Math.min(D[i][j], dif);
}
}
}
// calculate the minimum cost at the end
int ret = Integer.MAX_VALUE;
for (int i = 1; i <= 100; i++) {
ret = Math.min(ret, D[size - 1][i]);
}
I am trying to solve the Dynamic Problem question to find unique paths between origin and the last cell of a board. The problem is present on leetcode here https://leetcode.com/problems/unique-paths/.
The problem statement is -
A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).
How many possible unique paths are there?
I am stuck on a test case with m = 23 and n = 12. Can you please explain the inconsistency in my code?
public int uniquePaths(int m, int n) {
return getPath(m,n,1,1);
}
HashMap<String,Integer> map = new HashMap<>();
private int getPath(int m, int n, int x, int y){
if(x == n && y == m) return 1;
else if(x > n || y > m) return 0;
String s = ""+x+y;
if(map.get(s) != null) return map.get(s);
int max =0;
if(x < n)
max = max + getPath(m,n,x+1,y);
if(y < m)
max = max + getPath(m,n,x,y+1);
map.put(s,max);
return max;
}
}
On m = 23 and n = 12, I am getting 192184665 as output whereas 193536720 is the expected result.
Look into my comment. You can solve this in Sigma (m * n) with bottom-up dp.
Create an int matrix of size [m * n].
int[] a = new int[n][m];
for (int i = 0; i < n-1; ++i) {
a[i][m-1] = 1;
}
for (int j = 0; i < m-1; ++j) {
a[n-1][j] = 1;
}
for (int i = n-2; i >= 0; --i) {
for (int j = m-2; j >= 0; --j) {
a[i][j] = a[i+1][j] + a[i][j+1];
}
}
System.out.print(a[0][0]);
I need to find the maximum number of consecutive points in a straight line(row,column or diagonal) in a matrix .
For eg:- if it is a 4*4 matrix
input is (1#1,2#2,3#3,2#1) the answer should be 3 as the max consecutive points in diagonal is 3.
My code is successfully getting executed with expected results.But the code complexity is very high.
Can someone please suggest the best approach complexity wise.
Below is my code:
// Get the max number of Continuous points in a matrix row
private static int getMaxContinuousPointsInRow(boolean[][] matrix, int row){
int maxCount = 0;
int currCount = 0;
int pos = 0;
while(pos < matrix[row].length){
currCount = 0;
while(pos < matrix[row].length && !matrix[row][pos])
pos++;
if(pos >= matrix[row].length)
break;
while(pos < matrix[row].length && matrix[row][pos]){
currCount++;
pos++;
}
if(currCount > maxCount)
maxCount = currCount;
}
return maxCount;
}
// Get the max number of Continuous points in a matrix row
private static int getMaxContinuousPointsInCol(boolean[][] matrix, int col) {
int maxCount = 0;
int currCount = 0;
int pos = 0;
while (pos < matrix.length) {
currCount = 0;
while (pos < matrix.length && !matrix[pos][col])
pos++;
if(pos >= matrix.length)
break;
while (pos < matrix.length && matrix[pos][col]) {
currCount++;
pos++;
}
if (currCount > maxCount)
maxCount = currCount;
}
return maxCount;
}
// Get the max number of Continuous points in a matrix diagonal right starting from position (row,col)
private static int getMaxContinuousPointsInDiagonalRight(boolean[][] matrix, int row, int col) {
int maxCount = 0;
int currCount = 0;
int i = row, j = col;
while (i < matrix.length && j < matrix[row].length) {
currCount = 0;
while (i < matrix.length && j < matrix[row].length && !matrix[i][j]){
i++;
j++;
}
if(i >= matrix.length || j >= matrix[row].length)
break;
while (i < matrix.length && j < matrix[row].length && matrix[i][j]) {
currCount++;
i++;
j++;
}
if (currCount > maxCount)
maxCount = currCount;
}
return maxCount;
}
public static int function_called_by_main_method(int input1, int input2, String[] input3) {
// create a boolean matrix of size input1 x input2
// M[i][j] = true if input3 contains a point i#j, else M[i][j] = false
boolean M[][] = new boolean[input1 + 1][input2 + 1];
// initialize the matrix with all false values
for(int i=0; i <= input1; i++){
for(int j=0; j <= input2; j++){
M[i][j] = false;
}
}
// process each value in input3 and populate the matrix
for (String s : input3) {
// extract row, column value
String[] data = s.split("#");
int i = Integer.parseInt(data[0]);
int j = Integer.parseInt(data[1]);
M[i][j] = true;
}
// get max number of Continuous points among all matrix rows
int max = 0;
for(int row = 0; row <= input1; row++){
int rowMax = getMaxContinuousPointsInRow(M, row);
if(rowMax > max)
max = rowMax;
}
// get max number of Continuous points among all matrix rows and columns
for (int col = 0; col <= input2; col++) {
int colMax = getMaxContinuousPointsInCol(M, col);
if (colMax > max)
max = colMax;
}
// get max number of Continuous points among all matrix rows, columns and right diagonals
for(int col = input2 ; col >= 0; col--){
int diagMax = getMaxContinuousPointsInDiagonalRight(M, 0, col);
if(diagMax > max)
max = diagMax;
}
for(int row = 1 ; row <= input1; row++){
int diagMax = getMaxContinuousPointsInDiagonalRight(M, row, 0);
if(diagMax > max)
max = diagMax;
}
return max;
}
You could try parallelism with the java 8 streams, on a dumb brute force approach.
class Coord {
int i;
int j;
}
List<Coord[]> allLineCoords = calculateLinesForMatrix(rows, columns);
Comparator<Coord[]> comparator = (coords1, coords2) ->
length(matrix, coords1) - length(matrix, coords2);
Coord[] maxCoords = allLineCoords.parallelStream()
.max(comparator);
// or for just the max length:
int maxLength = (int) allLineCoords.parallelStream()
.mapToInt(coords -> length(matrix, coords))
.max();
Very unsatisfying is the missing intelligence. And the parallelism only scales to the number of cores of your computer.
// Counts the neighbors of alive or dead cells in boolean grid.
public static int countNeighbors ( final boolean[][] grid, final int row, final int col ) {
// Finds neighbors in top row.
int count = 0;
for (int i = 1; i > -1; --i) {
if (grid[row - 1][col + i] == true)
count += 1;
else if (grid[row - 1][col + i] == false)
count += 0;
}
// Finds neighbors in same row.
for (int i = 1; i > -1; --i) {
if (grid[row][col + i] == true)
count += 1;
else if (grid[row][col + i] == false)
count += 0;
}
// Finds neighbors in bottom row.
for (int i = 1; i > -1; --i) {
if (grid[row + 1][col + i] == true)
count += 1;
else if (grid[row + 1][col + i] == false)
count += 0;
}
return count;
}
Getting an array out of bounds exception when I attempt to find all true neighbor values in all 8 blocks around the specified square.
I figured the code would already handle if it was out of bounds as I assume those values would be false anyways.
Create a separate function to get the grid cell, including a bounds check:
public static boolean getGridCell ( final boolean[][] grid, final int row, final int col )
{
// bounds check:
if((row < 0) || (row >= grid.length))
return false;
if((col < 0) || (col >= grid[row].length))
return false;
return grid[row][col];
}
Then call this function instead of accessing the grid directly:
public static int countNeighbors ( final boolean[][] grid, final int row, final int col ) {
// Finds neighbors in top row.
int count = 0;
for (int i = 1; i >= -1; --i) {
if (getGridCell(grid, row - 1,col + i))
count += 1;
}
// Finds neighbors in same row.
for (int i = 1; i >= -1; --i) {
if (getGridCell(grid, row, col + i))
count += 1;
}
// Finds neighbors in bottom row.
for (int i = 1; i >= -1; --i) {
if (getGridCell(grid, row + 1, col + i))
count += 1;
}
return count;
}
Also:
There's no need to check if the grid cell is empty and add zero to count if it is, because that isn't going to make any difference to the count.
You don't need to test if(some_boolean == true), you can just write if(some_boolean)
Your loop termination condition should be >= -1 not > -1, if you intend include -1.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
I have the below java method called solution, there are two large for loops, as you can see, the two for loops are very samilar, so I think it's possible to refactor the code by having a method like public int getElementSize(ArrayList<Integer> factor1, ArrayList<Integer> factor2) which does the work of the for loop, so I can just call the method twice with different parameters instead repeating the two for loop. But since these two for loops have different loop orders, one from head to tail, another one from tail to head, beside this, all other parts of the loop are the same, any ideas how to refactor this code?
class Solution {
public int solution(int[] A) {
ArrayList<Integer> factor1 = new ArrayList<Integer>();
ArrayList<Integer> factor2 = new ArrayList<Integer>();
int factor = 1;
int N = A.length;
while(factor * factor <= N){
if(N % factor == 0){
factor1.add(factor);
factor2.add(N / factor);
}
factor++;
}
for(int i = 1; i < factor2.size(); i++){
int blockSize = factor2.get(i);
int elementSize = factor1.get(i);
int peaks = 0;
for(int j = 0; j < blockSize; j++){
boolean hasPeak = false;
for(int k = elementSize * j; k < elementSize * (j + 1); k++){
if(k > 0 && k < N - 1){
if(A[k] > A[k - 1] && A[k] > A[k + 1])
hasPeak = true;
}
}
if(!hasPeak)
break;
else
peaks++;
}
if(peaks == blockSize)
return blockSize;
}
for(int i = factor1.size() - 1; i >= 0; i--){
int blockSize = factor1.get(i);
int elementSize = factor2.get(i);
int peaks = 0;
for(int j = 0; j < blockSize; j++){
boolean hasPeak = false;
for(int k = elementSize * j; k < elementSize * (j + 1); k++){
if(k > 0 && k < N - 1){
if(A[k] > A[k - 1] && A[k] > A[k + 1])
hasPeak = true;
}
}
if(!hasPeak)
break;
else
peaks++;
}
if(peaks == blockSize)
return blockSize;
}
return 0;
}
}
How about this?
Conditional operator, ? and : similar to, (these are called ternary operators and resolve at compile time to if else blocks)
if(condition) {
this();
} else {
that();
}
In the above, you can single line that as, (condition ? this() : that())
class Solution {
public int solution(int[] A) {
ArrayList<Integer> factor1 = new ArrayList<Integer>();
ArrayList<Integer> factor2 = new ArrayList<Integer>();
int factor = 1;
int N = A.length;
while(factor * factor <= N){
if(N % factor == 0){
factor1.add(factor);
factor2.add(N / factor);
}
factor++;
}
// let i = 0 to be factor2, i = 1 is factor 1
for(int i = 0; i < 2; i++) {
for(int x = (i == 0 ? 1 : factor1.size() - 1); (i == 0 ? x < factor2.size() : x >= 0); (i == 0 ? x++ : x--)){
int blockSize = (i == 0 ? factor2.get(x) : factor1.get(x));
int elementSize = (i == 0 ? factor1.get(x) : factor2.get(x));
int peaks = 0;
for(int j = 0; j < blockSize; j++){
boolean hasPeak = false;
for(int k = elementSize * j; k < elementSize * (j + 1); k++){
if(k > 0 && k < N - 1){
if(A[k] > A[k - 1] && A[k] > A[k + 1])
hasPeak = true;
}
}
if(!hasPeak)
break;
else
peaks++;
}
if(peaks == blockSize)
return blockSize;
}
}
return 0;
}
}
You can refactor the code inside the the for loops to the new method inside move the two big for loops to the new method, in this way, the order of the two loops are still independent, basically it looks like below, the correctness needs to be verified, this is just one idea to not repeat:
class Solution {
public int solution(int[] A) {
ArrayList<Integer> factor1 = new ArrayList<Integer>();
ArrayList<Integer> factor2 = new ArrayList<Integer>();
int factor = 1;
int N = A.length;
while(factor * factor <= N){
if(N % factor == 0){
factor1.add(factor);
factor2.add(N / factor);
}
factor++;
}
for(int i = 1; i < factor2.size(); i++){
int blockSize = factor2.get(i);
int elementSize = factor1.get(i);
int peaks = getElementSize(A, blockSize, elementSize); //call the method
if(peaks == blockSize)
return blockSize;
}
for(int i = factor1.size() - 1; i >= 0; i--){
int blockSize = factor1.get(i);
int elementSize = factor2.get(i);
int peaks = getElementSize(A, blockSize, elementSize); //call the method
if(peaks == blockSize)
return blockSize;
}
return 0;
}
//this method include the code which was repeated inside the loops
public int getElementSize(int[] A, int blockSize, int elementSize){
int peaks = 0;
int N = A.length;
for(int j = 0; j < blockSize; j++){
boolean hasPeak = false;
for(int k = elementSize * j; k < elementSize * (j + 1); k++){
if(k > 0 && k < N - 1){
if(A[k] > A[k - 1] && A[k] > A[k + 1])
hasPeak = true;
}
}
if(!hasPeak)
break;
else
peaks++;
}
return peaks;
}
}