Two-Dimentional array circle rotation algorithm? - algorithm

Given NxN two-dimensional array. Write a function that rotates it by 1 element clockwise (almost circling move).
[1][2][3][4]
[5][6][7][8]
[9][0][1][2]
[3][4][5][6]
Becomes:
[5][1][2][3]
[9][0][6][4]
[3][1][7][8]
[4][5][6][2]
Update:
This was an online interview question - HackerRank. I couldn't solve it. All I found in StackOverflow so far are 90-degree rotation (if you found this question somewhere please share the link in comments).

I'm not very sure what kind of problem you've encountered, as obvious solution works well:
original array:
final int[][] a = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 0, 1, 2}, {3, 4, 5, 6}};
rotation:
for (int i = 0; i < (a.length >>> 1); i++) {
final int minx = i;
final int miny = i;
final int maxx = a.length - 1 - i;
final int maxy = a.length - 1 - i;
int incx = 1, incy = 0;
int prev = a[miny][minx];
for (int x = (minx + 1), y = miny; ((x != minx) || (y != miny)); x += incx, y += incy) {
final int temp = a[y][x];
a[y][x] = prev;
prev = temp;
if ((x == maxx) && (incx == 1)) {
incx = 0;
incy = 1;
}
if ((y == maxy) && (incy == 1)) {
incx = -1;
incy = 0;
}
if ((x == minx) && (incx == -1)) {
incx = 0;
incy = -1;
}
}
a[miny][minx] = prev;
}
output:
5 1 2 3
9 0 6 4
3 1 7 8
4 5 6 2

Another solution in Java.
The row and column distances are declared rather than computed.
final int[][] a = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 0, 1, 2 },
{ 3, 4, 5, 6 } };
final int[][] dRow = { { 1, 0, 0, 0 }, { 1, 1, 0, -1 },
{ 1, 0, -1, -1 }, { 0, 0, 0, -1 } };
final int[][] dCol = { { 0, -1, -1, -1 }, { 0, 0, -1, 0 },
{ 0, 1, 0, 0 }, { 1, 1, 1, 0 } };
int[][] tmp = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 } };
// rotate a to tmp
for (int row = 0; row < a.length; row++)
for (int col = 0; col < a[row].length; col++)
tmp[row][col] = a[row + dRow[row][col]][col + dCol[row][col]];
// copy tmp to a
for (int row = 0; row < a.length; row++)
for (int col = 0; col < a[row].length; col++)
a[row][col] = tmp[row][col];
// show result
for (int row = 0; row < a.length; row++)
for (int col = 0; col < a[row].length; col++)
System.out.print((col == 0 ? "\n" : "") + a[row][col]);

I quickly gave this a go, with a slightly different approach in Python for square matrix (you specified NxN). For each layer, I unwrap, rotate and re-apply. This is definitely more work than necessary, but was easy to trace and felt logical - and works for +-n step rotation.
def rotate_matrix(m, n):
assert len(m) is len(m[0]), 'Assertion: rotation requires square matrix'
rotated_matrix = [[None] * len(m[0]) for _ in range(len(m))]
def _rotate_layer(ns):
return ns[n:] + ns[:n]
def _nth_layer(l):
left = [m[i][l-1] for i in range(l-1, len(m)-(l-1))]
bottom = m[len(m)-1-(l-1)][l:len(m)-(l-1)]
right = [m[i][len(m[0])-l] for i in reversed(range(l-1, len(m)-l))]
upper = m[l-1][len(m[0])-l-1:l-1:-1]
return left + bottom + right + upper
def _apply_layer(l):
ns = _rotate_layer(_nth_layer(l))
for i in range(l-1, len(m)-(l-1)):
rotated_matrix[i][l-1] = ns.pop(0)
for i in range(l, len(m)-(l-1)):
rotated_matrix[len(m)-1-(l-1)][i] = ns.pop(0)
for i in reversed(range(l-1, len(m)-l)):
rotated_matrix[i][len(m[0])-l] = ns.pop(0)
for i in reversed(range(l, len(m[0])-l)):
rotated_matrix[l-1][i] = ns.pop(0)
for i in range(1, len(m)/2+1):
_apply_layer(i)
return rotated_matrix

Related

Algorithm puzzle: minimum cost for allow all persons standing on a line to communicate with each other

I have a algorithm design puzzle that I could not solve.
The puzzle is formulated like this: There are N persons standing on a number line, each of them maybe standing on any integer number on that line. Multiple persons may stand on the same number. For any two persons to be able to communicate with each other, the distance between them should be less than K. The goal is to move them so that each pair of two persons can communicate each other (possibly via other people). In other words, we need to move them so that the distance between any neighboring two persons is smaller than K.
Question: What is the minimum number of total moves? It feels like this falls into greedy algorithm family or dynamic programming. Any hints are appreciated!
We can do the following in O(n):
Calculate the cost of moving all people to the right of person i towards person i at an acceptable distance:
costRight(A[i]) = costRight(A[i+1]) + (A[i+1] - A[i] - k + 1) * count of people to the right
K = 3; A = { 0, 3, 11, 17, 21}
costRight = {32, 28, 10, 2, 0}
Calculate the cost of moving all people to the left of person i towards person i at an acceptable distance:
costLeft(A[i]) = costLeft(A[i-1]) + (A[i] - A[i-1] - k + 1) * count of people to the left
K = 3; A = { 0, 3, 11, 17, 21}
costLeft = { 0, 1, 13, 25, 33}
costRight = {32, 28, 10, 2, 0}
Now that we have cost from both directions we can do this in O(n):
minCost = min(costRight + costLeft) for all A[i]
minCost = min(32 + 0, 28 + 1, 13 + 10, 25 + 2, 33 + 0) = 23
But sometimes that's no enough:
K = 3; A = { 0, 0, 1, 8, 8}
carry: -2 -4 3
costLeft = { 0, 0, 0, 11, 11}
carry: -3 5 -2
costRight = { 8, 8, 8, 0, 0}
The optimum is neither 11 nor 8. Test the current best by moving towards the greatest saving:
move 1 to 2, cost = 1
K = 3; A = { 0, 0, 2, 8, 8}
carry: -2 -2 -10
costLeft = { 0, 0, 0, 10, 10}
carry: -2 -2
costRight = { 6, 6, 6, 0, 0}
minCost = 1 + min(0 + 6, 0 + 6, 0 + 6, 10 + 0, 10 + 0) = 1 + 6 = 7
Not quite sure how to formularize this efficiently.
Here is a greedy algorithm written in Java, but I don't know if it gives the optimal solution in every case. Also it is more a proof of concept, there is some room for optimizations.
It is based on the fact that two neighbouring persons must not be more than K apart, the next neighbour must not be more than 2K away and so on. In each step we move the person that "violates these constraints most". The details of this calculation are in method calcForce.
package so;
import java.util.Arrays;
public class Main {
public static void main(String args[]) {
int[] position = new int[] {0, 0, 5, 11, 17, 23};
int k = 5;
solve(position, k);
}
private static void solve(int[] position, int k) {
if (!sorted(position)) {
throw new IllegalArgumentException("positions must be sorted");
}
int[] force = new int[position.length];
int steps = 0;
while (calcForce(position, k, force)) {
int mp = -1;
int mv = -1;
for (int i = 0; i < force.length; i++) {
if (mv < Math.abs(force[i])) {
mv = Math.abs(force[i]);
mp = i;
}
}
System.out.printf("move %d to the %s%n", mp, force[mp] > 0 ? "right" : "left");
if (force[mp] > 0) {
position[mp]++;
} else {
position[mp]--;
}
steps++;
}
System.out.printf("total: %d steps%n", steps);
}
private static boolean calcForce(int[] position, int k, int[] force) {
boolean commProblem = false;
Arrays.fill(force, 0);
for (int i = 0; i < position.length - 1; i++) {
for (int j = i + 1; j < position.length; j++) {
int f = position[j] - position[i] - (j - i) * k;
if (f > 0) {
force[i] += f;
force[j] -= f;
commProblem = true;
}
}
}
return commProblem;
}
private static boolean sorted(int[] position) {
for (int i = 0; i < position.length - 1; i++) {
if (position[i] > position[i+1]) {
return false;
}
}
return true;
}
}

Find all M-length sets of positive integers that sum to N

The problem I'm trying to solve is how do we find all the integer sets [a1, a2, ... ,am] so that
a1 + a2 + ... + am = N
and with the constraint ai >= 1
For example if M = 4, and N = 7 there are three answers
[1,1,1,4]
[1,1,2,3]
[1,2,2,2]
Since you have to print all the sets that sum to N. You can employ a complete search algorithm using recursion. In the following code, M is the number of numbers in the set and N is the sum required.
int M;
int N;
void run(){
M = 4;
N = 7;
int[] arr = new int[M];
print(arr, 0, N, 1);
}
// req holds the required sum for the numbers in the array from arr[from]
// to arr[M-1].
// "last" holds the last value that we had put in the array.
// The first call to the array will be with last=1.
void print(int[] arr, int from, int req, int last){
// Reached the end of the array and sum required 0.
if(from==M && req==0){
System.out.println(Arrays.toString(arr));
return;
}
// Either reached the end of the array but sum is not equal to N
// Or if we have not reached the end of the array but sum has already
// become more than or equal to N.
if(from==M || req<=0){
return;
}
for(int i=last; i<=req; i++){
arr[from] = i;
print(arr, from+1, req-i, i);
}
}
Output for M=4 and N=7:
[1, 1, 1, 4]
[1, 1, 2, 3]
[1, 2, 2, 2]
Output for M=3 and N=10:
[1, 1, 8]
[1, 2, 7]
[1, 3, 6]
[1, 4, 5]
[2, 2, 6]
[2, 3, 5]
[2, 4, 4]
[3, 3, 4]
Answer for the problem in the link, just got accepted.
The idea is simple, assume that we know the maximum value for each section is X, and we want to find a way to divide these cabinets to achieve that , we can greedily divide them as follow:
Starting from first cabinet, iterating through each cabinet, until the total from first to ith cabinet is greater than X. So this is the first section, similarly, we can select other sections. This greedy will always find a solution (if exists).
Finally, we can using binary search to adjust the value of X, decrease X if we can find a way to divide the cabinets, or increase X if we cannot find one.
Here is the code in Java:
public class FairWorkload {
public int getMostWork(int[] folders, int workers) {
int[] data = new int[folders.length];
data[0] = folders[0];
for (int i = 1; i < data.length; i++) {
data[i] = data[i - 1] + folders[i];
}
if (workers == 1) {
return data[data.length - 1];
}
int start = 0;
int end = data[data.length - 1];
int result = Integer.MAX_VALUE;
while (start <= end) {
int mid = (start + end) / 2;
int index = 0;
for (int k = 0; k < workers && index < data.length; k++) {
int less = index > 0 ? data[index - 1] : 0;
int temp = index;
for (int i = index; i < data.length; i++) {
if (data[i] - less <= mid) {
temp = i;
} else {
break;
}
}
// System.out.println(data[temp] - less + " " + mid);
if(data[temp] - less > mid){
index = -1;
break;
}
index = temp + 1;
}
//System.out.println(mid + " " + index);
if (index != data.length) {
start = mid + 1;
} else {
result = Math.min(result, mid);
end = mid - 1;
}
}
return result;
}
public static void main(String[] args) {
int[] data = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1000};
System.out.println(new FairWorkload().getMostWork(data, 2));
}
}
One possible solution uses a counting technique, finding the rightmost term that satisfies [i] <= [length-1] - 2, and then flattening out all other terms to the right as much as possible, keeping a[i] <= a[i+1].
import java.util.Arrays;
public class test {
public static void main(String[] args) {
test t = new test();
t.go();
}
private void go() {
int w = 3;
int sum = 10;
int[] terms = new int[w];
for (int i = 0; i < terms.length; i++) {
terms[i] = 1;
}
terms[w-1] = sum - w + 1;
System.out.println(Arrays.toString(terms));
for (int i = right_index(terms); i>=0; i = right_index(terms)) {
terms[i]++;
int a = terms[i];
int overflow = -1;
// balance all the terms to the right
for (int j = i+1; j < terms.length-1; j++) {
overflow += terms[j] - a;
terms[j] = a;
}
terms[terms.length-1] += overflow;
System.out.println(Arrays.toString(terms));
}
}
// find the rightmost index i, where [i] <= [ia.length-1] - 2
private int right_index(int[] ia) {
int max = ia[ia.length-1];
for (int i = ia.length - 1; i >= 0; i--) {
if (ia[i] <= max - 2)
return i;
}
return -1;
}
}

Check if Sudoku solution is valid [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
You're given a solution to a Sudoku puzzle. Write the code to check if it's a valid solution.
Your function signature should be:
boolean isValid(int starti, int startj, int endi, int endj)
Rules for those unfamiliar with Sudoku:
Grid size is 9x9, divided into 9 regions of 3x3
Each row must contain all digits from 1-9
Each column must contain all digits from 1-9
Each 3x3 square must contain all digits from 1-9
I wasn't asked this question, but saw it on several places. Checking the last rule might be the interesting part
// rows
for (int i=0; i<9; i++) {
std::bitset<9> filled;
for (int j=0; j<9; j++)
filled.set(grid[i][j] - 1);
if (filled.count() != 9)
return false;
}
// ... similar with the loops "swapped" to get the columns
// (or do both in one loop)
for (int i=0; i<9; i += 3)
for (int j=0; j<9; j += 3) {
std::bitset<9> filled;
for (int k=0; k<3; k++)
for (int l=0; l<3; l++)
filled.set(grid[i+k][j+l] - 1);
if (filled.count() != 9)
return false;
}
return true;
Sorry, I know this must be homework, but I can't help myself. It's just too much fun to come up with something :-)
A spoon full of LINQ makes the medicine go down:
public class Sudoku
{
private int[][] sudoku;
public Sudoku(int[][] sudoku)
{
// TODO: Validate bounds and values
this.sudoku = sudoku;
}
public bool Validate() =>
VerticalLines.All(IsValid)
&& HorizontalLines.All(IsValid)
&& Squares.All(IsValid);
IEnumerable<IEnumerable<int>> VerticalLines =>
from line in sudoku select line;
IEnumerable<IEnumerable<int>> HorizontalLines =>
from y in Enumerable.Range(0, 9)
select (
from x in Enumerable.Range(0, 9)
select sudoku[x][y]);
IEnumerable<IEnumerable<int>> Squares =>
from x in Enumerable.Range(0, 3)
from y in Enumerable.Range(0, 3)
select GetSquare(x, y);
IEnumerable<int> GetSquare(int x, int y) =>
from squareX in Enumerable.Range(0, 3)
from squareY in Enumerable.Range(0, 3)
select sudoku[x * 3 + squareX][y * 3 + squareY];
bool IsValid(IEnumerable<int> line) => !(
from item in line
group item by item into g
where g.Count() > 1
select g)
.Any();
}
The nice thing about this solution is, that no teacher will believe you if you say you came up with this ;-)
SQL allows you to define the rules as CONSTRAINTS: invalid puzzels are forbidden and cannot exist.
-- Domain with only values 1..9 allowed,
-- used for both the {x,y,z} coordinates and the cell values.
CREATE DOMAIN one_nine
AS INTEGER
CHECK (value >= 1 AND value <= 9)
;
-- Table containing exactly one sudoku puzzle.
-- The zzz coordinate (the "box number") is formally redundant
-- (since it is functionally dependant on {xxx,yyy})
DROP TABLE IF EXISTS sudoku3 CASCADE;
CREATE TABLE sudoku3
( yyy one_nine NOT NULL
, xxx one_nine NOT NULL
, zzz one_nine NOT NULL
, val one_nine
);
-- First constraint: (x,y) is unique
ALTER TABLE sudoku3 ADD PRIMARY KEY (xxx,yyy);
-- Three constraints for unique values for {rows,columns,boxes}
CREATE UNIQUE INDEX sudoku_xv ON sudoku3 (xxx,val);
CREATE UNIQUE INDEX sudoku_yv ON sudoku3 (yyy,val);
CREATE UNIQUE INDEX sudoku_zv ON sudoku3 (zzz,val);
-- Create empty board.
INSERT INTO sudoku3 (yyy, xxx, zzz)
SELECT 1+(nn/9)
, 1+(nn%9)
, 1+3*((nn/3)%3)+1*(nn/27)
-- generate_series() is postgres-specific
FROM generate_series(0,80) AS nn;
Now, the ->val members can be updated, but the resulting table can never violate any of the four constraints (three are actually INDEXES, but that is unimportant here).
Checking for a completely valid filled-in table means: checking if there are 81 non-NULL entries:
SELECT 1 AS result -- COUNT(*)
FROM sudoku3
WHERE val IS NOT NULL
HAVING COUNT(*) = 81
;
A Java implementation using bit sets:
public static boolean isValid(int[][] board) {
//Check rows and columns
for (int i = 0; i < board.length; i++) {
BitSet bsRow = new BitSet(9);
BitSet bsColumn = new BitSet(9);
for (int j = 0; j < board[i].length; j++) {
if (board[i][j] == 0 || board[j][i] == 0) continue;
if (bsRow.get(board[i][j] - 1) || bsColumn.get(board[j][i] - 1))
return false;
else {
bsRow.set(board[i][j] - 1);
bsColumn.set(board[j][i] - 1);
}
}
}
//Check within 3 x 3 grid
for (int rowOffset = 0; rowOffset < 9; rowOffset += 3) {
for (int columnOffset = 0; columnOffset < 9; columnOffset += 3) {
BitSet threeByThree = new BitSet(9);
for (int i = rowOffset; i < rowOffset + 3; i++) {
for (int j = columnOffset; j < columnOffset + 3; j++) {
if (board[i][j] == 0) continue;
if (threeByThree.get(board[i][j] - 1))
return false;
else
threeByThree.set(board[i][j] - 1);
}
}
}
}
return true;
}
This would my solution in ruby
#Sudoku grid 9x9 with numbers between 1 and 9
#three rules:
#1) in any row all numbers between 1 and 9 have to be present
#2) in any columns all numbers between 1 and 9 have to be present
#3) in any of the 9 3x3 boxes all numbers between 1 and 9 have to be present
sudoku_correct =[[8,3,5,4,1,6,9,2,7],
[2,9,6,8,5,7,4,3,1],
[4,1,7,2,9,3,6,5,8],
[5,6,9,1,3,4,7,8,2],
[1,2,3,6,7,8,5,4,9],
[7,4,8,5,2,9,1,6,3],
[6,5,2,7,8,1,3,9,4],
[9,8,1,3,4,5,2,7,6],
[3,7,4,9,6,2,8,1,5]]
sudoku_incorrect =[[8,3,5,4,1,6,9,2,7],
[2,9,6,8,5,7,4,3,1],
[4,1,7,2,9,3,6,5,8],
[5,6,9,1,3,4,7,8,2],
[1,2,3,6,7,8,5,4,9],
[7,4,8,5,2,9,1,6,3],
[6,5,2,7,8,1,3,9,4],
[9,8,1,3,4,5,2,7,6],
[3,7,4,9,6,2,8,1,1]]
class Sudoku
def initialize(s_arr)
#sudoku_arr = s_arr
end
# given 9 integers makesure that you have 1 to 9
def valid_contents?(set)
set.each do |e|
return false unless (1..9).include?(e)
end
return true
end
# check if set has no duplicates
def has_no_duplicates?(set)
set.uniq.size < set.size ? false : true
end
def valid_set?(set)
valid_contents?(set) && has_no_duplicates?(set)
end
# obtain blocks of sudoku, given a grid
def get_blocks(s_grid)
blocks = []
s_grid.each_slice(3) do |row_set|
blocks_temp = [[],[],[]]
row_set.each do |row|
row.each_slice(3).with_index do|s,i|
blocks_temp[i] = blocks_temp[i] + s
end
end
blocks += blocks_temp
end
blocks
end
def valid?(s_arr = #sudoku_arr)
#check for row validity
s_arr.each do |set|
return false unless valid_set?(set)
end
#check for block validity
get_blocks(s_arr).each do |set|
return false unless valid_set?(set)
end
#check column validity
s_arr.transpose.each do |set|
return false unless valid_set?(set)
end
true
end
end
puts Sudoku.new(sudoku_correct).valid?
puts Sudoku.new(sudoku_incorrect).valid?
# output: True & False
the solution which use just one array iteration.
through the whole iteration of array, posRec array is going to have each numbers availability in ROW/COL/GRID.
if there is missing bit in posRec, we can say sudoku isn’t correct.
#include <stdio.h>
#define ROW 0
#define COL 1
#define GRID 2
#define TRUE 1
#define FALSE 0
char sudoku_correct[9][9] ={{8,3,5,4,1,6,9,2,7},
{2,9,6,8,5,7,4,3,1},
{4,1,7,2,9,3,6,5,8},
{5,6,9,1,3,4,7,8,2},
{1,2,3,6,7,8,5,4,9},
{7,4,8,5,2,9,1,6,3},
{6,5,2,7,8,1,3,9,4},
{9,8,1,3,4,5,2,7,6},
{3,7,4,9,6,2,8,1,5}};
char sudoku_incorrect[9][9] ={{8,3,5,4,1,6,9,2,7},
{2,9,6,8,5,7,4,3,1},
{4,1,7,2,9,3,6,5,8},
{5,6,9,1,3,4,7,8,2},
{1,2,3,6,7,8,5,4,9},
{7,4,8,5,2,9,1,6,3},
{6,5,2,7,8,1,3,9,4},
{9,8,1,3,4,5,2,7,6},
{3,7,4,9,6,2,8,1,1}};
short posRec[9][3];
int isValid(char a[][9]) {
int i, j, val, gIndex;
for(i=0; i <9; i++){
posRec[i][ROW] = 0;
posRec[i][COL] = 0;
posRec[i][GRID] = 0;
}
for(i=0; i<9; i++) {
for(j=0; j<9; j++) {
val=a[i][j]-1; //convert to 0-8 array index
if((posRec[val][ROW]>>i) & 0x1)
return FALSE;
posRec[val][ROW] |= (0x1<<i);
if((posRec[val][COL]>>j) & 0x1)
return FALSE;
posRec[val][COL] |= (0x1<<j);
gIndex = (j/3) + ((i/3) * 3);
if((posRec[val][GRID]>>gIndex) & 0x1)
return FALSE;
posRec[val][GRID] |= (0x1<<gIndex);
}
}
for(i=0; i<9;i++){
if(posRec[i][COL] != 0x1ff ||
posRec[i][ROW] != 0x1ff ||
posRec[i][GRID] != 0x1ff)
return FALSE;
}
return TRUE;
}
int main(){
printf("correct sudoku check = %s \n", isValid(sudoku_correct)?"CORRECT":"INCORRECT");
printf("incorrect sudoku check = %s \n", isValid(sudoku_incorrect)?"CORRECT":"INCORRECT");
return 0;
}
package Questions;
public class SudukoSonChek {
public static void main(String args[]) {
int a[][] = { { 2, 4, 8, 3, 9, 5, 7, 1, 6 },
{ 5, 7, 1, 6, 2, 8, 3, 4, 9 }, { 9, 3, 6, 7, 4, 1, 5, 8, 2 },
{ 6, 8, 2, 5, 3, 9, 1, 7, 4 }, { 3, 5, 9, 1, 7, 4, 6, 2, 8 },
{ 7, 1, 4, 8, 6, 2, 9, 5, 3 }, { 8, 6, 3, 4, 1, 7, 2, 9, 5 },
{ 1, 9, 5, 2, 8, 6, 4, 3, 7 }, { 4, 2, 7, 9, 5, 3, 8, 6, 1 } };
System.out.println(check(a));
}
public static boolean check(int arr[][]) {
int i, j;
int count[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int count1[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
boolean b = true;
for (i = 0; i < 9; i++) {
for (j = 0; j < 9; j++) {
if (count[arr[j][i]] > i) {
b = false;
return b;
}
if (count1[arr[i][j]] > i) {
b = false;
return b;
}
count1[arr[i][j]]++;
count[arr[j][i]]++;
}
}
return b;
}
}
In reference to the excellent answer from #Stephen, here is a solution in C# without resorting to LINQ, to show the difference between the two approaches.
This solution handles both 4x4 and 9x9 Sodoku boards.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Sodoku
{
class Program
{
static void Main(string[] args)
{
List<string> lines = new List<string>();
lines.Add("4;1,4,2,3,2,3,1,4,4,2,3,1,3,1,4,2");
lines.Add("4;2,1,3,2,3,2,1,4,1,4,2,3,2,3,4,1");
lines.Add("9;5,3,4,6,7,8,9,1,2,6,7,2,1,9,5,3,4,8,1,9,8,3,4,2,5,6,7,8,5,9,7,6,1,4,2,3,4,2,6,8,5,3,7,9,1,7,1,3,9,2,4,8,5,6,9,6,1,5,3,7,2,8,4,2,8,7,4,1,9,6,3,5,3,4,5,2,8,6,1,7,9");
lines.Add("9;8,7,1,4,6,9,3,5,2,4,2,6,3,5,1,8,9,7,5,9,3,7,2,8,4,6,1,3,5,2,9,4,7,6,1,8,6,4,9,1,8,2,5,7,3,1,8,7,5,3,6,2,4,9,9,6,4,2,1,3,7,8,5,7,3,8,6,9,5,1,2,4,2,1,5,8,7,4,9,3,6");
lines.Add("9;1,2,7,5,3,9,8,4,6,4,5,3,8,6,1,7,9,2,8,9,6,4,7,2,1,5,3,2,8,9,3,1,7,4,6,5,3,6,5,2,8,4,9,1,7,7,4,1,9,5,6,3,2,8,9,7,4,6,2,8,5,3,1,5,1,2,7,4,3,6,8,9,6,3,8,1,9,5,2,7,4");
lines.Add("4;1,4,4,3,2,3,4,4,3,2,3,1,3,1,4,2");
foreach (var line in lines)
{
var tokens = line.Split(';');
var NxN = int.Parse(tokens[0]);
var nums = tokens[1].Trim().Split(',').Select(int.Parse).ToArray();
// Copy into Grid. Input is in row major form.
var grid = new int[NxN, NxN];
{
int i = 0;
for (int row = 0; row < NxN; row++)
{
for (int col = 0; col < NxN; col++)
{
grid[row, col] = nums[i];
i++;
}
}
}
int violations = 0;
// Check if each column passes tests for Sodoku.
{
for (int row = 0; row < NxN; row++)
{
var tempArray = new int[NxN];
for (int col = 0; col < NxN; col++)
{
tempArray[col] = grid[row, col];
}
if (IfArrayPassesSodoku(tempArray) == false)
{
violations++;
}
}
}
// Check if each row passes tests for Sodoku.
{
for (int row = 0; row < NxN; row++)
{
var tempArray = new int[NxN];
for (int col = 0; col < NxN; col++)
{
tempArray[col] = grid[col, row];
}
if (IfArrayPassesSodoku(tempArray) == false)
{
violations++;
}
}
}
// Check if each sub-grid passes tests for Sodoku.
// In 9x9 Sodoku, there are 9 subgrids of 3x3 each.
{
int NxNsub = (int)Math.Sqrt(NxN); // Length of side of sub-grid, for a 9x9 board this will be 3.
for (int row = 0; row < NxN; row += NxNsub)
{
for (int col = 0; col < NxN; col += NxNsub)
{
var tempArray = new int[NxN];
int index = 0;
for (int i = 0; i < NxNsub; i++)
{
for (int j = 0; j < NxNsub; j++)
{
tempArray[index] = grid[i + col, j + row];
index++;
}
}
if (IfArrayPassesSodoku(tempArray) == false)
{
violations++;
}
}
}
}
Console.WriteLine(violations == 0 ? "True" : "False");
// Correct output is:
// True
// False
// True
// True
// True
// False
}
Console.ReadKey();
}
/// <summary>
/// Checks to see if one-dimensional array passes Sodoku rules:
/// 1. Digits range from 1 to N.
/// 2. No repeating digits.
/// Could be way more efficient, but this solution is more readable compared to other concise forms.
/// </summary>
/// <param name="array">Array.</param>
/// <returns>True if one-dimensional array passes Sodoku rules.</returns>
static bool IfArrayPassesSodoku(int[] array)
{
int violations = 0;
// Check for repeating digits.
bool ifRepeatedDigits = (array.Distinct().ToArray().Length != array.Length);
if (ifRepeatedDigits == true)
{
return false;
}
// Check to see that it contains the digits 1 to N.
var sorted = array.OrderBy(o => o).ToArray();
if (array.Length == 4)
{
if (sorted[0] != 1 || sorted[3] != 4)
{
return false;
}
}
else if (array.Length == 9)
{
if (sorted[0] != 1 || sorted[8] != 9)
{
return false;
}
}
else
{
Console.Write("Error E5234. Invalid grid size.\n");
return false;
}
return true;
}
}
}
I had a similar task, input coming from standard input.
I used sets.
Put the element to the right row, column, and square (called box in my code).
If all 3 set's size is 9, it's valid.
#include <iostream>
#include <set>
int main()
{
//decl
std::set<int> row[9];
std::set<int> column[9];
std::set<int> box[9];
//read & store
for (int i = 0; i < 9; ++i)
{
for (int j = 0; j < 9; ++j)
{
int val;
std::cin >> val;
if ((val >= 1) && (val <= 9))
{
row[i].insert(val);
column[j].insert(val);
int k = j / 3 + i / 3 + i / 3 + i / 3;
box[k].insert(val);
}
}
}
//check
bool l = true;
int i = 0;
while (l && i < 9)
{
l = row[i].size() == 9;
++i;
}
if (!l) std::cout << "Invalid" << std::endl;
else
{
bool l = true;
int i = 0;
while (l && i < 9)
{
l = column[i].size() == 9;
++i;
}
if (!l) std::cout << "Invalid" << std::endl;
else
{
bool l = true;
int i = 0;
while (l && i < 9)
{
l = box[i].size() == 9;
++i;
}
if (!l) std::cout << "Invalid" << std::endl;
else std::cout << "Valid" << std::endl;
}
}
return 0;
}
I thought my solution was terse, but apparently so if everyone else's. Anyways, I think this is a very clear and easy to read answer in ruby I made for an interview question on 7/11/2014:
## Returns true iff the given string is a valid sudoku solution
def is_valid_solution(grid)
return false unless grid.is_a? String and grid.size == 9 * 9
validate_rows(grid) and validate_columns(grid) and validate_boxes(grid)
end
## Returns true iff the set is the chars "1", "2", ..., "9"
def is_valid_set(set)
return false if set.size != 9
(1..9).each do | x |
return false unless set.include?(x.to_s)
end
true
end
def validate_rows(grid)
(0...9).each do | row |
index = row * 9
return false unless is_valid_set(grid[index, 9])
end
true
end
def validate_columns(grid)
(0...9).each do | index |
column = (index...81).step(9).to_a.map { | i | grid[i] }.join
return false unless is_valid_set(column)
end
true
end
## This is ugly, but I'm running out of time...
TOP_LEFT_INDICES = [ 0, 1, 2, 9, 10, 11, 18, 19, 20]
TOP_MID_INDICES = [ 3, 4, 5, 12, 13, 14, 21, 22, 23]
TOP_RIGHT_INDICES = [ 6, 7, 8, 15, 16, 17, 24, 25, 26]
MID_LEFT_INDICES = [27, 28, 29, 36, 37, 38, 45, 46, 47]
MID_MID_INDICES = [30, 31, 32, 39, 40, 41, 48, 49, 50]
MID_RIGHT_INDICES = [33, 34, 35, 42, 43, 44, 51, 52, 53]
BOT_LEFT_INDICES = [54, 55, 56, 63, 64, 65, 72, 73, 74]
BOT_MID_INDICES = [57, 58, 59, 66, 67, 68, 75, 76, 77]
BOT_RIGHT_INDICES = [60, 61, 62, 69, 70, 71, 78, 79, 80]
BOX_INDICES = [TOP_LEFT_INDICES, TOP_MID_INDICES, TOP_RIGHT_INDICES,
MID_LEFT_INDICES, MID_MID_INDICES, MID_RIGHT_INDICES,
BOT_LEFT_INDICES, BOT_MID_INDICES, BOT_RIGHT_INDICES]
def validate_boxes(grid)
BOX_INDICES.each do | indices |
box = indices.map { | i | grid[i] }.join
return false unless is_valid_set(box)
end
true
end
The rows and columns can be validated in a single loop
public class SudokuChecker {
static int[][] sMatrix = {
{5,3,4,6,7,8,9,1,2},
{6,7,2,1,9,5,3,4,8},
{1,9,8,3,4,2,5,6,7},
{8,5,9,7,6,1,4,2,3},
{4,2,6,8,5,3,7,9,1},
{7,1,3,9,2,4,8,5,6},
{9,6,1,5,3,7,2,8,4},
{2,8,7,4,1,9,6,3,5},
{3,4,5,2,8,6,1,7,9}
};
public static void main(String[] args) {
if (rowColumnCheck() && boxCheck()) {
System.out.println("Valid!");
} else {
System.out.println("Invalid!");
}
}
private static boolean boxCheck() {
for (int i = 0; i < sMatrix.length; i += 3) {
for (int j = 0; j < sMatrix.length; j += 3) {
boolean[] gridMatrix = new boolean[9];
for (int k = i; k < 3 + i; k++) {
for (int l = j; l < 3 + j; l++) {
int currentNumber = sMatrix[k][l];
if (currentNumber < 1 || currentNumber > 9) {
return false;
}
gridMatrix[currentNumber - 1] = true;
}
}
for (boolean booleanValue : gridMatrix) {
if (!booleanValue) {
return false;
}
}
}
}
return true;
}
private static boolean rowColumnCheck() {
for (int i = 0; i < 9; i++) {
boolean[] rowArray = new boolean[9];
boolean[] columnArray = new boolean[9];
for (int j = 0; j < 9; j++) {
int currentNumberRow = sMatrix[i][j];
int currentNumberColumn = sMatrix[j][i];
if ((currentNumberRow < 1 || currentNumberRow > 9) && (currentNumberColumn < 1 || currentNumberColumn > 9)) {
return false;
}
rowArray[currentNumberRow - 1] = true;
columnArray[currentNumberColumn - 1] = true;
}
for (boolean booleanValue : rowArray) {
if (!booleanValue) {
return false;
}
}
for (boolean booleanValue : columnArray) {
if (!booleanValue) {
return false;
}
}
}
return true;
}
}

Find longest increasing sequence

You are given a sequence of numbers and you need to find a longest increasing subsequence from the given input(not necessary continuous).
I found the link to this(Longest increasing subsequence on Wikipedia) but need more explanation.
If anyone could help me understand the O(n log n) implementation, that will be really helpful. If you could explain the algo with an example, that will be really appreciated.
I saw the other posts as well and what I did not understand is:
L = 0
for i = 1, 2, ... n:
binary search for the largest positive j ≤ L such that X[M[j]] < X[i] (or set j = 0 if no such value exists)
above statement, from where to start binary search? how to initialize M[], X[]?
A simpler problem is to find the length of the longest increasing subsequence. You can focus on understanding that problem first. The only difference in the algorithm is that it doesn't use the P array.
x is the input of a sequence, so it can be initialized as:
x = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]
m keeps track of the best subsequence of each length found so far. The best is the one with the smallest ending value (allowing a wider range of values to be added after it). The length and ending value is the only data needed to be stored for each subsequence.
Each element of m represents a subsequence. For m[j],
j is the length of the subsequence.
m[j] is the index (in x) of the last element of the subsequence.
so, x[m[j]] is the value of the last element of the subsequence.
L is the length of the longest subsequence found so far. The first L values of m are valid, the rest are uninitialized. m can start with the first element being 0, the rest uninitialized. L increases as the algorithm runs, and so does the number of initialized values of m.
Here's an example run. x[i], and m at the end of each iteration is given (but values of the sequence are used instead of indexes).
The search in each iteration is looking for where to place x[i]. It should be as far to the right as possible (to get the longest sequence), and be greater than the value to its left (so it's an increasing sequence).
0: m = [0, 0] - ([0] is a subsequence of length 1.)
8: m = [0, 0, 8] - (8 can be added after [0] to get a sequence of length 2.)
4: m = [0, 0, 4] - (4 is better than 8. This can be added after [0] instead.)
12: m = [0, 0, 4, 12] - (12 can be added after [...4])
2: m = [0, 0, 2, 12] - (2 can be added after [0] instead of 4.)
10: m = [0, 0, 2, 10]
6: m = [0, 0, 2, 6]
14: m = [0, 0, 2, 6, 14]
1: m = [0, 0, 1, 6, 14]
9: m = [0, 0, 1, 6, 9]
5: m = [0, 0, 1, 5, 9]
13: m = [0, 0, 1, 5, 9, 13]
3: m = [0, 0, 1, 3, 9, 13]
11: m = [0, 0, 1, 3, 9, 11]
7: m = [0, 0, 1, 3, 7, 11]
15: m = [0, 0, 1, 3, 7, 11, 15]
Now we know there is a subsequence of length 6, ending in 15. The actual values in the subsequence can be found by storing them in the P array during the loop.
Retrieving the best sub-sequence:
P stores the previous element in the longest subsequence (as an index of x), for each number, and is updated as the algorithm advances. For example, when we process 8, we know it comes after 0, so store the fact that 8 is after 0 in P. You can work backwards from the last number like a linked-list to get the whole sequence.
So for each number we know the number that came before it. To find the subsequence ending in 7, we look at P and see that:
7 is after 3
3 is after 1
1 is after 0
So we have the subsequence [0, 1, 3, 7].
The subsequences ending in 7 or 15 share some numbers:
15 is after 11
11 is after 9
9 is after 6
6 is after 2
2 is after 0
So we have the subsequences [0, 2, 6, 9, 11], and [0, 2, 6, 9, 11, 15] (the longest increasing subsequence)
One of the best explanation to this problem is given by MIT site.
http://people.csail.mit.edu/bdean/6.046/dp/
I hope it will clear all your doubts.
based on FJB's answer, java implementation:
public class Lis {
private static int[] findLis(int[] arr) {
int[] is = new int[arr.length];
int index = 0;
is[0] = index;
for (int i = 1; i < arr.length; i++) {
if (arr[i] < arr[is[index]]) {
for (int j = 0; j <= index; j++) {
if (arr[i] < arr[is[j]]) {
is[j] = i;
break;
}
}
} else if (arr[i] == arr[is[index]]) {
} else {
is[++index] = i;
}
}
int[] lis = new int[index + 1];
lis[index] = arr[is[index]];
for (int i = index - 1; i >= 0; i--) {
if (is[i] < is[i + 1]) {
lis[i] = arr[is[i]];
} else {
for (int j = is[i + 1] - 1; j >= 0; j--) {
if (arr[j] > arr[is[i]] && arr[j] < arr[is[i + 1]]) {
lis[i] = arr[j];
is[i] = j;
break;
}
}
}
}
return lis;
}
public static void main(String[] args) {
int[] arr = new int[] { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11,
7, 15 };
for (int i : findLis(arr)) {
System.out.print(i + "-");
}
System.out.println();
arr = new int[] { 1, 9, 3, 8, 11, 4, 5, 6, 4, 19, 7, 1, 7 };
for (int i : findLis(arr)) {
System.out.print(i + "-");
}
System.out.println();
}
}
Below is the O(NLogN) longest increasing subsequence implementation:
// search for the index which can be replaced by the X. as the index can't be
//0 or end (because if 0 then replace in the findLIS() and if it's greater than the
//current maximum the just append)of the array "result" so most of the boundary
//conditions are not required.
public static int search(int[] result, int p, int r, int x)
{
if(p > r) return -1;
int q = (p+r)/2;
if(result[q] < x && result[q+1]>x)
{
return q+1;
}
else if(result[q] > x)
{
return search(result, p, q, x);
}
else
{
return search(result, q+1, r, x);
}
}
public static int findLIS(int[] a)
{
int[] result = new int[a.length];
result[0] = a[0];
int index = 0;
for(int i=1; i<a.length; i++)
{
int no = a[i];
if(no < result[0]) // replacing the min number
{
result[0] = no;
}
else if(no > result[index])//if the number is bigger then the current big then append
{
result[++index] = no;
}
else
{
int c = search(result, 0, index, no);
result[c] = no;
}
}
return index+1;
}
Late to the party, but here's a JavaScript implementation to go along with the others.. :)
var findLongestSubsequence = function(array) {
var longestPartialSubsequences = [];
var longestSubsequenceOverAll = [];
for (var i = 0; i < array.length; i++) {
var valueAtI = array[i];
var subsequenceEndingAtI = [];
for (var j = 0; j < i; j++) {
var subsequenceEndingAtJ = longestPartialSubsequences[j];
var valueAtJ = array[j];
if (valueAtJ < valueAtI && subsequenceEndingAtJ.length > subsequenceEndingAtI.length) {
subsequenceEndingAtI = subsequenceEndingAtJ;
}
}
longestPartialSubsequences[i] = subsequenceEndingAtI.concat();
longestPartialSubsequences[i].push(valueAtI);
if (longestPartialSubsequences[i].length > longestSubsequenceOverAll.length) {
longestSubsequenceOverAll = longestPartialSubsequences[i];
}
}
return longestSubsequenceOverAll;
};
Based on #fgb 's answer, I implemented the algorithm using c++ to find the longest strictly increasing sub-sequence. Hope this will be somewhat helpful.
M[i] is the index of the last element of the sequence whose length is i, P[i] is the index of the previous element of i in the sequence, which is used to print the whole sequence.
main() is used to run the simple test case: {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}.
#include <vector>
using std::vector;
int LIS(const vector<int> &v) {
int size = v.size(), max_len = 1;
// M[i] is the index of the last element of the sequence whose length is i
int *M = new int[size];
// P[i] is the index of the previous element of i in the sequence, which is used to print the whole sequence
int *P = new int[size];
M[0] = 0; P[0] = -1;
for (int i = 1; i < size; ++i) {
if (v[i] > v[M[max_len - 1]]) {
M[max_len] = i;
P[i] = M[max_len - 1];
++max_len;
continue;
}
// Find the position to insert i using binary search
int lo = 0, hi = max_len - 1;
while (lo <= hi) {
int mid = lo + ((hi - lo) >> 1);
if (v[i] < v[M[mid]]) {
hi = mid - 1;
} else if (v[i] > v[M[mid]]) {
lo = mid + 1;
} else {
lo = mid;
break;
}
}
P[i] = P[M[lo]]; // Modify the previous pointer
M[lo] = i;
}
// Print the whole subsequence
int i = M[max_len - 1];
while (i >= 0) {
printf("%d ", v[i]);
i = P[i];
}
printf("\n");
delete[] M, delete[] P;
return max_len;
}
int main(int argc, char* argv[]) {
int data[] = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15};
vector<int> v;
v.insert(v.end(), data, data + sizeof(data) / sizeof(int));
LIS(v);
return 0;
}
The O(N lg N) solution comes from patience sorting of playing card. I found this from my code comment and hence sharing here. I believe it would be really easier to understand for everyone how it works. Also you can find all possible longest increasing sub-sequence list if you understand well.
https://www.cs.princeton.edu/courses/archive/spring13/cos423/lectures/LongestIncreasingSubsequence.pdf
Code:
vector<int> lisNlgN(vector<int> v) {
int n = v.size();
vector<int> piles = vector<int>(n, INT_MAX);
int maxLen = 0;
for(int i = 0; i < n; i++) {
int pos = lower_bound(piles.begin(), piles.end(), v[i]) - piles.begin();
piles[pos] = v[i];
maxLen = max(maxLen, pos+1); // Plus 1 because of 0-based index.
}
// // Print piles for debug purpose
// for (auto x : piles) cout << x << " ";
// cout << endl;
//
// // Print position for debug purpose
// for (auto x : position) cout << x << " ";
// cout << endl;
vector<int> ret = vector<int>(piles.begin(), piles.begin() + maxLen);
return ret;
}
Code:
vector<vector<int>> allPossibleLIS(vector<int> v) {
struct Card {
int val;
Card* parent = NULL;
Card(int val) {
this->val = val;
}
};
auto comp = [](Card* a, Card* b) {
return a->val < b->val;
};
int n = v.size();
// Convert integers into card node
vector<Card*> cards = vector<Card*>(n);
for (int i = 0; i < n; i++) cards[i] = new Card(v[i]);
vector<Card*> piles = vector<Card*>(n, new Card(INT_MAX));
vector<Card*> lastPileCards;
int maxLen = 0;
for(int i = 0; i < n; i++) {
int pos = lower_bound(piles.begin(), piles.end(), new Card(v[i]), comp) - piles.begin();
piles[pos] = cards[i];
// Link to top card of left pile
if (pos == 0) cards[i]->parent = NULL;
else cards[i]->parent = piles[pos-1];
// Plus 1 because of 0-based index.
if (pos+1 == maxLen) {
lastPileCards.push_back(cards[i]);
} else if (pos+1 > maxLen) {
lastPileCards.clear();
lastPileCards.push_back(cards[i]);
maxLen = pos + 1;
}
}
// Print for debug purpose
// printf("maxLen = %d\n", maxLen);
// printf("Total unique lis list = %d\n", lastPileCards.size());
vector<vector<int>> ret;
for (auto card : lastPileCards) {
vector<int> lis;
Card* c = card;
while (c != NULL) {
lis.push_back(c->val);
c = c->parent;
}
reverse(lis.begin(), lis.end());
ret.push_back(lis);
}
return ret;
}

Find largest rectangle containing only zeros in an N×N binary matrix

Given an NxN binary matrix (containing only 0's or 1's), how can we go about finding largest rectangle containing all 0's?
Example:
I
0 0 0 0 1 0
0 0 1 0 0 1
II->0 0 0 0 0 0
1 0 0 0 0 0
0 0 0 0 0 1 <--IV
0 0 1 0 0 0
IV
For the above example, it is a 6×6 binary matrix. the return value in this case will be Cell 1:(2, 1) and Cell 2:(4, 4). The resulting sub-matrix can be square or rectangular. The return value can also be the size of the largest sub-matrix of all 0's, in this example 3 × 4.
Here's a solution based on the "Largest Rectangle in a Histogram" problem suggested by #j_random_hacker in the comments:
[Algorithm] works by iterating through
rows from top to bottom, for each row
solving this problem, where the
"bars" in the "histogram" consist of
all unbroken upward trails of zeros
that start at the current row (a
column has height 0 if it has a 1 in
the current row).
The input matrix mat may be an arbitrary iterable e.g., a file or a network stream. Only one row is required to be available at a time.
#!/usr/bin/env python
from collections import namedtuple
from operator import mul
Info = namedtuple('Info', 'start height')
def max_size(mat, value=0):
"""Find height, width of the largest rectangle containing all `value`'s."""
it = iter(mat)
hist = [(el==value) for el in next(it, [])]
max_size = max_rectangle_size(hist)
for row in it:
hist = [(1+h) if el == value else 0 for h, el in zip(hist, row)]
max_size = max(max_size, max_rectangle_size(hist), key=area)
return max_size
def max_rectangle_size(histogram):
"""Find height, width of the largest rectangle that fits entirely under
the histogram.
"""
stack = []
top = lambda: stack[-1]
max_size = (0, 0) # height, width of the largest rectangle
pos = 0 # current position in the histogram
for pos, height in enumerate(histogram):
start = pos # position where rectangle starts
while True:
if not stack or height > top().height:
stack.append(Info(start, height)) # push
elif stack and height < top().height:
max_size = max(max_size, (top().height, (pos - top().start)),
key=area)
start, _ = stack.pop()
continue
break # height == top().height goes here
pos += 1
for start, height in stack:
max_size = max(max_size, (height, (pos - start)), key=area)
return max_size
def area(size):
return reduce(mul, size)
The solution is O(N), where N is the number of elements in a matrix. It requires O(ncols) additional memory, where ncols is the number of columns in a matrix.
Latest version with tests is at https://gist.github.com/776423
Please take a look at Maximize the rectangular area under Histogram and then continue reading the solution below.
Traverse the matrix once and store the following;
For x=1 to N and y=1 to N
F[x][y] = 1 + F[x][y-1] if A[x][y] is 0 , else 0
Then for each row for x=N to 1
We have F[x] -> array with heights of the histograms with base at x.
Use O(N) algorithm to find the largest area of rectangle in this histogram = H[x]
From all areas computed, report the largest.
Time complexity is O(N*N) = O(N²) (for an NxN binary matrix)
Example:
Initial array F[x][y] array
0 0 0 0 1 0 1 1 1 1 0 1
0 0 1 0 0 1 2 2 0 2 1 0
0 0 0 0 0 0 3 3 1 3 2 1
1 0 0 0 0 0 0 4 2 4 3 2
0 0 0 0 0 1 1 5 3 5 4 0
0 0 1 0 0 0 2 6 0 6 5 1
For x = N to 1
H[6] = 2 6 0 6 5 1 -> 10 (5*2)
H[5] = 1 5 3 5 4 0 -> 12 (3*4)
H[4] = 0 4 2 4 3 2 -> 10 (2*5)
H[3] = 3 3 1 3 2 1 -> 6 (3*2)
H[2] = 2 2 0 2 1 0 -> 4 (2*2)
H[1] = 1 1 1 1 0 1 -> 4 (1*4)
The largest area is thus H[5] = 12
Here is a Python3 solution, which returns the position in addition to the area of the largest rectangle:
#!/usr/bin/env python3
import numpy
s = '''0 0 0 0 1 0
0 0 1 0 0 1
0 0 0 0 0 0
1 0 0 0 0 0
0 0 0 0 0 1
0 0 1 0 0 0'''
nrows = 6
ncols = 6
skip = 1
area_max = (0, [])
a = numpy.fromstring(s, dtype=int, sep=' ').reshape(nrows, ncols)
w = numpy.zeros(dtype=int, shape=a.shape)
h = numpy.zeros(dtype=int, shape=a.shape)
for r in range(nrows):
for c in range(ncols):
if a[r][c] == skip:
continue
if r == 0:
h[r][c] = 1
else:
h[r][c] = h[r-1][c]+1
if c == 0:
w[r][c] = 1
else:
w[r][c] = w[r][c-1]+1
minw = w[r][c]
for dh in range(h[r][c]):
minw = min(minw, w[r-dh][c])
area = (dh+1)*minw
if area > area_max[0]:
area_max = (area, [(r-dh, c-minw+1, r, c)])
print('area', area_max[0])
for t in area_max[1]:
print('Cell 1:({}, {}) and Cell 2:({}, {})'.format(*t))
Output:
area 12
Cell 1:(2, 1) and Cell 2:(4, 4)
Here is J.F. Sebastians method translated into C#:
private Vector2 MaxRectSize(int[] histogram) {
Vector2 maxSize = Vector2.zero;
int maxArea = 0;
Stack<Vector2> stack = new Stack<Vector2>();
int x = 0;
for (x = 0; x < histogram.Length; x++) {
int start = x;
int height = histogram[x];
while (true) {
if (stack.Count == 0 || height > stack.Peek().y) {
stack.Push(new Vector2(start, height));
} else if(height < stack.Peek().y) {
int tempArea = (int)(stack.Peek().y * (x - stack.Peek().x));
if(tempArea > maxArea) {
maxSize = new Vector2(stack.Peek().y, (x - stack.Peek().x));
maxArea = tempArea;
}
Vector2 popped = stack.Pop();
start = (int)popped.x;
continue;
}
break;
}
}
foreach (Vector2 data in stack) {
int tempArea = (int)(data.y * (x - data.x));
if(tempArea > maxArea) {
maxSize = new Vector2(data.y, (x - data.x));
maxArea = tempArea;
}
}
return maxSize;
}
public Vector2 GetMaximumFreeSpace() {
// STEP 1:
// build a seed histogram using the first row of grid points
// example: [true, true, false, true] = [1,1,0,1]
int[] hist = new int[gridSizeY];
for (int y = 0; y < gridSizeY; y++) {
if(!invalidPoints[0, y]) {
hist[y] = 1;
}
}
// STEP 2:
// get a starting max area from the seed histogram we created above.
// using the example from above, this value would be [1, 1], as the only valid area is a single point.
// another example for [0,0,0,1,0,0] would be [1, 3], because the largest area of contiguous free space is 3.
// Note that at this step, the heigh fo the found rectangle will always be 1 because we are operating on
// a single row of data.
Vector2 maxSize = MaxRectSize(hist);
int maxArea = (int)(maxSize.x * maxSize.y);
// STEP 3:
// build histograms for each additional row, re-testing for new possible max rectangluar areas
for (int x = 1; x < gridSizeX; x++) {
// build a new histogram for this row. the values of this row are
// 0 if the current grid point is occupied; otherwise, it is 1 + the value
// of the previously found historgram value for the previous position.
// What this does is effectly keep track of the height of continous avilable spaces.
// EXAMPLE:
// Given the following grid data (where 1 means occupied, and 0 means free; for clairty):
// INPUT: OUTPUT:
// 1.) [0,0,1,0] = [1,1,0,1]
// 2.) [0,0,1,0] = [2,2,0,2]
// 3.) [1,1,0,1] = [0,0,1,0]
//
// As such, you'll notice position 1,0 (row 1, column 0) is 2, because this is the height of contiguous
// free space.
for (int y = 0; y < gridSizeY; y++) {
if(!invalidPoints[x, y]) {
hist[y] = 1 + hist[y];
} else {
hist[y] = 0;
}
}
// find the maximum size of the current histogram. If it happens to be larger
// that the currently recorded max size, then it is the new max size.
Vector2 maxSizeTemp = MaxRectSize(hist);
int tempArea = (int)(maxSizeTemp.x * maxSizeTemp.y);
if (tempArea > maxArea) {
maxSize = maxSizeTemp;
maxArea = tempArea;
}
}
// at this point, we know the max size
return maxSize;
}
A few things to note about this:
This version is meant for use with the Unity API. You can easily make this more generic by replacing instances of Vector2 with KeyValuePair. Vector2 is only used for a convenient way to store two values.
invalidPoints[] is an array of bool, where true means the grid point is "in use", and false means it is not.
Solution with space complexity O(columns) [Can be modified to O(rows) also] and time complexity O(rows*columns)
public int maximalRectangle(char[][] matrix) {
int m = matrix.length;
if (m == 0)
return 0;
int n = matrix[0].length;
int maxArea = 0;
int[] aux = new int[n];
for (int i = 0; i < n; i++) {
aux[i] = 0;
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
aux[j] = matrix[i][j] - '0' + aux[j];
maxArea = Math.max(maxArea, maxAreaHist(aux));
}
}
return maxArea;
}
public int maxAreaHist(int[] heights) {
int n = heights.length;
Stack<Integer> stack = new Stack<Integer>();
stack.push(0);
int maxRect = heights[0];
int top = 0;
int leftSideArea = 0;
int rightSideArea = heights[0];
for (int i = 1; i < n; i++) {
if (stack.isEmpty() || heights[i] >= heights[stack.peek()]) {
stack.push(i);
} else {
while (!stack.isEmpty() && heights[stack.peek()] > heights[i]) {
top = stack.pop();
rightSideArea = heights[top] * (i - top);
leftSideArea = 0;
if (!stack.isEmpty()) {
leftSideArea = heights[top] * (top - stack.peek() - 1);
} else {
leftSideArea = heights[top] * top;
}
maxRect = Math.max(maxRect, leftSideArea + rightSideArea);
}
stack.push(i);
}
}
while (!stack.isEmpty()) {
top = stack.pop();
rightSideArea = heights[top] * (n - top);
leftSideArea = 0;
if (!stack.isEmpty()) {
leftSideArea = heights[top] * (top - stack.peek() - 1);
} else {
leftSideArea = heights[top] * top;
}
maxRect = Math.max(maxRect, leftSideArea + rightSideArea);
}
return maxRect;
}
But I get Time Limite exceeded excpetion when I try this on LeetCode. Is there any less complex solution?
I propose a O(nxn) method.
First, you can list all the maximum empty rectangles. Empty means that it covers only 0s. A maximum empty rectangle is such that it cannot be extended in a direction without covering (at least) one 1.
A paper presenting a O(nxn) algorithm to create such a list can be found at www.ulg.ac.be/telecom/rectangles as well as source code (not optimized). There is no need to store the list, it is sufficient to call a callback function each time a rectangle is found by the algorithm, and to store only the largest one (or choose another criterion if you want).
Note that a proof exists (see the paper) that the number of largest empty rectangles is bounded by the number of pixels of the image (nxn in this case).
Therefore, selecting the optimal rectangle can be done in O(nxn), and the overall method is also O(nxn).
In practice, this method is very fast, and is used for realtime video stream analysis.
Here is a version of jfs' solution, which also delivers the position of the largest rectangle:
from collections import namedtuple
from operator import mul
Info = namedtuple('Info', 'start height')
def max_rect(mat, value=0):
"""returns (height, width, left_column, bottom_row) of the largest rectangle
containing all `value`'s.
Example:
[[0, 0, 0, 0, 0, 0, 0, 0, 3, 2],
[0, 4, 0, 2, 4, 0, 0, 1, 0, 0],
[1, 0, 1, 0, 0, 0, 3, 0, 0, 4],
[0, 0, 0, 0, 4, 2, 0, 0, 0, 0],
[0, 0, 0, 2, 0, 0, 0, 0, 0, 0],
[4, 3, 0, 0, 1, 2, 0, 0, 0, 0],
[3, 0, 0, 0, 2, 0, 0, 0, 0, 4],
[0, 0, 0, 1, 0, 3, 2, 4, 3, 2],
[0, 3, 0, 0, 0, 2, 0, 1, 0, 0]]
gives: (3, 4, 6, 5)
"""
it = iter(mat)
hist = [(el==value) for el in next(it, [])]
max_rect = max_rectangle_size(hist) + (0,)
for irow,row in enumerate(it):
hist = [(1+h) if el == value else 0 for h, el in zip(hist, row)]
max_rect = max(max_rect, max_rectangle_size(hist) + (irow+1,), key=area)
# irow+1, because we already used one row for initializing max_rect
return max_rect
def max_rectangle_size(histogram):
stack = []
top = lambda: stack[-1]
max_size = (0, 0, 0) # height, width and start position of the largest rectangle
pos = 0 # current position in the histogram
for pos, height in enumerate(histogram):
start = pos # position where rectangle starts
while True:
if not stack or height > top().height:
stack.append(Info(start, height)) # push
elif stack and height < top().height:
max_size = max(max_size, (top().height, (pos - top().start), top().start), key=area)
start, _ = stack.pop()
continue
break # height == top().height goes here
pos += 1
for start, height in stack:
max_size = max(max_size, (height, (pos - start), start), key=area)
return max_size
def area(size):
return size[0] * size[1]
To be complete, here's the C# version which outputs the rectangle coordinates.
It's based on dmarra's answer but without any other dependencies.
There's only the function bool GetPixel(int x, int y), which returns true when a pixel is set at the coordinates x,y.
public struct INTRECT
{
public int Left, Right, Top, Bottom;
public INTRECT(int aLeft, int aTop, int aRight, int aBottom)
{
Left = aLeft;
Top = aTop;
Right = aRight;
Bottom = aBottom;
}
public int Width { get { return (Right - Left + 1); } }
public int Height { get { return (Bottom - Top + 1); } }
public bool IsEmpty { get { return Left == 0 && Right == 0 && Top == 0 && Bottom == 0; } }
public static bool operator ==(INTRECT lhs, INTRECT rhs)
{
return lhs.Left == rhs.Left && lhs.Top == rhs.Top && lhs.Right == rhs.Right && lhs.Bottom == rhs.Bottom;
}
public static bool operator !=(INTRECT lhs, INTRECT rhs)
{
return !(lhs == rhs);
}
public override bool Equals(Object obj)
{
return obj is INTRECT && this == (INTRECT)obj;
}
public bool Equals(INTRECT obj)
{
return this == obj;
}
public override int GetHashCode()
{
return Left.GetHashCode() ^ Right.GetHashCode() ^ Top.GetHashCode() ^ Bottom.GetHashCode();
}
}
public INTRECT GetMaximumFreeRectangle()
{
int XEnd = 0;
int YStart = 0;
int MaxRectTop = 0;
INTRECT MaxRect = new INTRECT();
// STEP 1:
// build a seed histogram using the first row of grid points
// example: [true, true, false, true] = [1,1,0,1]
int[] hist = new int[Height];
for (int y = 0; y < Height; y++)
{
if (!GetPixel(0, y))
{
hist[y] = 1;
}
}
// STEP 2:
// get a starting max area from the seed histogram we created above.
// using the example from above, this value would be [1, 1], as the only valid area is a single point.
// another example for [0,0,0,1,0,0] would be [1, 3], because the largest area of contiguous free space is 3.
// Note that at this step, the heigh fo the found rectangle will always be 1 because we are operating on
// a single row of data.
Tuple<int, int> maxSize = MaxRectSize(hist, out YStart);
int maxArea = (int)(maxSize.Item1 * maxSize.Item2);
MaxRectTop = YStart;
// STEP 3:
// build histograms for each additional row, re-testing for new possible max rectangluar areas
for (int x = 1; x < Width; x++)
{
// build a new histogram for this row. the values of this row are
// 0 if the current grid point is occupied; otherwise, it is 1 + the value
// of the previously found historgram value for the previous position.
// What this does is effectly keep track of the height of continous avilable spaces.
// EXAMPLE:
// Given the following grid data (where 1 means occupied, and 0 means free; for clairty):
// INPUT: OUTPUT:
// 1.) [0,0,1,0] = [1,1,0,1]
// 2.) [0,0,1,0] = [2,2,0,2]
// 3.) [1,1,0,1] = [0,0,1,0]
//
// As such, you'll notice position 1,0 (row 1, column 0) is 2, because this is the height of contiguous
// free space.
for (int y = 0; y < Height; y++)
{
if (!GetPixel(x, y))
{
hist[y]++;
}
else
{
hist[y] = 0;
}
}
// find the maximum size of the current histogram. If it happens to be larger
// that the currently recorded max size, then it is the new max size.
Tuple<int, int> maxSizeTemp = MaxRectSize(hist, out YStart);
int tempArea = (int)(maxSizeTemp.Item1 * maxSizeTemp.Item2);
if (tempArea > maxArea)
{
maxSize = maxSizeTemp;
maxArea = tempArea;
MaxRectTop = YStart;
XEnd = x;
}
}
MaxRect.Left = XEnd - maxSize.Item1 + 1;
MaxRect.Top = MaxRectTop;
MaxRect.Right = XEnd;
MaxRect.Bottom = MaxRectTop + maxSize.Item2 - 1;
// at this point, we know the max size
return MaxRect;
}
private Tuple<int, int> MaxRectSize(int[] histogram, out int YStart)
{
Tuple<int, int> maxSize = new Tuple<int, int>(0, 0);
int maxArea = 0;
Stack<Tuple<int, int>> stack = new Stack<Tuple<int, int>>();
int x = 0;
YStart = 0;
for (x = 0; x < histogram.Length; x++)
{
int start = x;
int height = histogram[x];
while (true)
{
if (stack.Count == 0 || height > stack.Peek().Item2)
{
stack.Push(new Tuple<int, int>(start, height));
}
else if (height < stack.Peek().Item2)
{
int tempArea = (int)(stack.Peek().Item2 * (x - stack.Peek().Item1));
if (tempArea > maxArea)
{
YStart = stack.Peek().Item1;
maxSize = new Tuple<int, int>(stack.Peek().Item2, (x - stack.Peek().Item1));
maxArea = tempArea;
}
Tuple<int, int> popped = stack.Pop();
start = (int)popped.Item1;
continue;
}
break;
}
}
foreach (Tuple<int, int> data in stack)
{
int tempArea = (int)(data.Item2 * (x - data.Item1));
if (tempArea > maxArea)
{
YStart = data.Item1;
maxSize = new Tuple<int, int>(data.Item2, (x - data.Item1));
maxArea = tempArea;
}
}
return maxSize;
}
An appropriate algorithm can be found within Algorithm for finding the largest inscribed rectangle in polygon (2019).
I implemented it in python:
import largestinteriorrectangle as lir
import numpy as np
grid = np.array([[0, 0, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 1],
[0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1],
[0, 0, 1, 0, 0, 0]],
"bool")
grid = ~grid
lir.lir(grid) # [1, 2, 4, 3]
the result comes as x, y, width, height

Resources