Related
public static boolean isSplitable(int[] arr, int diff, int i)
no loops or helper methods i need to check if arr[i...arr.length - 1] has a two section sum that is equal to diff
for example i have: diff = 1, i = 2, arr = {3, 4, 1, 1, 2, 0, 1, 1, 3} it returns true because sum of {1, 1, 2, 0}(4) minus the sum of {1, 1, 3}(5) equals diff(1).
i have tried to think of ways to even sum arr without a loop only thing i came up with is adding it to diff but then i lose my original diff plus i dont know the amount of elements so i can add "or" in my return statement so now im out of ideas.
I'm assuming your restrictions are no loops and no library usage. You probably need some kind of additional functions. Moreover, I assume the difference check shall use absolute values, i.e. it does not matter if the first or second sum is smaller, as long as the difference matches (-1 or 1 in your example). That being said, a first approach could look like this:
import org.junit.jupiter.api.Test;
import static java.util.Arrays.copyOfRange;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class RecursiveSplitTest {
#Test
public void testIsSplitable() {
{
int[] array = {3, 4, 1, 1, 2, 0, 1, 1, 3};
assertTrue(isSplitable(array, 1, 2));
}
{
int[] array = {3, 4, 1, 1, 1, 0, 4, 1, 3};
assertTrue(isSplitable(array, 1, 4));
}
{
int[] array = {3, 4, 1, 1, 1, 0, 4, 1, 3};
assertFalse(isSplitable(array, 1, 7));
}
{
int[] array = {3};
assertFalse(isSplitable(array, 1, 1));
}
}
public static boolean isSplitable(int[] array, int diff, int start) {
if (start < 0 || start > array.length - 2) {
System.out.println("Not possible due to initial parameters");
return false;
}
return doSplitableRecursive(copyOfRange(array, start, array.length), diff, 0);
}
private static boolean doSplitableRecursive(int[] array, int diff, int start) {
if (start + 1 >= array.length) {
System.out.println("Could not find it");
return false;
}
int[] left = copyOfRange(array, 0, start + 1);
int[] right = copyOfRange(array, start + 1, array.length);
int leftSum = sum(left, 0);
int rightSum = sum(right, 0);
System.out.println("leftSum: " + leftSum);
System.out.println("rightSum: " + rightSum);
if (leftSum + diff == rightSum || leftSum - diff == rightSum) {
System.out.println("Found match for cut at start + " + (start + 1));
return true;
}
return doSplitableRecursive(array, diff, start + 1);
}
private static int sum(int[] array, int current) {
if (array.length == 0) {
return current;
}
return sum(copyOfRange(array, 1, array.length), current + array[0]);
}
}
The key is to systematically divide the array in two pieces, beginning at start and checking the sum of each piece against the difference. Then cutting one index further and repeating the process if it did not match. Finally, you have to exit with false if there are no more elements left.
It is a little rough around the edges. Feel free to improve it and fix possibly remaining bugs. The print statements are for debugging purposes. Of course, one could argue JUnit and java.util.Arrays are library functions. These can be replaced with a little bit of extra effort if needed.
I am trying to search for a number in a particular column of a two dimensional array. I tried a few different approach and would like to use stream in Java 8. However, it doesn't seem to be the best performance. Wonder if someone can help?
boolean isInColumn(int col, int number) {
return IntStream.range(0, board.length)
.map(i -> board[i][col])
.filter(num -> num == number )
.findFirst()
.isPresent();
}
trying to search in a block as well. Any hints?
public boolean isInBlock(int row, int col, int number) {
int r = row - row % 3;
int c = col - col % 3;
for (int i = r; i < r + 3; i++) {
for (int j = c; j < c + 3; j++) {
if (board[i][j] == number)
return true;
}
}
return false;
}
the input data is the following array.
public static int[][] PUZZLE = {
{9,0,0,1,0,0,0,0,5},
{0,0,5,0,9,0,2,0,1},
{8,0,0,0,4,0,0,0,0},
{0,0,0,0,8,0,0,0,0},
{0,0,0,7,0,0,0,0,0},
{0,0,0,0,2,6,0,0,9},
{2,0,0,3,0,0,0,0,6},
{0,0,0,2,0,0,9,0,0},
{0,0,1,9,0,4,5,7,0},
};
This 'stream'-version seems a little bit optimzed, but I think searching for a hit in an array will always be faster the old fashioned way, see Java performance tutorial – How fast are the Java 8 streams?
boolean isInColumn(int col, int number) {
return IntStream.range(0, board.length)
.anyMatch(i -> (board[i][col] == number) );
}
I made a short attempt with a parallel stream, but the overhead made it far worse.
I think it would be different if the action wasn't a simple compare...
If it's only about speed for a Sudoku-solver/generator maybe you shouldn't loop at all but write the 9 conditions in one return statement
return board[0,col] == number || board[1,col] == number ...
Since this seems to be Sudoku what you could do is store the data redundantly. Don't only store the numbers in "normally" in a two dimensional array, but also have two-dimensional boolean arrays, where you store whether the row/column/block contains the number.
class Sudoku {
private final int[][] puzzle = new int[9][9];
private final boolean[][] rows = new boolean[9][9];
private final boolean[][] columns = new boolean[9][9];
private final boolean[][] blocks = new boolean[9][9];
public void setCell(int row, in column, int number) {
puzzle[row][column] = number;
rows[row][number - 1] = true;
columns[column][number - 1] = true;
blocks[calcBlockId(row, column)][number - 1] = true;
}
// returns a number (0 - 8) identifying a block
// 0 - 2 is first line, 3 - 5 second line, etc.
private int calcBlockId(int row, int column) {
// Left as an exercise to the reader
}
public boolean isInColumn(int col, int number) {
return columns[col][number - 1];
}
public boolean isInBlock(int row, int column, int number) {
return blocks[calcBlockId(row, column)][number - 1];
}
}
This code searches for an element in a 2d array and returns the coordinates of the first match, if such an element is present, or null otherwise:
public static int[] findElement(int[][] arr, int element) {
return IntStream
// iterate through the indexes
// of the rows of the array
.range(0, arr.length)
// for each row
.mapToObj(i -> {
// look for the element in this row
int j = IntStream
// iterate through the indexes
// of the elements of the row
.range(0, arr[i].length)
// filter a matching element
.filter(el -> arr[i][el] == element)
// take first match
.findFirst().orElse(-1);
// if element is present
if (j >= 0)
// return its coordinates
return new int[]{i, j};
else
// or null otherwise
return null;
})
// take first non-null coordinates, if they are present
.filter(Objects::nonNull).findFirst()
// or null otherwise
.orElse(null);
}
// test
public static void main(String[] args) {
int[][] puzzle = {
{9, 0, 0, 1, 0, 0, 0, 0, 5},
{0, 0, 5, 0, 9, 0, 2, 0, 1},
{8, 0, 0, 0, 4, 0, 0, 0, 0},
{0, 0, 0, 0, 8, 0, 0, 0, 0},
{0, 0, 0, 7, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 2, 6, 0, 0, 9},
{2, 0, 0, 3, 0, 0, 0, 0, 6},
{0, 0, 0, 2, 0, 0, 9, 0, 0},
{0, 0, 1, 9, 0, 4, 5, 7, 0}};
int[] coordinates = findElement(puzzle, 7);
System.out.println(Arrays.toString(coordinates)); // [4, 3]
}
See also:
• Difference between anyMatch and findAny in java 8
• First unique character in a string using LinkedHashMap
I have the following array:
int [] mi_array= {9,4,0,0,4,0,3,0,1,8,0};
I want to order the numbers other than 0 on the left, and the 0s on the right, but I find that the function steps on one of the numbers.
The output must be
{9,4,4,3,1,8,0,0,0,0,0}
public class Array {
public static void main(String[] args) {
int [] mi_array= {9,4,4,3,1,8,0,0,0,0,0};
int x=0;
int y=mi_array.length-1;
for (int i=0;i<mi_array.length;i++)
if(mi_array[i]!=0) {
mi_array[x]=mi_array[i];
x++;
}
else {
mi_array[y]=mi_array[i];
y--;
}
for (int i=0;i<mi_array.length;i++)
System.out.println(mi_array[i]);
System.out.println(x);
}
}
Try this.
int[] mi_array = {9, 4, 0, 0, 4, 0, 3, 0, 1, 8, 0};
for (int i = 0, j = i + 1, s = mi_array.length; j < s;)
if (mi_array[i] == 0) {
mi_array[i] = mi_array[j];
mi_array[j] = 0;
++j;
} else if (++i >= j)
j = i + 1;
System.out.println(Arrays.toString(mi_array));
// -> [9, 4, 4, 3, 1, 8, 0, 0, 0, 0, 0]
You can use filter and IntStream.concat to merge the parts of the array that are not 0 with the parts that are.
final int[] mi_array = { 9, 4, 0, 0, 4, 0, 3, 0, 1, 8, 0 };
final int[] result = IntStream.concat(Arrays.stream(mi_array).filter(i -> i != 0),
Arrays.stream(mi_array).filter(i -> i == 0)).toArray();
System.out.println(Arrays.toString(result));
Demo!
You can also do this:
final int[] mi_array = { 9, 4, 0, 0, 4, 0, 3, 0, 1, 8, 0 };
final int[] result = new int[mi_array.length];
final AtomicInteger idx = new AtomicInteger();
Arrays.stream(mi_array).filter(i -> i != 0).forEach(val -> result[idx.getAndIncrement()] = val);
System.out.println(Arrays.toString(result));
Your primary problem here is that you overwrite numbers you haven't already covered.
if (mi_array[i] != 0) {
mi_array[x] = mi_array[i];
x++;
}
x can never exceed i in this code; it starts at 0 just like i does, and increments at most by 1 every loop (and i increments by 1 every loop). So, no problem here; at 'worst' this is mi_array[i] = mi_array[i]; which does nothing.
however...
} else {
mi_array[y]=mi_array[i];
y--;
}
This is much more problematic. Given inputs {9,4,0,0,4,0,3,0,1,8,0};, when i is 2, then mi_array[i] is 0, thus this code runs. y is still 10, so this will end up running: mi_array[10] = 0;. The second 0 occurs when i is 3, and ends up running: mi_array[9] = 0;. And at that point, the 8 at index 9? You deleted it. It cannot be recovered.
The solution
The dumb solution is to make a copy of the array; edit the copy, refer to the original (which you won't change at all). You don't actually end up needing a copy; this code will write every number back, so just make a new array of the same size and write in that.
A slightly more elegant solution will not write 0s at all. Instead, it just writes the non-zeroes (as that code cannot overwrite anything, as shown before), and then at the end, overwrite the rest with zeroes. Now you don't need a copy.
O(n), two-pointer approach:
public static void shiftZeroesRight(int[] array) {
int notZeroPos;
for (int i = 0; i < array.length; i++) {
if (array[i] != 0)
continue;
notZeroPos = i + 1;
while (notZeroPos < array.length && array[notZeroPos] == 0)
++notZeroPos;
if (notZeroPos >= array.length)
break;
array[i] = array[notZeroPos];
array[notZeroPos] = 0;
}
}
I have an adjacency matrix adj of the form below:
0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0
1 0 0 0 1 0 1 0 0
0 0 0 1 0 1 0 0 0
0 0 1 0 1 0 0 0 1
0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0
This is the adjacency matrix for a maze with rules adj(x,y) = 1 if:
x != y
x is adjacent to y
neither x or y is a wall in the maze
The maze is as below (beside it are the element numbers):
S X E | 1 2 3
O O O | 4 5 6
O X O | 7 8 9
//S = starting position
//E = ending position
//X = wall
I have a DFS algorithm that will display the nodes to traverse from S to E, but it displays unnecessary nodes.
public static void main(String [] args){
int[][] adj = //the adjacency matrix
boolean[] visited = new boolean[adj.length];
int n = adj.length;
int m = 1; //starting position
int o = 3; //ending position
DFS(adjMatrix, visited, n, m, o);
}
public static void DFS(int[][] adj, boolean[] visited, int n, int i, int o){
System.out.print(" " + (i+1));
visited[i]= true;
if (i+1 != o) {
for (int j = 0; j<n;j++){
if(!(visited[j]) && adj[i][j]==1){
DFS(adj, visited, n, j, o);
}
}
}
}
public static void BFS(int[][] adj, boolean[] visited, int n, int i, int o){
queue Q = new queue;
visited[i]= true;
Q.enqueue(i);
while (!Q.isEmpty()) {
//...
}
}
This prints 1 4 5 6 3 9 7. I'm wracking my head around modifying it so that it will only print 1 4 5 6 3.
What have I done wrong here?
There are some major issues with the code, in addition to fixes needed for the DFS algorithm:
You Start and end are wrong: it should be decreased by 1 (because the
indices are 0 based)
Your adjanecy matrix is wrong (it is of size 10X9 - it should be a squared matrix)(edit fixed it)
Your solution should only print elements that are in the path. One way to do it would be to return a List<> (rather than void - that populates all the nodes in the current path. If you reached the destination, create the list, otherwise - return null. Attach elements only when the recursive call returns something that is not null. Code attached
Also note, it prints the nodes in the correct order (and not reversed order)
public static void main(String [] args){
int[][] adj = {
{0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 1, 0, 0, 0},
{1, 0, 0, 0, 1, 0, 1, 0, 0},
{0, 0, 0, 1, 0, 1, 0, 0, 0},
{0, 0, 1, 0, 1, 0, 0, 0, 1},
{0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 1, 0, 0, 0}
};
boolean[] visited = new boolean[adj.length];
int n = adj.length;
int m = 1-1; //starting position
int o = 3-1; //ending position
System.out.println(DFS(adj, visited, n, m, o));
}
public static List<Integer> DFS(int[][] adj, boolean[] visited, int n, int i, int o){
visited[i]= true;
if (i == o) return new LinkedList<Integer>(Arrays.asList(i+1));
for (int j = 0; j<n;j++){
if(!(visited[j]) && adj[i][j]==1){
List<Integer> res = DFS(adj, visited, n, j, o);
if (res != null) {
res.add(0, i+1);
return res;
}
}
}
return null; //no path
}
Will result (as expected) with:
[1, 4, 5, 6, 3]
As a side note, though this solution is complete (will always find a solution if such exists), it is not optimal - it might return a longer solution than the shortest one.
If you want to find the shortest path from source to target, consider switching to a BFS
When you finally reach your destination, the method stack will have the path.
ArrayList<Integer> list = new ArrayList<>(); // this will have your path.
public static boolean DFS(int[][] adj, boolean[] visited, int n, int i, int o){
if(i==o){
list.add(o);
//System.out.println(i);
return true;
}
visited[i]= true;
for (int j = 0; j<n;j++){
if(!(visited[j]) && adj[i][j]==1){
if(DFS(adj, visited, n, j, o)){
list.add(0,j);
//System.out.println(j);
return true;
}
}
}
return false;
}
Try with this code:
public static boolean DFS(int[][] adj, boolean[] visited, int n, int i, int o){
visited[i]= true;
boolean good = false;
if (i+1 != o) {
for (int j = 0; j<n;j++){
if(!(visited[j]) && adj[i][j]==1){
good |= DFS(adj, visited, n, j, o);
}
}
} else {
good = true;
}
if (good) System.out.print(" " + (i+1));
return good;
}
This will print paths in reverse (from end to start) - but it will only print nodes that are part of a good path. If you need to print the path in start-to-end order, you can store it in an array and then print it in reverse:
public static void DFS(int[][] adj, boolean[] visited,
ArrayList<int> path, int n, int i, int o){
visited[i]= true;
if (i+1 != o) {
for (int j = 0; j<n;j++){
if(!(visited[j]) && adj[i][j]==1){
path.add(j);
DFS(adj, visited, n, j, o);
path.remove(path.size()-1);
}
}
} else {
// show path
for (int i : path) {
System.out.print(" " + i);
}
}
}
I am really stuck at this problem.
In this problem, you are given a 2xN board. You need to fill in non-negative numbers in this board in such a way, that:
The sum of all the numbers filled = N
Each of the 2 rows
consist of numbers in non-increasing order
Each of the N
columns consist of numbers in non-increasing order.
In how many ways can this be done, given the number N?
Two ways are considered different if there is a cell in the board which has different numbers.
The output should be the number of ways the matrix can be formed.
The matrix can have repetitive numbers and zero can be used. The matrix should not have increasing numbers but equal numbers can be filled along side each other.
Example:
input-> 5
output->16
From your example (input=5, output=16) I suppose only integer numbers are allowed.
One naive (brute force) solution is to use backtracing algorithm:
http://en.wikipedia.org/wiki/Backtracking
On this site you can see example with sudoku board being filled until solution is found.
==
For example:
You have array of integers with size 2N.
For position 0 you take first free number.
If solution is not broken yet you go to position 1 of array.
If solution is broken - stop as cannot back anymore
For position 1 you take next free number.
If solution is not broken you you go to position 2 of array.
If solution is broken you back to previous sten and take next free number.
For position 2...
This is typically done with recursion.
I think, on each position (recursion level) numbers can be taken from pool 0..N.
Try - good luck.
EDIT:
Here is valid solution (using backtracking algo):
private final int N = 5;
// 2 rows in one array [0..N-1, N..2N-1]
private int[] board = new int[2 * N];
// found solution counter
int found = 0;
/*
* this method set next number to current position
* and recursively go to next position.
*/
public void check(int position) {
// if board is complete - check if valid
if (position == 2 * N) {
if (isValid()) {
System.out.println("foun : " + Arrays.toString(board));
found++;
}
return;
}
// if board is not complete - put all numbers (0..N) into current position
// and recursively go to next position
for (int v = 0; v <= N; v++) {
board[position] = v;
// if solution is already broken - step backwards
// see: backtracking algorithms
if (isBroken(position)) {
return;
}
check(position + 1);
}
}
public boolean isValid() {
// condition 1
int sum = 0;
for (int i = 0; i < board.length; i++) {
sum += board[i];
}
if (sum != N) {
return false;
}
// conditin 2
int prev = board[0];
for (int i = 1; i < N; i++) {
if (board[i] > prev) {
return false;
}
prev = board[i];
}
prev = board[N];
for (int i = N + 1; i < 2 * N; i++) {
if (board[i] > prev) {
return false;
}
prev = board[i];
}
// condition 3
for (int i = 0; i < N; i++) {
int top = board[i];
int bottom = board[i + N];
if (top < bottom) {
return false;
}
}
// valid
return true;
}
// simplified version of this method - but correct
public boolean isBroken(int current) {
int sum = 0;
for (int i = 0; i <= current; i++) {
sum += board[i];
}
return sum > N;
}
public void start() {
check(0);
System.out.println("found: " + found);
}
And program output for N = 5:
found : [1, 1, 1, 0, 0, 1, 1, 0, 0, 0]
found : [1, 1, 1, 1, 0, 1, 0, 0, 0, 0]
found : [1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
found : [2, 1, 0, 0, 0, 1, 1, 0, 0, 0]
found : [2, 1, 0, 0, 0, 2, 0, 0, 0, 0]
found : [2, 1, 1, 0, 0, 1, 0, 0, 0, 0]
found : [2, 1, 1, 1, 0, 0, 0, 0, 0, 0]
found : [2, 2, 0, 0, 0, 1, 0, 0, 0, 0]
found : [2, 2, 1, 0, 0, 0, 0, 0, 0, 0]
found : [3, 0, 0, 0, 0, 2, 0, 0, 0, 0]
found : [3, 1, 0, 0, 0, 1, 0, 0, 0, 0]
found : [3, 1, 1, 0, 0, 0, 0, 0, 0, 0]
found : [3, 2, 0, 0, 0, 0, 0, 0, 0, 0]
found : [4, 0, 0, 0, 0, 1, 0, 0, 0, 0]
found : [4, 1, 0, 0, 0, 0, 0, 0, 0, 0]
found : [5, 0, 0, 0, 0, 0, 0, 0, 0, 0]
found: 16
I'm almost positive this has a solution in closed form, or its similar to another problem with a solution in closed form. I would do it programmatically with recursion.
So suppose you know a solution for N. You want N+1. So what you should do is take all the solutions for N and see where you can stick an extra 1 in there without breaking any constraints. That is, super impose the N solution(s) on the N+1 board then try in all 2N places to add 1 without breaking constraints. Then store all of them in a set so they will be deduped.
In any case, its similar to http://en.wikipedia.org/wiki/Partition_(number_theory)
Here's a brute force way: since this is a 2xN matrix and the sum of all numbers must be N, the simplest solution is to fill the first row with 1's, and the 2nd row with 0's. Now you will need a recursive algorithm that takes a valid board, and removes 1 from any "free" position and add it to any legal position. That board is also a solution. By "free" I mean a number n at position [i, j] where [i+1, j] <= n - 1 and [i, j + 1] <= n - 1. You then recursively invoke the algorithm on the new boards, and save everything.
All that's left is to deduplicate solutions.
Example of the algorithm on input 5:
Initial solution:
11111
00000
The only "free" number is [0, 4]. Remove 1, the only legal positions are [0, 0] and [0, 1]. This gives you 2 new solutions
21110
00000
and
11110
10000
Now apply same algorithm again on both these solutions. Notice that the 2nd board now has 2 "free" numbers. Repeat until you get to
50000
00000
EDIT: Just had a lot of fun coding this example. Didn't test it, but that's where my head is going:
public void TwoRowBoard()
{
var board = new int[2, N];
//Create initial, simplest solution.
for (int i = 0; i < N; i++)
{
board[0, i] = 1;
}
var solutions = new List<int[,]>();
RecursiveSolve(board, solutions);
}
private void RecursiveSolve(int[,] board, List<int[,]> solutions)
{
var freeNumbers = GetFreeNumbers(board);
foreach (var freeNumber in freeNumbers)
{
board[freeNumber.i, freeNumber.j] -= 1;
var legalPositions = GetLegalPositions(board);
foreach (var legalPosition in legalPositions)
{
var newBoard = Copy(board);
newBoard[legalPosition.i, legalPosition.j] += 1;
solutions.Add(newBoard);
RecursiveSolve(newBoard, solutions);
}
}
}
private List<Coordinates> GetLegalPositions(int[,] board)
{
//Position 0, 0 is always legal.
var results = new List<Coordinates> {new Coordinates {i = 0, j = 0}};
//Row 0
for (int j = 1; j < N; j++)
{
if (board[0, j - 1] > board[0, j])
{
results.Add(new Coordinates{i = 0, j = j});
}
}
//Row 1. Board[1, higher than N/2] are never legal positions.
for (int j = 0; j <= N /2; j++)
{
if (board[1, j - 1] > board[1, j]
&& board[0, j] > board[1, j])
{
results.Add(new Coordinates{i = 1, j = j});
}
}
return results;
}
private List<Coordinates> GetFreeNumbers(int[,] board)
{
var results = new List<Coordinates>();
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < N; j++)
{
if (i == 0 && j == 0)
{
continue;
}
if (i == 0)
{
if (j == N - 1 && board[0, j] > 0)
{
results.Add(new Coordinates {i = 0, j = j});
}
else if (board[0, j] > board[1, j]
&& board[0, j] > board[0, j + 1])
{
results.Add(new Coordinates {i = 0, j = j});
}
}
else
{
if (j > N/2 && board[1, j] > 0)
{
throw new Exception("Don't see how it's possible for board[1, N/2 or higher] to not be 0");
}
if (board[1, j] > board[1, j + 1])
{
results.Add(new Coordinates{i = 1, j = j});
}
}
}
}
return results;
}
public class Coordinates
{
public int i { get; set; }
public int j { get; set; }
}