I'm having trouble with an algorithm, suppose the following:
A cinema has n rows, each row consists of m seats (n and m do not exceed 20). A two-dimensional matrix stores the information on the sold tickets, number 1 means that the ticket for this place is already sold, the number 0 means that the place is available. You want to buy k tickets to the neighboring seats in the same row. Find whether it can be done.
Input data
On the input, the program gets the number of n rows and m seats. Then, there are n lines, each containing m numbers (0 or 1) separated by spaces. The last line contains a number k.
Output data
The program should output the number of the row with k consecutive available seats. If there are several rows with k available seats, output the first row with these seats. If there is no such a row, output the number 0.
Code
import java.util.Scanner;
class Main {
static int findRowWithAvailableSeat(int[][] matrix, int tickets) {
final int rows = matrix.length;
final int columns = matrix[0].length;
int seatCounter = 0;
for (int r = 1; r <= rows; r++) {
for (int c = 1; c <= columns; c++) {
if (matrix[r][c] == 1) {
continue;
} if (matrix[r][c] == matrix[r][c + 1]) {
seatCounter++;
if (seatCounter == tickets) {
return r;
}
}
}
}
return 0;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int rows = scanner.nextInt();
int columns = scanner.nextInt();
int[][] matrix = new int[rows][columns];
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
matrix[r][c] = scanner.nextInt();
}
}
int kTickets = scanner.nextInt();
int rowWithAvailableSeats = findRowWithAvailableSeat(matrix, kTickets);
System.out.println(rowWithAvailableSeats);
}
}
I know the problem is somewhere in findRowWithAvailableSeat method. I would like a hint on how to solve the problem, not the actual solution. Thank you very much.
EDIT
I could finally solve it (or at least it works as intended, I'm not sure if it's the best implementation). Thanks you all for your tips.
static int findRowWithAvailableSeat(int[][] matrix, int tickets) {
final int rows = matrix.length;
final int columns = matrix[0].length;
int seatCounter;
for (int r = 0; r < rows; r++) {
seatCounter = 0;
for (int c = 0; c < columns; c++) {
if (matrix[r][c] == 1) {
seatCounter = 0;
continue;
}
if (matrix[r][c] == 0) {
seatCounter++;
if (seatCounter == tickets) {
return r + 1;
}
}
}
}
return 0;
}
Here are the 4 tips you need:
Don't compare matrix[r][c] == matrix[r][c + 1]. Plainly compare to 0:
matrix[r][c] == 0. To avoid ArrayIndexOutOfBoundsException
As DarkSigma already pointed, start your loops iterator from 0, not 1: for (int r = 0; r < rows...
Re-init your seatCounter to 0 for each row.
And! When you print out System.out.println(rowWithAvailableSeats), remember that row counting starts from 0.
Hope this helps
on main() method, you set matrix from index 0 to rows-1, and from index 0 to columns-1. But on findRowWithAvailableSeat(), you start from index 1. So index 0 will never be accessed.
} if (matrix[r][c] == matrix[r][c + 1]) { this line will try to access index c+1, will result index out of bound exception. either you need to check whether or not c+1 is less than column size or compare matrix[r][c] with 0 (matrix[r][c] == 0).
if you looking for neighboring seats, then you need to reset the seatCounter when you visit the sold seat (matrix[r][c] == 1)
you also need to reset seatCounter for each row.
I would put each row in a string and all rows in a string array a[m], then do a[i].contains(k) on each row:
"1001101110100010110010".contains("000")
Your for loops start at 1 instead of 0
for (int r = 1; r <= rows; r++) {
for (int c = 1; c <= columns; c++) {
if (matrix[r][c] == 1) {
The first index of the matrix array is being skipped. So you're not checking the first row and the first seat of each row.
Also, seatCounter is not being reset for each row. It currently retains any seats counted from previous rows.
I'm also not sure what this is for
if (matrix[r][c] == matrix[r][c + 1])
Related
I'm trying to print an element of a 2D array by designating it's location with an index. Say, I want to print location 3 which would be String[1][0] for my array.
String[][] fruit = new String[2][2];
fruit[0][0] = "apple"; //position 1
fruit[0][1] = "banana"; //position 2
fruit[1][0] = "pear"; //position 3
fruit[1][1] = "melon"; //position 4
I would like to call fruit[1][0] position 3 so when I ask to print "position 3" it gives me "pear".
What you're looking for is obviously the literal position of a cell since arrays start from an index value of 0. You also need to keep in mind that a 2D Array can possibly have different number of columns for any given row. The first and second rows for example may have 4 columns, the fifth row might have 6 columns, and the sixth, seventh row may have 4 columns again. Unless you know for sure that all columns within the Array are indeed fixed to a specific length (a "square" 2D Array), I can't see an advantage to this scheme.
Never the less, this can be easily done with two for loops (one nested within the other), for example:
String[][] array = {
{"cell 1", "cell 2"}, // Row 1 (index 0)
{"cell 3", "cell 4", "cell 5"}, // Row 2 (index 1)
{"cell 6", "cell 7"}}; // Row 3 (index 2)
int yourDesiredCell = 5;
int cellCount = 0;
boolean found = false;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
cellCount++;
if (cellCount == yourDesiredCell) {
System.out.println(array[i][j]);
found = true;
break;
//return array[i][j];
}
}
if (found) {
break;
}
}
You could also place this into a class method, for example:
public static String getCellData(String[][] array, int yourDesiredCell) {
int cellCount = 0;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
cellCount++;
if (cellCount == yourDesiredCell) {
return array[i][j];
}
}
}
return null;
}
Another method that could be handy is retrieving the total number of actual cells contained within the 2D Array (if you don't already know):
public static int getTotalCellCount(String[][] array) {
int cellCount = 0;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
cellCount++;
}
}
return cellCount;
}
What I got from your question was that there is a multi-dimensional array A of size say nxm where n is number of rows and'mis number of columns. You want to get let say 1st element which will beA[0][0], but you don't know how to convert 1` into indices for the array.
Lets do this for a 2d array A of size nxm, then you can extend it to 3d etc too. Remember that each A[i] is an array of'melements, hence the position of row where the element isx/m, i=x/m. No need to make it 0-indexed because the integer division of java does that for you. If i>=n`, then we should say element is not present.
Now you have to decide the position of the element in m elements. Hence j or position of the column is x%m. This will give you index b/w 0 and m-1 which is correct range of j, but for an element in the first place it should give 0, but it's giving 1. Hence it js not 0-indexed. So j= x%m -1 but for (m-1)th element its giving
-1 as x would be divisible by m or x%m=0. So use ternary operator here, j = x%m-1 < 0 ? m-1 : x%m-1.
i = x/m ;
if(i<n){
j = x%m -1 < 0 ? m-1 : x%m -1 ;
}else{
System.out.println("Element " +m+" does not exist") ;
}
I would like to suggest another approach with a time complexity O(n).
public String getByPosition(int pos,String[][] mulArr){
int row,col;
int temp = pos;
while(temp % mulArr.length != 0)temp++;
row = (temp / mulArr.length) - 1;
col = ((pos % mulArr[0].length) - 1 < 0) ? mulArr[0].length - 1 : (pos % mulArr[0].length) - 1;
return mulArr[row][col];
}
This method is simple, there is 2D array, not a rectangle, the purpose is to check the values in each column whether they are increasing or not, if they are in an increasing order, return true, else return false.
The shape of the array is like the following, it is a Young Tableaux
{
[1,4,5,10,11],
[2,6,8],
[3,9,12],
[7]
}
The main properties of a young tableaux:
it consists of cells which are filled with integers, and arranged in
left-justified rows,
no row is longer than a preceding row,
from left to right in any row, and down any column the integers are increasing,
the set of integers used is {1, 2, . . . , n} where n is the number
of cells
How I solve it?
My approach is simple, first convert this 2D array into a rectangle matrix, if some position is empty, then filled it with 0.
Then check the column one by one, if found a error, then break, and return the result.
It works, I just wonder if there is a better apporach for this.
public static boolean columnValuesIncrease(int[][] t) {
//How many columns are there?
int columnCounts = t[0].length;
int rowCounts = t.length;
//create a rectangle matrix, fill 0 when outIndex
int[][] addZero = new int[rowCounts][columnCounts];
for (int row = 0; row < rowCounts; row++) {
for (int col = 0; col < t[0].length; col++) {
try {
addZero[row][col] = t[row][col];
} catch (IndexOutOfBoundsException e) {
addZero[row][col] = 0;
}
}
}
//Let's check the damn column!
boolean mark = true;
myLoop:
for (int col = 0; col < columnCounts; col++) {
for (int row = 0; row < rowCounts; row++) {
if (row + 1 < rowCounts && col + 1 < columnCounts) {
if (addZero[row + 1][col] != 0) {
mark = addZero[row][col] <
addZero[row + 1][col] ? true : false;
}
}
if (!mark) {
break myLoop;
}
}
}
return mark;
}
This approach takes a row. It considers 'this' row and the one after it. It considers N number of columns, where N is the minimum of the number of columns in this row and the row after. In math, if R is the number of rows in this 2D matrix, take some r1: r1 ∈ [0, R) and r2 = r1 + 1. Then, N = min{num_cols(r1), num_cols(r2)}.
In column n, where n ∈ [0, N], if the value at the column in the next row happens to be smaller than the value in the preceding row, it returns false. If everything else worked, it returns true.
public static boolean columnValuesIncrease(int[][] t) {
for(int i = 0 ; i < t.length - 1 ; i++)
for(int j = 0 ; j < Math.min(t[i].length, t[i+1].length) ; j++)
if(t[i][j] > t[i+1][j])
return false;
return true;
}
I have a string of characters for which I want to encrypt by loading into a 2D array by rows and then printing the array by column. Such that:
|A|B|
|C|D|
|E|
encrypts to "ACEBD".
However I cant seem to be able to avoid dropping characters in the last row in my output getting "ACBD". Any idea how to solve this?
public static void main(String[] args) throws FileNotFoundException {
if (handleArguments(args))
System.out.println("encrypt");
// get input
Scanner input = new Scanner(inputFile);
String line = input.nextLine();
// calculate height of the array
int height = line.length() / width;
// Add one to height if there's a partial last row
if (line.length() % width != 0)
height += 1;
loadUnloadGrid(line, width, height);
}
static void loadUnloadGrid(String line, int width, int height) {
// make an empty array
char grid[][] = new char[height][width];
// fill the array row by row with character from line
int charCount = 0;
for (int r = 0; r < height - 1; r++) {
for (int c = 0; c < width; c++) {
// check to make sure accessing past end of the line
if (charCount < line.length()) {
grid[r][c] = line.charAt(charCount);
charCount++;
}
}
}
// print to standard output the characters in array
System.out.printf("Grid width %d: \"", width);
for (int r = 0; r < width; r++) {
for (int c = 0; c < height; c++) {
System.out.print(grid[c][r]);
}
}
// !!Special handling for last row!!
int longColumn = line.length() % width;
if (longColumn == 0)
longColumn = width;
for (int c = 0; c < longColumn; c++) {
System.out.print(grid[height - 1][c]);
}
System.out.println();
}
You need to loop the rows before you loop the columns, i.e., just the way you usually don't do it.
for (int i = 0; i < array[0].length; i++) {
for (int j = 0; j < array.length; j++) {
// prints columns before rows
}
}
However, be aware that you cannot check whether one row has less columns than another within the loop. Usually array[i].length avoids any NPEs. In this case you might want to define a check whether the array at row j even has column i. This could be done within the second loop by checking:
if (array[j].length > i)
// System.out.println(...);
else
break;
Edit: I see your loop should be working correctly. Most likely height is only 1 instead of 2 and thus, the last row gets cut off. My code as it is works for your input and your loop should be working the same way. Try to print height and check if it is correct or debug your program and go through it step by step.
public static int[][] solve(int[][] input){
for (int i = 0; i < 9*9; i++){
if(input[i / 9][i % 9] != 0){
continue;
}
for (int j = 1; j <= 9; j++){
if(validNumber(input, i / 9, i % 9, j)){
input[i / 9][i % 9] = j;
solve(input);
}
}
}
return input;
}
This method should solve a (solvable) sudoku puzzle via backtracking regardless of the initial situation. It works like this:
Given a sudoku puzzle it iterates from the upper left corner over each row to the lower right corner of the 2D array. When there is already a number, it gets skipped. When there is a zero (empty field) it calculates possible values via the validNumber method. The first valid number (from 1 to 9) is put in the field and the method goes to the next field.
In this algorithm the method does not now whether or not a valid number will eventually render the puzzle unsolvable.
I want to alter it like this:
At the end, when the method finishes iterating through the whole 2d array, every entry of the array gets tested if it is a zero or not.
If there is even one zero the whole algorithm must go to the place where the very first "valid" number was put in. Now, the next "valid" number is put in and so on until there are no zeroes at the end of the algorithm.
I have some troubles implementing this thought. It seems to me there must be an other for loop somewhere, or something like a goto statement, but I don't know where to put it.
Any advice?
I implemented a Sudoku solver once before. It was a bit more complicated than what you had, but solved the game in a blink. :)
What you are attempting to do is solve Sudoku by "Brute Force" and using (tail) recursion. That means you are attempting to solve the board by iterating over all 981 possible combinations. 9 to the power of 81 is... well it's a big number. And so your approach will take eternity, but you'll run out of stack space from the tail recursion much sooner.
When I implemented Sudoko, it was more straight up. It kept a 9x9 array of "items", where each item was the value in the square, and an array of 9 booleans representing candidates (true == viable, false == eliminated). And then it just did a non-recursive loop of solving the board.
The main loop would start with the simple process of finding squares with only 1 remaining candidate. Then the next step would do simple candidate elimination based on values already assigned. Then it would work its way into more complicated elimination techniques such as X-Wing.
Your algorithm does not actually backtrack. It moves forward if it can, but it never moves backwards when it realizes it's stuck in a corner. This is because it never returns any knowledge up the stack, and it never resets squares. Unless you get really lucky, your code will get the game board into a cornered state, and then print out that cornered state. To backtrack, you need to reset the last square you set (the one that got you cornered) to zero, so your algorithm will know to keep trying other things.
For understanding backtracking, I highly recommend a book called The Algorithm Design Manual by Steven Skiena. I read it when I was preparing for SWE interviews, and it really improved my knowledge of backtracking, complexity, and graph search. The second half of the book is a catalog of 75 classic algorithmic problems, and Sudoku is one of them! He has an interesting analysis of optimizations you can make to prune the search tree and solve very hard puzzle boards. Below is some code I wrote a long time ago after reading this chapter (probably not that high quality by my current standards, but it works). I just read through it really quickly and added the solveSmart boolean in the solve method which allows you to turn one of those optimizations on or off, which results in a pretty big time savings when solving a "hard" class Sudoku board (one with only 17 squares filled in to start with).
public class Sudoku {
static class RowCol {
int row;
int col;
RowCol(int r, int c) {
row = r;
col = c;
}
}
static int numSquaresFilled;
static int[][] board = new int[9][9];
static void printBoard() {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
System.out.print(" " + (board[i][j] == 0 ? " " : board[i][j]) + " ");
if (j % 3 == 2 && j < 8)
System.out.print("|");
}
System.out.println();
if (i % 3 == 2 && i < 8)
System.out.println("---------|---------|---------");
}
System.out.println();
}
static boolean isEntireBoardValid() {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (!isBoardValid(i, j)) {
return false;
}
}
}
return true;
}
static boolean isRowValid(int row) {
int[] count = new int[9];
for (int col = 0; col < 9; col++) {
int n = board[row][col] - 1;
if (n == -1)
continue;
count[n]++;
if (count[n] > 1)
return false;
}
return true;
}
static boolean isColValid(int col) {
int[] count = new int[9];
for (int row = 0; row < 9; row++) {
int n = board[row][col] - 1;
if (n == -1)
continue;
count[n]++;
if (count[n] > 1)
return false;
}
return true;
}
static boolean isSquareValid(int row, int col) {
int r = (row / 3) * 3;
int c = (col / 3) * 3;
int[] count = new int[9];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
int n = board[r + i][c + j] - 1;
if (n == -1)
continue;
count[n]++;
if (count[n] > 1)
return false;
}
}
return true;
}
static boolean isBoardValid(int row, int col) {
return (isRowValid(row) && isColValid(col) && isSquareValid(row, col));
}
static RowCol getOpenSpaceFirstFound() {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] == 0) {
return new RowCol(i, j);
}
}
}
return new RowCol(0, 0);
}
static RowCol getOpenSpaceMostConstrained() {
int r = 0, c = 0, max = 0;
int[] rowCounts = new int[9];
int[] colCounts = new int[9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] != 0)
rowCounts[i]++;
if (board[j][i] != 0)
colCounts[i]++;
}
}
int[][] squareCounts = new int[3][3];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
int count = 0;
for (int m = 0; m < 3; m++) {
for (int n = 0; n < 3; n++) {
if (board[(i * 3) + m][(j * 3) + n] != 0)
count++;
}
}
squareCounts[i][j] = count;
}
}
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] == 0) {
if (rowCounts[i] > max) {
max = rowCounts[i];
r = i;
c = j;
}
if (colCounts[j] > max) {
max = rowCounts[j];
r = i;
c = j;
}
}
}
}
return new RowCol(r, c);
}
static boolean solve() {
if (81 == numSquaresFilled) {
return true;
}
boolean solveSmart = true;
RowCol rc = solveSmart ? getOpenSpaceMostConstrained() : getOpenSpaceFirstFound();
int r = rc.row;
int c = rc.col;
for (int i = 1; i <= 9; i++) {
numSquaresFilled++;
board[r][c] = i;
if (isBoardValid(r, c)) {
if (solve()) {
return true;
}
}
board[r][c] = 0;
numSquaresFilled--;
}
return false;
}
public static void main(String[] args) {
// initialize board to a HARD puzzle
board[0][7] = 1;
board[0][8] = 2;
board[1][4] = 3;
board[1][5] = 5;
board[2][3] = 6;
board[2][7] = 7;
board[3][0] = 7;
board[3][6] = 3;
board[4][3] = 4;
board[4][6] = 8;
board[5][0] = 1;
board[6][3] = 1;
board[6][4] = 2;
board[7][1] = 8;
board[7][7] = 4;
board[8][1] = 5;
board[8][6] = 6;
numSquaresFilled = 17;
printBoard();
long start = System.currentTimeMillis();
solve();
long end = System.currentTimeMillis();
System.out.println("Solving took " + (end - start) + "ms.\n");
printBoard();
}
}
Eventually validNumber() method will not return any number because there is no possibilities left that means one of the previous choices was incorrect. Just imagine that the algorithm is started with the empty grid (obviously this puzzle is solvable1).
The solution is to keep tree of possible choices and if some choices are incorrect, then just remove them from the tree and use the next available choice (or step back on a higher level of the tree, if there is no choice left in this branch). This method should find a solution if any. (Actually this is how I implemented my sudoku solver some time ago.)
1 IMHO there are 3 different kinds of sudoku:
"true" correct sudoku that has a single unique complete solution;
ambiguous sudoku that has multiple distinct complete solutions, e.g. a puzzle with only 7 different numbers, so it has at least two distinct solutions that differ by swapping 8th and 9th numbers;
incorrect sudoku that has no complete solution, e.g. with a row with two or more occurrences of the same number.
With this definition, a solver algorithm should either:
prove that there is no solution;
return complete solution that satisfies the initial grid.
In the case of a "true" sudoku the result is a "true" solution by definition. In the case of an ambiguous sudoku the result can be different depending on the algorithm. An empty grid is the ultimate example of ambiguous sudoku.
I'm working on a Java program that checks if a sudoku puzzle is solved or not. I have finished the horizontal and vertical number check part. But when trying to check squares, I can't do anything. Here is how my check system works.
This is what I want to make. Hope someone helps because I'm on a hard situation with square check.
int[][] SudokuBoard = new int[9][9];
// I didn't wrote the sudoku board completely hope you understood how sudoku table looks like.
public static boolean checkSquares(int[][] SquareBoard) {
int retr = false;
int loop = 0;
int[] extraboard = new int[9];
int[] truelist ={1,2,3,4,5,6,7,8,9};
for(int i = 1; i <=9 ; I++) {
//here , extraboard will have the numbers in " i " numbered sudoku square.( i is like first //,second)
Arrays.sort(extraboard);
for(int j = 0; j < 9; j++) {
if(extraboard[j] == truelist[j])
loop += 1;
}
extraboard = new int[9];
}
if(loop == 81)
retr == true;
return retr;
}
You could do
int count = 0;
for(int k = 0; k < 9; k++) {
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
extraboard[count++] = SquareBoard[i+3*k/3][j+k%3*3];
}
}
Arrays.sort(extraboard);
for(int j = 0; j < 9; j++) {
if(extraboard[j] == truelist[j])
loop += 1;
}
extraboard = new int[9];
count = 0;
}
The actual formula to calculate the location in the box is quite simple. As the board is split into rows and column, getting the location of the row and column needs to get offset based on the location of the box in the full area.
i here counts the index within the box of the row. As each row of boxes has a length of 3 in a 9x9 sudoku we need to increase the row number by 3 each time we get 3 boxes in. To figure out and only add 3 we can use some integer division.
For example:
i+i.length*k/i.length
This is obviously an syntax error as i doesn't have length but can consider it as the limit of i in the loop (in this case 3).
This would then get the current row in the box (the first i) and add that to the offset of boxes in the sudoki. That is for every 3 boxes k/i.length becomes 1 more, and we then multiply that with 3 to get the offset of 3.
In the column part we have a bit of an bigger issue as we need to offset it for every 3 we move left in the array and reset it when we get back to boxes on the far left.
So the forumla would become
j + (k%i.length)*j.length
This would give us the column in the box we are in, then we offset by the box location with k%i.length. The reason we use the i.length and not the j.length is that we need to calculate the offset by rows and then offset it by the length of the box column wise.
With this you can then apply to this to any size board. 2x2, 2x3, 3x2, 3x3 or bigger even.
public static boolean checkSquares(int[][] SquareBoard) {
int i=0, extraboard=0;
for (;i<9;i++,extraboard=0) {
for (int j=0;j<9;j++)
extraboard+=1<<(SquareBoard[i/3*3+j/3][i%3*3+j%3]-1);
if (extraboard!=(1<<9)-1) // 511, binary(511) = 111111111
break;
}
return i==9;
}
This is a solution i came up with. it uses 4 nested loops but the time complexity is still O(n^2). Basically i check the first 3 boxes on top, then the 3 boxes in the middle, then the last 3 boxes.
for (int l = 0; l < 9; l+= 3){
for (int i = 0; i < 9; i += 3){
HashSet<Character> set = new HashSet<>();
for (int j = l; j < l+3; j++){
for (int k = i; k < i+3; k++){
if (!set.contains(board[j][k])){
if (board[j][k] != '.')
set.add(board[j][k]);
}
else
return false;
}
}
}
}
return true;
and note that the sudoku might not be complete, and the missing numbers are replaced by ' . '