I'm a beginner and I'm trying to figure out a way to get the corresponding neighbors of an index in a 2D array.
public class Main {
public static int[][] graph(){
int[][] myGraph = {
{1, 2, 3, 4, 5},
{6, 7, 8, 9, 10},
{11, 12, 13, 14, 15},
{16, 17, 18, 19, 20}
};
return myGraph;
}
public static int[][] findNeighbors(int[][] graph, int x, int y){
for (int i = 0; i < graph.length; i++){
for (int j = 0; j < graph[i].length; j++){
}
}
}
public static void main(String[] args) {
System.out.println(findNeighbors(graph(), 2, 2));
}
}
I created a simple 2D array above, and lets say I want to find the neighbors to index (2,2), so in this case given '13', I want to return the values '8', '18', '14, and '12'. I tried to use a nested for loop to get the values +- 1 but I couldn't really figure it out.
You can get the corresponding values by:
-finding what index your given value lays at
-returning it's -1 index and +1 index (warn: can cause nullpointer in some cases)
But remember that your array is only 5x4 in your mind, so the neighbours below and above are not determinable.
It's not clear how you want to represent the neighbors in your 2D array return value, but here is how you access the neighboring cells.
There are fancy ways to write this in much less code, but I purposely wrote it out verbosely to illustrate the steps needed:
public static void findNeighbors(int[][] graph, int x, int y){
int x2;
int y2;
int value;
if (y>=0 && y<graph.length) {
if (x>=0 && x<graph[0].length) {
// North neighbor
y2 = y - 1;
x2 = x;
if (y2 >= 0) {
value = graph[y2][x2];
// ... do something with "value" ...
}
else {
System.out.println("North is out of bounds!");
}
// East neighbor
y2 = y;
x2 = x + 1;
if (x2 < graph[y].length) {
value = graph[y2][x2];
// ... do something with "value" ...
}
else {
System.out.println("East is out of bounds!");
}
// South neighbor
y2 = y + 1;
x2 = x;
if (y2 < graph.length) {
value = graph[y2][x2];
// ... do something with "value" ...
}
else {
System.out.println("South is out of bounds!");
}
// West neighbor
y2 = y;
x2 = x - 1;
if (x2 >= 0) {
value = graph[y2][x2];
// ... do something with "value" ...
}
else {
System.out.println("West is out of bounds!");
}
}
else {
System.out.println("x-coord out of bounds!");
}
}
else {
System.out.println("y-coord out of bounds!");
}
}
public static List<Integer> findNeighbors(int[][] graph, int x, int y) {
List<Integer> neighbors = new ArrayList<>();
// Checking if x and y are inside the 2d Array if not return empty array
if (y < 0 || y > graph().length - 1 || x < 0 || x > graph()[0].length - 1) return neighbors;
// Checking if x - 1 is in bounds
if (x - 1 >= 0) neighbors.add(graph[y][x - 1]);
// Checking if x + 1 is in bounds
if (x + 1 < graph()[0].length - 1) neighbors.add(graph[y][x + 1]);
// Checking if y - 1 is in bounds
if (y - 1 >= 0) neighbors.add(graph[y - 1][x]);
// Checking if y + 1 is in bounds
if (y + 1 < graph().length - 1) neighbors.add(graph[y + 1][x]);
return neighbors;
}
Related
I am working on the following problem:
Write a method that, given a chessboard with one knight, rocks on some of the squares, and a target position, indicates whether or not the knight can reach the target without landing on any rocks, and if so, the smallest number of moves needed by the knight to reach the target. The method should return the minimum number of moves needed to do so; otherwise, the method should return the value -1. (If the initial position has a rock on it, the method should return -1; likewise, if the target position has a rock on it, the method should return -1.)
You can see the code I've implemented so far below. My approach to rocks is to change the "coordinates" on the chessboard that have rocks as visited, so the knight can't revisit them, hence blocking his path(?).
My program compiles but doesn't return either minimum moves or -1. Any tips/different approaches to the problem are much appreciated. Thanks!!
PS: I'm ridiculously new to Java so apologies in advance for the messy code :)
import java.util.*;
public class Knight {
public static int numMoves( int dim, int xstart, int ystart, int xtarget,
int ytarget, int[] xrock, int[] yrock )
{
int result = -1;
List<Integer> knightPos = new ArrayList<>(Arrays.asList(xstart, ystart));
int [] targetPos = {xtarget, ytarget};
int dis = 0;
// x and y direction, where a knight can move
int[] dx = { -2, -1, 1, 2, -2, -1, 1, 2 };
int[] dy = { -1, -2, -2, -1, 1, 2, 2, 1 };
// queue for storing states of knight in board
Vector<cell> q = new Vector<>();
// push starting position of knight with 0 distance
q.add(new cell(knightPos.get(xstart), knightPos.get(ystart), dis));
cell t;
int x, y;
boolean[][] visit = new boolean[dim + 1][dim + 1];
// make all cell unvisited
for (int i = 1; i <= dim; i++) {
for (int j = 1; j <= dim; j++) {
visit[i][j] = false;
}
}
// visit starting state
visit[knightPos.set(0,xstart)][knightPos.set(1,ystart)] = true;
// visit rock squares
for (int i = 0; i < xrock.length;) {
for (int j = 0; j < yrock.length; ++i, ++j) {
visit[knightPos.get(i)][knightPos.get(j)] = true;
}
}
// loop until we have one element in queue
while (!q.isEmpty()) {
t = q.firstElement();
q.remove(0);
// if current cell is equal to target cell,
// return its distance
if (t.x == targetPos[0] && t.y == targetPos[1])
return t.dis;
// loop for all reachable states
for (int i = 0; i < 8; i++) {
x = t.x + dx[i];
y = t.y + dy[i];
// If reachable state is not yet visited and
// inside board, push that state into queue
if (isInside(x, y, dim) && !visit[x][y]) {
visit[x][y] = true;
q.add(new cell(x, y,dis + 1));
}
}
}
return result;
}
public static boolean isInside (int x, int y, int dim)
{
return x >= 0 && x <= dim && y >= 0 && y <= dim;
}
static class cell {
int x, y;
int dis;
public cell(int x, int y, int dis) {
this.x = x;
this.y = y;
this.dis = dis;
}
}
public static void main( String[] args )
{
}
}
I am trying to get all the neighbors of a combination of simple one character strings in a 2d array. Meaning, my output looks like this currently in a 3x5:
A B C
D E F
A S D
F S A
G S A
So the neighbor of (1,0) should be = A B E S A .
Currently I have the following:
public void getNeighborsOfPoint(int x, int y) {
for (int xx = -1; xx <= 1; xx++) {
for (int yy = -1; yy <= 1; yy++) {
if (xx == 0 && yy == 0) {
continue; // You are not neighbor to yourself
}
if (Math.abs(xx) + Math.abs(yy) > 1) {
continue;
}
if (isOnMap(x + xx, y + yy)) {
System.out.println(grid[x+xx][y+yy]);
}
}
}
public boolean isOnMap(int x, int y) {
return x >= 0 && y >= 0 && x < length && y < width;
}
However it is only returning A E A in the example I provided.(it is not returning the ones cross-wise)
What is the right code to make it work? Note that the input will not always be 3 x 5. It may be a lot of different combination of x and y s.
The diagonals aren't included because of this code:
if (Math.abs(xx) + Math.abs(yy) > 1) {
continue;
}
When it's on the diagonal Math.abs(xx) == 1 && Math.abs(yy) == 1. So their sum will be greater than 1. You're skipping over the diagonals by having this code here.
The reason you're not getting the diagonals in your current group is that second if statement. You need to cover, for example, (2, 1) which is when xx is 1 and yy is 1. But abs(1) + abs(1) = 2 and 2 > 1, so you don't include it.
As a refactoring exercise, it might be a little cleaner if you have the inside of that for loop simplified to one conditional.
if (expression) {
continue
};
// other stuff
is equivalent to
if (!expression) {
// other stuff.
}
And for you, expression (in psuedocode) is not(xx=0 and yy=0) and isOnMap(xx, yy)
In a loop, the continue keyword means that you will skip to the next iteration of the loop. In your case, you have :
if (Math.abs(xx) + Math.abs(yy) > 1) {
continue;
}
if (isOnMap(x + xx, y + yy)) {
System.out.println(grid[x+xx][y+yy]);
}
So if the first condition is verified, you will not print any answer, meaning that your program won't consider A(xx, yy) to be a neighbord.
In your ABESA example, B and S are ignored because of this.
If you want to use 2d arrays with variable number of rows and columns you have to pass them as parameters in your's isOnMap method like below:
public static boolean isOnMap(int x, int y, int length, int width) {
return x >= 0 && y >= 0 && x < length && y < width;
}
You can handle the special cases of your 2d array (when one or both rownumber and columnnumber of your element are equal to 0) rewriting your getNeighborsOfPoint method in this way:
public static void getNeighborsOfPoint(int x, int y, char[][] grid) {
final int length = grid.length;
final int width = grid[0].length;
if (isOnMap(x, y, length, width)) {
for (int i = Math.max(0, x - 1); i < Math.min(length, x + 2); ++i) {
for (int j = Math.max(0, y - 1); j < Math.min(width, y + 2); ++j) {
if (i != x || j != y) {
System.out.println(grid[i][j]);
}
}
}
}
}
I have to do a method that will go through the matrix.I give the coordinates from the keyboard of the position [L, C], from where the extension will start.It will pass to the next value only if the next value is smaller than this.On the diagonals do not go!
PS: Sorry for my english
Like in image:
enter image description here
Three steps need to be done here:
// prepare output matrix and fill it with -1
int[][] outMatrix = prepareOut(inputArray.length, inputArray[0].length);
// call recursively method to mark cells starting from the initial coordinates
outMatrix = markCell(inputArray, outMatrix, line, column, 1);
// print output matrix
printOutput(outMatrix);
The most relevant method implementation may be like this:
static int[][] markCell(int[][] arr, int[][] out, int y, int x, int move) {
int val = arr[y][x];
if (out[y][x] == 0) {
return out;
} else if (out[y][x] < 0) {
out[y][x] = move;
}
// checking a cell above the current one (north)
if (y > 0 && out[y - 1][x] < 0) {
if (cellMarked(arr, out, y - 1, x, val, move)) {
out = markCell(arr, out, y -1, x, move + 1);
}
}
// checking a cell under the current one (south)
if (y < arr.length - 1 && out[y + 1][x] < 0) {
if (cellMarked(arr, out, y + 1, x, val, move)) {
out = markCell(arr, out, y +1, x, move + 1);
}
}
// checking a cell to the left of the current one (west)
if (x > 0 && out[y][x - 1] < 0) {
if (cellMarked(arr, out, y, x - 1, val, move)) {
out = markCell(arr, out, y, x - 1, move + 1);
}
}
// checking a cell to the right of the current one (east)
if (x < arr[0].length - 1 && out[y][x + 1] < 0) {
if (cellMarked(arr, out, y, x +1, val, move)) {
out = markCell(arr, out, y, x + 1, move + 1);
}
}
return out;
}
static boolean cellMarked(int[][] arr, int[][] out, int y, int x, int val, int move) {
final boolean marked = arr[y][x] <= val;
out[y][x] = marked ? move : 0;
return marked;
}
When printing the output matrix, you replace remaining -1 with 0:
static void printOutput(int[][] arr) {
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
char c = arr[i][j] <= 0 ? '0' : '*';
System.out.print(c);
System.out.print('\t');
}
System.out.print('\n');
}
}
prepareOut may be implemented like this:
private static int[][] prepareOut(int rows, int cols) {
int [][] out = new int[rows][cols];
for(int[] row: out) {
Arrays.fill(row, -1);
}
return out;
}
I am new to this website so correct me if there is anything wrong with my question. I keep receiving this error and I am not entirely sure what is wrong with my program:
Exception in thread "main" java.lang.IllegalArgumentException: Parameter N must be positive
at StdRandom.uniform(StdRandom.java:119)
at Maze.chooseRandomlyFrom(Maze.java:52)
at Maze.expandMaze(Maze.java:136)
at Maze.main(Maze.java:193)**
I ran the JUnit test in my IDE (eclipse) however I could not trace where the error is coming from. Any help or guidance is greatly appreciated and thank you for taking the time to check out the code. Here is what I am working with. I included comments for each method as clearly as I could.
public class Maze {
public static final int EAST = 1;
public static final int NORTH = 0;
public static final int[][] OFFSETS = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
public static final int SOUTH = 2;
public static final int WEST = 3;
//Purpose: Modifies passage to contain a one-way passage from location a to location
//b. Assumes these two locations (arrays of two numbers) are adjacent.
//Parameters: boolean[][][] passages, int[] a, int[] b
//Return: N/A
public static void addPassage(boolean[][][] passages, int[] a, int[] b)
{
int ax = a[0];
int ay = a[1];
int bx = b[0];
int by = b[1];
if (by == ay + 1) {
passages[ax][ay][0] = true;
} else if (bx == ax + 1) {
passages[ax][ay][1] = true;
} else if (by == ay - 1) {
passages[ax][ay][2] = true;
} else {
passages[ax][ay][3] = true;
}
}
//Purpose: Gets array of pairs containing start and all locations in the list.
//Parameters: int[] start, int[][] list
//Return: Returns a new array of pairs containing start followed by all of the locations in list.
public static int[][] addToFront(int[] start, int[][] list)
{
int[][] path = new int[list.length + 1][];
path[0] = start;
for (int i = 1; i < path.length; i++) {
path[i] = list[(i - 1)];
}
return path;
}
//Purpose: Gets random one from the first element of the list
//Parameters: int[][] list, int n
//Return: Returns a random one of the first n elements of list.
public static int[] chooseRandomlyFrom(int[][] list, int n)
{
return list[StdRandom.uniform(n)];
}
//Purpose: Gets pair and compares to first number as one of the first n element
//Parameters: int[] pair, int[][] list, int n
//Return: Returns true if pair, assumed to be an array of two numbers, has the same
//numbers as one of the first n elements of list.
public static boolean contains(int[] pair, int[][] list, int n)
{
for (int i = 0; i < n; i++) {
if ((pair[0] == list[i][0]) && (pair[1] == list[i][1])) {
return true;
}
}
return false;
}
//Purpose: Will draw the maze
//Parameters: boolean[][][] passages
//Return: N/A
public static void drawMaze(boolean[][][] passages)
{
StdDraw.clear(StdDraw.PINK);
StdDraw.setPenColor(StdDraw.WHITE);
int width = passages.length;
StdDraw.setPenRadius(0.75 / width);
// Draw passages
for (int x = 0; x < width; x++) {
for (int y = 0; y < width; y++) {
if (passages[x][y][NORTH] || (y + 1 < width && passages[x][y + 1][SOUTH])) {
StdDraw.line(x, y, x, y + 1);
}
if (passages[x][y][EAST] || (x + 1 < width && passages[x + 1][y][WEST])) {
StdDraw.line(x, y, x + 1, y);
}
}
}
// Draw entrance and exit
StdDraw.line(0, 0, -1, 0);
StdDraw.line(width - 1, width - 1, width, width - 1);
StdDraw.show(0);
}
//Purpose: Will draw the maze solution
//Parameters: int[][] path, int width
//Return: N/A
public static void drawSolution(int[][] path, int width)
{
StdDraw.setPenColor(); // Black by default
StdDraw.setPenRadius();
StdDraw.line(0, 0, -1, 0);
StdDraw.line(width - 1, width - 1, width, width - 1);
for (int i = 0; i < path.length - 1; i++) {
StdDraw.line(path[i][0], path[i][1], path[i + 1][0], path[i + 1][1]);
}
StdDraw.show(0);
}
//Purpose: Checks if here's neighbor in direction (called there) is in unexplored. If so, adds a passage from here
//to there and returns there. If not,returns null.
//Parameters: boolean[][][] passages, int[][] unexplored, int n, int[] here, int direction otherwise.
public static int[] expandLocation(boolean[][][] passages, int[][] unexplored, int n, int[] here, int direction)
{
int[] there = new int[2];
here[0] += OFFSETS[direction][0];
here[1] += OFFSETS[direction][1];
if (contains(there, unexplored, n))
{
addPassage(passages, here, there);
return there;
}
return null;
}
//Purpose: Chooses "here" to be either lastExploredLocation (if it is not null) or a random location in
//frontier. If possible, adds a passage from "here" to a location "there" in unexplored, then moves "there" from unexplored to
//frontier. If not, moves "here" from frontier to done.
//Parameters: boolean[][][] passages, int[][] done, int[][] frontier, int[][] unexplored, int[] counts, int[] lastExploredLocation
//Return: N/A
public static int[] expandMaze(boolean[][][] passages, int[][] done, int[][] frontier, int[][] unexplored, int[] counts, int[] lastExploredLocation)
{
int[] here;
if (lastExploredLocation == null) {
here = chooseRandomlyFrom(frontier, counts[1]);
} else {
here = lastExploredLocation;
}
int direction = StdRandom.uniform(4);
for (int i = 0; i < 4; i++)
{
int[] there = expandLocation(passages, unexplored, counts[2], here, direction);
if (there != null)
{
frontier[counts[1]] = there;
counts[1] += 1;
remove(there, unexplored, counts[2]);
counts[2] -= 1;
return there;
}
direction = (direction + 1) % 4;
}
done[counts[0]] = here;
counts[0] += 1;
remove(here, frontier, counts[1]);
counts[1] -= 1;
return null;
}
//Purpose: Draws then solves maze
//Parameters: String[] args
//Return: N/A
public static void main(String[] args)
{
int width = 20;
StdDraw.setXscale(-0.5, width - 0.5);
StdDraw.setYscale(-0.5, width - 0.5);
StdDraw.show(0);
boolean[][][] passages = new boolean[width][width][4];
// Initially, no locations are done
int[][] done = new int[width * width][];
// The frontier only contains {0, 0}
int[][] frontier = new int[width * width][];
frontier[0] = new int[] { 0, 0 };
// All other locations are in unexplored
int[][] unexplored = new int[width * width][];
// Number of nodes done, on the frontier, and unexplored
int[] counts = { 0, 1, width * width - 1 };
int i = 0;
for (int x = 0; x < width; x++) {
for (int y = 0; y < width; y++) {
if (x != 0 || y != 0) {
unexplored[i] = new int[] { x, y };
i++;
}
}
}
// As long as there are unexplored locations, expand the maze
int[] lastExploredLocation = null;
while (counts[2] > 0) {
lastExploredLocation = expandMaze(passages, done, frontier, unexplored, counts, lastExploredLocation);
drawMaze(passages);
StdDraw.show(25);
}
// Solve the maze
int[][] solution = solve(passages, new int[] { 0, 0 }, new int[] { width - 1, width - 1 });
drawSolution(solution, width);
}
//Purpose: Modifies list so that pair is replaced with the (n - 1)th element of list. Assumes pair is an
//array of two numbers that appears somewhere in list. Thus, when this method is done, the first n - 1 element of list are
//the same as the first n elements of the old version, but with pair removed and with the order of elements potentially different.
//Parameters: int[] pair, int[][] list, int n
//Return: N/A
public static void remove(int[] pair, int[][] list, int n)
{
for (int i = 0; i < n; i++) {
if ((pair[0] == list[i][0]) && (pair[1] == list[i][1]))
{
list[i] = list[(n - 1)];
return;
}
}
}
//Purpose: Gets a return path from start to finish
//Parameters: boolean[][][] passages, int[] start, int[] goal
//Return: Returns a path (sequence of locations) leading from start to goal in passages or null if there is no such path.
public static int[][] solve(boolean[][][] passages, int[] start, int[] goal) {
if ((start[0] == goal[0]) && (start[1] == goal[1])) {
return new int[][] { goal };
}
for (int d = 0; d < 4; d++) {
if (passages[start[0]][start[1]][d] != false)
{
int[] next = { start[0] + OFFSETS[d][0], start[1] + OFFSETS[d][1] };
int[][] restOfPath = solve(passages, next, goal);
if (restOfPath != null) {
return addToFront(start, restOfPath);
}
}
}
return null;
}
}
When you pass the argument 'n' to
StdRandom.uniform() at Maze.chooseRandomlyFrom(Maze.java:52) the argument you are passing is negative. According to the error message, the parameter must be positive. This could be because during expandMaze, you are assigning counts[1] to be one less than its current value (counts[1] -= 1;), which will eventually result in a negative number. It would appear that the method is called over and over as long as counts[2] > 0, which in some cases must be the case for enough iterations such as counts[1] becomes a negative number.
Perhaps before calling this StdRandom.uniform() method, you should take the absolute value of counts[1] to ensure it is always positive. Math.abs(counts[1]) should do the trick.
I've been working on this problem for two days, and the best I can do is a brute force solution which is not efficient enough.
You are given a bunch of positive coordinate points ranging from (0, 0) to (1 billion, 1 billion). You must enclose all of the points with only two rectangles with the smallest possible total area. Rectangles must have sides parallel to the x-axis and y-axis. The rectangles cannot overlap, sharing the same boundary counts as overlapping. You **can** have a 0 by 0 rectangle of area zero. The sum of the areas of the two rectangles is **X**
You also have to find a single rectangle of the smallest possible area that encloses all of the points. This area is **Y**
You are trying to find **Y** - **X**.
For the following example, the answer **Y** - **X** = 107.
(4, 2), (8, 10), (1, 1), (9, 12), (14, 7), (2, 3)
Providing code would be very appreciated, if you do then please use Java or C++ if possible.
I do not want to spoil the game.
Start with the large rectangle. Then you can split on every x or y of a point.
Sort the points once by x, once by y.
Split vertically:
#######
#######
#######
#######
Split horizonally:
##
## ####
####
####
Splitting at a coordinate yields two sets of point where both rectangle halves are easily reduced.
Added a solution because of comment
As Point class I actually use int[2] so the x/y choice can be made as for-index. On the other hand, I had to make a class AreaCollector, where a simple Rectangle would suffice.
The rectangle points I have collected too; without them the code would become a bit smaller.
static private class AreaCollector {
private final int[] lwb = new int[] { Integer.MAX_VALUE, Integer.MAX_VALUE };
private final int[] upb = new int[] { Integer.MIN_VALUE, Integer.MIN_VALUE };
public void add(int[] point) {
if (point[0] < lwb[0]) {
lwb[0] = point[0];
}
if (point[1] < lwb[1]) {
lwb[1] = point[1];
}
if (point[0] > upb[0]) {
upb[0] = point[0];
}
if (point[1] > upb[1]) {
upb[1] = point[1];
}
}
public int getArea() {
if (upb[0] == Integer.MIN_VALUE) { /// Zero points added.
return 0;
}
return (upb[0] - lwb[0]) * (upb[1] - lwb[1]);
}
}
public int solve(int[][] points) {
AreaCollector ac = new AreaCollector();
for (int[] point : points) {
ac.add(point);
}
final int y = ac.getArea();
final int n = points.length;
// Best solution sofar:
int[][] ascPoints = Arrays.copyOf(points, n);
int[][] descPoints = new int[0][];
int bestX = y + 0;
for (int direction = 0; direction < 2; ++direction) {
final int dir = direction;
Arrays.sort(points, Comparator.comparingInt((pt) -> pt[dir]));
int[] ascAreas = new int[n];
AreaCollector ascAC = new AreaCollector();
for (int i = 0; i < n; ) {
int[] point = points[i];
int coord = point[direction];
for (int j = i; j < n && points[j][direction] == coord; ++j) {
ascAC.add(points[j]);
}
int area = ascAC.getArea();
for (int j = i; j < n && points[j][direction] == coord; ++j) {
ascAreas[j] = area;
++i;
}
}
int[] descAreas = new int[n];
AreaCollector descAC = new AreaCollector();
for (int i = n - 1; i >= 0; ) {
int[] point = points[i];
int coord = point[direction];
for (int j = i; j >= 0 && points[j][direction] == coord; --j) {
descAC.add(points[j]);
}
int area = descAC.getArea();
for (int j = i; j >= 0 && points[j][direction] == coord; --j) {
descAreas[j] = area;
--i;
}
}
int bestI = -1;
for (int i = 0; i < n- 1; ++i) {
if (points[i][direction] != points[i + 1][direction]) {
int x = ascAreas[i] + descAreas[i + 1];
if (x < bestX) {
bestX = x;
bestI = i;
}
}
}
if (bestI != -1) {
ascPoints = Arrays.copyOfRange(points, 0, bestI + 1);
descPoints = Arrays.copyOfRange(points, bestI + 1, n);
}
}
return y -bestX;
}
As Comparator I used java 8 terse notation. As you see the complexity of the hand-coded part is O(N) superseeded by Arrays.sort O(N.log N).
Here's a solution in Java. After calculating area Y, it first sorts the coordinates by X coordinates and then calculates the area of the rectangles by splitting the array into two halves at each X coordinate (with a special handling if two coordinates have the same X value). Then it does the same for the Y coordinates. The minimum rectangle area is the resulting X area.
import java.util.Arrays;
import java.util.Comparator;
public class Puzzle {
public static void main(String[] args) {
int[][] COORDINATES_1 = { { 4, 2 }, { 8, 10 }, { 1, 1 }, { 9, 12 }, { 14, 7 }, { 2, 3 } };
int[][] COORDINATES_2 = { { 2, 1 }, { 2, 2 }, { 3, 1 }, { 3, 3 }, { 4, 3 }, { 5, 3 }, { 5, 4 }, { 6, 4 } };
int[][] COORDINATES_3 = { { 4, 2 } };
solve(COORDINATES_1);
solve(COORDINATES_2);
solve(COORDINATES_3);
}
public static void solve(int[][] coordinates) {
int size = coordinates.length;
int y = calcMinRectArea(coordinates, 0, size);
// sort by x coordinates
Arrays.sort(coordinates, new Comparator<int[]>() {
#Override
public int compare(int[] o1, int[] o2) {
return o1[0] - o2[0];
}
});
int x = y;
for (int i = 1; i < size; i++) {
if (coordinates[i][0] == coordinates[i - 1][0])
continue; // several coordinates with the same x coordinates
x = Math.min(calcMinRectArea(coordinates, 0, i) + calcMinRectArea(coordinates, i, size - i), x);
}
// sort by y coordinates
Arrays.sort(coordinates, new Comparator<int[]>() {
#Override
public int compare(int[] o1, int[] o2) {
return o1[1] - o2[1];
}
});
for (int i = 1; i < size; i++) {
if (coordinates[i][1] == coordinates[i - 1][1])
continue; // several coordinates with the same y coordinates
x = Math.min(calcMinRectArea(coordinates, 0, i) + calcMinRectArea(coordinates, i, size - i), x);
}
System.out.printf("Y = %d, X = %d, Y - X = %d\n", y, x, y - x);
}
private static int calcMinRectArea(int[][] coords, int start, int length) {
if (length == 0)
return 0;
int minX = coords[start][0];
int maxX = minX;
int minY = coords[start][1];
int maxY = minY;
for (int i = start + 1; i < start + length; i++) {
int x = coords[i][0];
minX = Math.min(minX, x);
maxX = Math.max(maxX, x);
int y = coords[i][1];
minY = Math.min(minY, y);
maxY = Math.max(maxY, y);
}
return (maxX - minX) * (maxY - minY);
}
}