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);
}
}
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 implementing longest increasing path problem of leetcode.
Given an integer matrix, find the length of the longest increasing path.
From each cell, you can either move to four directions: left, right, up or down. You may NOT move diagonally or move outside of the boundary (i.e. wrap-around is not allowed).
Example 1:
Input: nums =
[
[9,9,4],
[6,6,8],
[2,1,1]
]
Output: 4
Explanation: The longest increasing path is [1, 2, 6, 9].
So Below is my implementation tries a lot on recursion, but not able to understand why it is not giving correct result why maxDist decreases from 4 to 3 to 2 in this example, as this variable is is global not local.
public class LongestIncreasingPath {
private static final int[][] dirs = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
private int m, n;
int maxDist;
public int longestIncreasingPath(int[][] matrix) {
if (matrix.length == 0)
return 0;
m = matrix.length;
n = matrix[0].length;
int ans = 1;
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j) {
dfs(matrix, i, j, 1);
ans = Math.max(ans, maxDist);
}
return ans;
}
private int dfs(int[][] matrix, int i, int j, int dist) {
for (int[] d : dirs) {
int x = i + d[0], y = j + d[1];
if (0 <= x && x < m && 0 <= y && y < n && matrix[x][y] > matrix[i][j]) {
maxDist = Math.max(maxDist, dfs(matrix, x, y, dist+1));
}
}
return dist;
}
public static void main(String[] args) {
int[][] nums = { { 9, 9, 4 }, { 6, 6, 8 }, { 2, 1, 1 } };
LongestIncreasingPath lIP = new LongestIncreasingPath();
System.out.println(lIP.longestIncreasingPath(nums));
}
}
The following is a working version, tested on 2 test cases (only). Please note the comments about bugs and some changes in structure:
public class LongestIncreasingPath {
private static final int[][] dirs = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
private int rows, cols;
//avoid non-volatile class variable that may be updated by more than one thread
//use local variables instead
//private int maxDist;
public int longestIncreasingPath(int[][] matrix) {
if (matrix.length == 0) return 0;
rows = matrix.length;
cols = matrix[0].length;
int maxDist = 0; //retain max found
for (int row = 0; row < rows; ++row) {
for (int col = 0; col < cols; ++col) {
//bug fix: use distance (matrix[row][col]) instead of 1
int distance = dfs(matrix, row, col, matrix[row][col]);
maxDist = Math.max(distance, maxDist);
}
}
return maxDist;
}
private int dfs(int[][] matrix, int row, int newCol, int dist) {
int maxDist = dist;
for (int[]dir : dirs) {
int newRow = row + dir[0], y = newCol + dir[1];
if (0 <= newRow && newRow < rows && 0 <= y && y < cols &&
matrix[newRow][y] > matrix[row][newCol]) {
//bug fix: //add new distance matrix[x][y] instead of 1
maxDist = Math.max(maxDist, dfs(matrix, newRow, y, dist + matrix[newRow][y]));
}
}
return maxDist;
}
public static void main(String[] args) {
LongestIncreasingPath lIP = new LongestIncreasingPath();
int[][] nums = { { 9, 9, 4 },
{ 6, 6, 8 },
{ 2, 2, 1 }
};
//printout test case 1
System.out.println(lIP.longestIncreasingPath(nums));
nums = new int[][]{ { 5, 6, 7 },
{ 4, 9, 8 },
{ 3, 2, 1 }
};
//printout test case 2
System.out.println(lIP.longestIncreasingPath(nums));
}
}
Here I want to use DFS to traverse in a 2D array from leftmost column to rightmost column, each element can go to its upper right element or right element or lower right element. I need to record each possible path. For example, here I have:
1 2 3
4 5 6
7 8 9
Then the possible paths will be 123, 126, 153, 156, 159, 423, 426, 453, 456, 459, 486, 489, 753, 756, 759, 786, 789
Now my idea is straightforward backtrack:
public int findSolution(int[][] array) {
List<List<Integer>> availablePaths = new ArrayList<List<Integer>>();
for (int i = 0; i < array.length; i++) {
List<Integer> tempList = new ArrayList<Integer>();
dfs(array, availablePaths, tempList, 0, i);
}
int res = 0;
int min = Integer.MAX_VALUE;
for (List<Integer> path : availablePaths) {
min = Integer.MAX_VALUE;
for (Integer cur : path) {
if (cur < min) {
min = cur;
}
}
if (min > res) {
res = min;
}
}
return res;
}
public void dfs(int[][] array, List<List<Integer>> availablePaths, List<Integer> tempList, int curCol, int curRow) {
if (tempList.size() == array[0].length) {
availablePaths.add(new ArrayList<Integer>(tempList));
return;
}
tempList.add(array[curRow][curCol]);
int startRow;
int endRow;
// Next Column
if (curRow == 0) {
startRow = 0;
endRow = curRow+1;
} else if (curRow == array.length-1) {
startRow = curRow - 1;
endRow = curRow;
} else {
startRow = curRow - 1;
endRow = curRow + 1;
}
for (int i = startRow; i <= endRow; i++) {
dfs(array, availablePaths, tempList, curCol + 1, i);
tempList.remove(tempList.size()-1);
}
}
However, this can not work because of ArrayIndexOutOfBoundsException, so I guess my code has wrong idea.
Could someone give a solution to solve this problem?
The following DFS implementation solves your problem. I added your example as a test case as well.Basically, we start a new dfs on each cell on the first column. In each dfs call, as long as the current cell is in bound, we add it to the current path in a list. If the current cell is already the last column, add the path stored in the list to the final result.
The dx, dy arrays are a concise way of implementing the 3 possible moves.
import java.util.ArrayList;
import java.util.List;
public class Solution {
private static int[] dx = {-1,0,1}, dy = {1,1,1};
public static List<List<Integer>> dfsForAllPaths(int[][] grid) {
List<List<Integer>> res = new ArrayList<>();
if(grid == null) {
return res;
}
for(int i = 0; i < grid[0].length; i++) {
dfsHelper(grid, i, 0, res, new ArrayList<>());
}
return res;
}
private static void dfsHelper(int[][] grid, int x, int y, List<List<Integer>> res, List<Integer> list) {
if(!isInBound(grid, x, y)) {
return;
}
list.add(grid[x][y]);
if(y == grid[0].length - 1) {
res.add(new ArrayList<>(list));
}
for(int dir = 0; dir < 3; dir++) {
int newX = x + dx[dir], newY = y + dy[dir];
dfsHelper(grid, newX, newY, res, list);
}
list.remove(list.size() - 1);
}
private static boolean isInBound(int[][] grid, int x, int y) {
return x >= 0 && x < grid.length && y >= 0 && y < grid[0].length;
}
public static void main(String[] args) {
int[][] grid = {{1,2,3},{4,5,6},{7,8,9}};
List<List<Integer>> res = dfsForAllPaths(grid);
for(int i = 0; i < res.size(); i++) {
System.out.println(res.get(i));
}
}
}
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 am trying to implement a convolution method taking two vectors: an image; and a kernel. My problem is that i don't know how to calculate the index of the image neighbour element when I "slide" the kernel over the image vector. For example, with two identical vectors {0, 1, 2, 3, 4, 5, 6, 7, 8} I would like to achieve the following result:
My code so far is as follows:
public int[] convolve(int[] image, int[] kernel)
{
int imageValue;
int kernelValue;
int outputValue;
int[] outputImage = new int[image.length()];
// loop through image
for(int i = 0; i < image.length(); i++)
{
outputValue = 0;
// loop through kernel
for(int j = 0; j < kernel.length(); j++)
{
neighbour = ?;
// discard out of bound neighbours
if (neighbour >= 0 && neighbour < imageSize)
{
imageValue = image[neighbour];
kernelValue = kernel[j];
outputValue += imageValue * kernelValue;
}
}
output[i] = outputValue;
}
return output;
}
As i + j - (kernel.length / 2) may be too short for an answer:
public class Convolution
{
public static void main(String[] args)
{
int image[] = { 0,1,2,3,4,5,6,7,8 };
int kernel[] = { 0,1,2,3,4,5,6,7,8 };
int output[] = convolve(image, kernel);
for (int i=0; i<image.length; i++)
{
System.out.printf(output[i]+" ");
}
}
public static int[] convolve(int[] image, int[] kernel)
{
int[] output = new int[image.length];
// loop through image
for(int i = 0; i < image.length; i++)
{
System.out.println("Compute output["+i+"]");
int outputValue = 0;
// loop through kernel
for(int j = 0; j < kernel.length; j++)
{
int neighbour = i + j - (kernel.length / 2);
// discard out of bound neighbours
if (neighbour >= 0 && neighbour < image.length)
{
int imageValue = image[neighbour];
int kernelValue = kernel[j];
outputValue += imageValue * kernelValue;
System.out.println("image["+neighbour+"] and kernel["+j+"]");
}
}
output[i] = outputValue;
}
return output;
}
}
Note that this only works properly when the kernel has an odd length. In fact, what you are doing there is to move the center of the kernel through the image space (this is where the kernel.length/2 comes from). For even length kernels, like 0 1 2 3, you would have to decide whether you wanted to include...
0 1 2 3 4 (image)
3 <- This line and/or ...
2 3
1 2 3
0 1 2 3
0 1 2 3
0 1 2
0 1
0 <- ... this line
Sounds to me like you want something like a slider:
static class Slider implements Iterable<List<Integer>> {
final List<Integer> kernel;
final int imageWidth;
final int center;
public Slider(int imageWidth, int kernelWidth) {
// Build my kernel offsets list.
this.kernel = new ArrayList<>(kernelWidth);
for (int i = 0; i < kernelWidth; i++) {
kernel.add(i, i);
}
// Which kernel cell is in the center.
center = kernelWidth / 2;
// Remember the image width.
this.imageWidth = imageWidth;
}
#Override
public Iterator<List<Integer>> iterator() {
return new Iterator<List<Integer>>() {
int x = 0;
#Override
public boolean hasNext() {
return x < imageWidth;
}
#Override
public List<Integer> next() {
List<Integer> slice = kernel.subList(Math.max(0, center - x), Math.min(kernel.size(), center - x + kernel.size()));
x += 1;
return slice;
}
};
}
}
public void test() {
List<Integer> image = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> kernel = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8);
// Keep track of image position.
int x = 0;
for (List<Integer> slice : new Slider(image.size(), kernel.size())) {
System.out.println(slice);
int outputValue = 0;
int imageValue = image.get(x++);
for (Integer o : slice) {
int kernelValue = kernel.get(o);
outputValue += imageValue * kernelValue;
}
System.out.println("outputValue=" + outputValue);
}
}