Optimizing N Queens code to avoid stack overflow - java

i've been trying to write a java class to solve the n queens problem using some sort of stacking and recursion, the answers are stored in grids(two dimensionnal arrays), but i've hit a dead wall which is stack overflow for recursion at n=8 (max recursion depth reached 2298)
So i've been wondering if there is some way to bypass this dead by doing something complex like allocating more heap space in java(if possible?) or using multi thread(point me out to a tutorial/examples)... or please do advice on how to optimize the code...
Thanks in advance
public void resoudre(){
this.gridPile.push(copyGrid(grid));
try{
int row = gridPile.size()-1;
if(gridPile.size()==0)row = 0;
chooseGridSpace(this.grid, locateFirstAvailable(grid, row));
if(gridPile.size() == this.taille){
gridSolutions.push(copyGrid(grid));
grid = gridPile.pop();
boolean erronous = true;
while(erronous){
try{
MakeNextUnavailable(grid, gridPile.size());
erronous = false;
}
catch(UnavailabilityException r1){
try{
grid = gridPile.pop();
}
catch(java.util.EmptyStackException r2){
return;
}
}
}
}
}
catch(InvalidPositionException e1){
this.grid = gridPile.pop();
boolean error = true;
while(error){
try{
MakeNextUnavailable(grid, gridPile.size());
error = false;
}
catch(UnavailabilityException er){
try{
this.grid = gridPile.pop();
}
catch(java.util.EmptyStackException err){
return;
}
}
}
}
catch(java.lang.ArrayIndexOutOfBoundsException e2){
return;
}
this.resoudre();
}
private static void chooseGridSpace(int[][] grid, Position a){
grid[a.getLigne()][a.getColonne()] = 1;
fillNotAvailable(grid, a);
}

Direct answer: There's no need to push whole grids onto the stack, and you might want to represent the grid as array of 8 integers denoting the Queen position at each row.
Real problem: Your code is too long and too complicated. Keep it simple! The queen's problem is usually solved by 2 functions of <10 lines each. Is is as simple as:
public static boolean isSolution(final int[] board)
{
for (int i = 0; i < board.length; i++) {
for (int j = i + 1; j < board.length; j++) {
if (board[i] == board[j]) return false; // same column "|"
if (board[i]-board[j] == i-j) return false; // diagonal "\"
if (board[i]-board[j] == j-i) return false; // diagonal "/"
}
}
return true;
}
public static void solve(int depth, int[] board)
{
if (depth == board.length && isSolution(board)) {
outputSolution(board);
}
if (depth < board.length) { // try all positions of the next row
for (int i = 0; i < board.length; i++) {
board[depth] = i;
solve(depth + 1, board);
}
}
}
Add some output code and a main program, and you're finished!
public static void outputSolution(final int[] board)
{
System.out.println("--- Solution ---");
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i]; j++) System.out.print(" ");
System.out.println("Q");
}
}
public static void main(String[] args)
{
int n = 8;
solve(0, new int[n]);
}

Reading the code, it looks like your program is using a Stack<..> and not Java recursion. Therefore it is probably running out of Java heap space rather than Java stack space. If that is the case, you can use the -Xms and -Xmx options to increase the initial and maximum heap sizes.

No reason to reach stack depth of 2298 for N = 8!
The correct algorithm is to represent the queens by an array of 8 integers, each representing the row position of the ith queen (queen per column).
Your max stack size should be 8.

In Java, the commands -ss and -oss can both be used to change the stack size.
$java -ss156k (native)
$java -oss600k (Java)
The argument is the stack size you would like in kbytes or mbytes. Experiment with some increased values until you don't overflow.

Related

How to make algorithm more efficient? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 months ago.
Improve this question
DISCLAIMER This problem is part of a COMPLETED competition and will not be reused
I was hoping someone could create and explain a solution efficient enough to run file sizes at most 15 x 15 tiles. Below is the problem:
Tiled Floor (40 points)
Sam recently hired a tile installer to tile a kitchen floor. The floor was supposed to be very colorful with no two
adjacent tiles having the same color. Unfortunately, the installer failed to ensure adjacent tiles have different
colors. The mortar is still wet, but it is difficult to lift just one tile at a time, so the installer is limited to swapping
adjacent tiles. The question is how to exchange adjacent tiles in as few moves as possible so that the floor meets
the criteria that no two adjacent tiles have the same color.
A sample input is
RGR
RPC
GRB
YPG
Representing the tiles on a three by four floor where R is a red tile, G is green, B is blue, C is cyan, P is purple, and
Y is yellow. In general, the input will be a series of lines of R, G, B, C, P, and Y. Each line will have the same length
and there will be a maximum of 15 lines with 15 characters in each line. The output is to be an integer
representing the number of swaps of adjacent tiles. For this problem, “adjacent” means touching and in the same
row or column; for example, the only two tiles are adjacent to the yellow tile in the lower left corner of the above
floor: the green tile at the start of the third row and the purple tile in the middle of the fourth row.
The output for the above floor will be
2
since the red tile at the start of row 2 can be swapped with the green tile at the start of row three, and then the
red tile in middle of row 3 can be swapped with the blue tile at the end. This gives the arrangement
RGR
GPC
RBR
YPG
Other fixes are possible such as exchanging the first two tiles on row 2 to get PRC and then exchanging the middle
tiles in rows 3 and 4. Your program does not print the resulting floor arrangement, just the minimum number of
tile swaps that must take place. Sometimes it is not possible to fix a floor:
GGYGP
CGGRG
This isn’t possible to tile because there are 6 Gs and a floor this size can fit only 5 without two being adjacent. In
cases where there is no solution, the output is to be
not possible
I have created a solution but it works only for approximately 16 tiles (4 x 4), any more takes an enormous amount of time. This is because of the recursive and naive nature of this function, for every call it calls itself at least 4 times.
Below is my attempted solution, keep in mind that there are extra methods from previous attempts and that minimumSwaps() is the main recursive method:
import java.util.*;
import java.io.*;
class Main {
private static ArrayList<String[][]> solutions = new ArrayList<String[][]>();
private static ArrayList<Integer> moves = new ArrayList<Integer>();
private static int min = Integer.MAX_VALUE;
public static void main(String[] args) throws Exception {
File file = new File("Tiles.txt");
Scanner scan = new Scanner(file);
Scanner scan1 = new Scanner(file);
int length = 0;
while (scan1.hasNextLine()) {
scan1.nextLine();
length++;
}
String[][] tiles = new String[length][];
for (int i = 0; i < length; i++) {
String line = scan.nextLine();
tiles[i] = new String[line.length()];
for (int l = 0; l < tiles[i].length; l++) {
tiles[i][l] = line.substring(l, l + 1);
}
}
System.out.println("Start");
minimumSwaps(tiles, 0, new ArrayList<String>());
//System.out.println(Arrays.toString(findCount(tiles)));
//findSolutions(new String[tiles.length][tiles[0].length], findCount(tiles), 0, 0);
//System.out.println(solutions.size());
System.out.println(min);
//display();
}
//tilesIDs: more efficient way to check if computer has seen previous situation
//how to know if there are moves that do not involve problem areas that reduces total number of moves?
public static void minimumSwaps (String[][] tiles, int moves, ArrayList<String> tilesIDs) {
if (moves < min) {
String newID = computeID(tiles);
if (linearSearch(tilesIDs, newID)) return;
tilesIDs.add(newID);
if (solved(tiles)) {
//Main.moves.add(moves);
if (moves < min) min = moves;
//solutions.add(cloneTiles(tiles));
}
else if (moves < min - 1) {
for (int i = 0; i < tiles.length; i++) {
for (int l = 0; l < tiles[i].length; l++) {
if (adjacentPresent(tiles, tiles[i][l], i, l)) {
try {
String[][] newTiles = cloneTiles(tiles);
String current = newTiles[i][l];
newTiles[i][l] = newTiles[i][l - 1];
newTiles[i][l - 1] = current;
minimumSwaps(newTiles, moves + 1, (ArrayList<String>)(tilesIDs.clone()));
}
catch (Exception e) {}
try {
String[][] newTiles = cloneTiles(tiles);
String current = newTiles[i][l];
newTiles[i][l] = newTiles[i][l + 1];
newTiles[i][l + 1] = current;
minimumSwaps(newTiles, moves + 1, (ArrayList<String>)(tilesIDs.clone()));
}
catch (Exception e) {}
try {
String[][] newTiles = cloneTiles(tiles);
String current = newTiles[i][l];
newTiles[i][l] = newTiles[i - 1][l];
newTiles[i - 1][l] = current;
minimumSwaps(newTiles, moves + 1, (ArrayList<String>)(tilesIDs.clone()));
}
catch (Exception e) {}
try {
String[][] newTiles = cloneTiles(tiles);
String current = newTiles[i][l];
newTiles[i][l] = newTiles[i + 1][l];
newTiles[i + 1][l] = current;
minimumSwaps(newTiles, moves + 1, (ArrayList<String>)(tilesIDs.clone()));
}
catch (Exception e) {}
}
}
}
}
}
}
public static boolean linearSearch(ArrayList<String> IDs, String newID) {
for (String ID : IDs) if (ID.equals(newID)) return true;
return false;
}
public static String computeID(String[][] tiles) {
String ID = "";
for (String[] letters : tiles) {
for (String letter : letters) {
ID += letter;
}
}
return ID;
}
public static String[][] cloneTiles(String[][] tiles) {
String[][] newTiles = new String[tiles.length][tiles[0].length];
for (int i = 0; i < tiles.length; i++) {
newTiles[i] = tiles[i].clone();
}
return newTiles;
}
public static boolean solved(String[][] tiles) {
for (int i = 0; i < tiles.length; i++) {
for (int l = 0; l < tiles[i].length; l++) {
if (adjacentPresent(tiles, tiles[i][l], i, l)) return false;
}
}
return true;
}
public static int minMoves() {
int min = Integer.MAX_VALUE;
for (int num : moves) if (num < min) min = num;
return min;
}
public static void findSolutions(String[][] tiles, int[] count, int i, int l) {
String[] colors = {"R", "G", "B", "C", "P", "Y"};
for (int z = 0; z < 6; z++) {
//System.out.println("testing");
if (!adjacentPresent(tiles, colors[z], i, l) && count[z] > 0) {
String[][] newTiles = new String[tiles.length][tiles[0].length];
for (int a = 0; a < newTiles.length; a++) {
for (int b = 0; b < newTiles[0].length; b++) {
newTiles[a][b] = tiles[a][b]; // clone does not work properly?
}
}
newTiles[i][l] = colors[z];
//System.out.println(Arrays.deepToString(newTiles));
int[] newCount = count.clone();
newCount[z]--;
if (l == tiles[0].length - 1 && i != tiles.length - 1) {
findSolutions(newTiles, newCount, i + 1, 0);
}
else if (l < tiles[0].length - 1) {
findSolutions(newTiles, newCount, i, l + 1);
}
else if (l == tiles[0].length - 1 && i == tiles.length - 1) {
solutions.add(newTiles);
}
}
}
}
public static boolean adjacentPresent(String[][] tiles, String color, int i, int l) {
try {
if (tiles[i][l + 1].equals(color)) return true;
}
catch (Exception e) {}
try {
if (tiles[i][l - 1].equals(color)) return true;
}
catch (Exception e) {}
try {
if (tiles[i + 1][l].equals(color)) return true;
}
catch (Exception e) {}
try {
if (tiles[i - 1][l].equals(color)) return true;
}
catch (Exception e) {}
return false;
}
public static int[] findCount(String[][] tiles) {
int[] count = new int[6];
for (String[] line : tiles) {
for (String letter : line) {
switch (letter) {
case "R": count[0]++;
break;
case "G": count[1]++;
break;
case "B": count[2]++;
break;
case "C": count[3]++;
break;
case "P": count[4]++;
break;
case "Y": count[5]++;
break;
}
}
}
return count;
}
public static void display() {
for (String[][] lines : solutions) {
for (String[] line : lines) {
for (String letter : line) {
System.out.print(letter);
}
System.out.println();
}
System.out.println("\n\n");
}
}
}
Improving the algorithm
A breadth-first search would yield, as first result, an optimal solution. It could still be slow on larger problems where the solution is deeper in; or in the worst case, when there is no solution at all.
Your current algorithm looks like backtracking, which is depth-first, and therefore you need to look at all possible solutions before being sure you have found the shortest one. This is very wasteful.
Improving the data representation
You have 6 colors in a 15x15 grid. You are currently storing up to 15x15=225 strings, and constantly copying that String[][] over. It would be a lot more efficient to use a single byte[] (of length dim x dim), which can be copied over faster. Use integers (1, 2, ...) instead of color-chars ("R", "Y", ...). With a single dimension you have to do some math to check for adjacency, but it is nothing too fancy; and you win a lot of memory locality.

CoinChange Problem with DP in Java using 2D array

I am implementing an algorithm to solve the Coin Change problem, where given an array that indicates types of coins (i.e. int[] coinValues = {1,4,6};) and a value to achieve (i.e. int totalAmount=8;), an array is returned where the value at position 0 indicates the minimum number of coins needed to achieve totalAmount. The rest of the array will keep a track of how many coins are needed to achieve the total sum.
An example input of coins = {1,4,6} and total = 8 should return the array [3,2,0,1]. However, my code is returning [1,2,0,1].
Another example would be coins = {2,4,8,16,34,40,64} and total = 50 should return the array [2, 0, 0, 0, 1, 1, 0, 0]. My code is not returning that result.
The algorithm is implemented with 2 methods: CoinChange and CoinCount. CoinChange creates the coin matrix and CoinCount keeps track of the coins required to achieve the total sum.
package P5;
import java.util.Arrays;
public class CoinChange7 {
public static int[] CoinChange(int[] v, int sum) {
int[][] aux = new int[v.length + 1][sum + 1];
// Initialising first column with 0
for(int i = 1; i <= v.length; i++) {
aux[i][0] = 0;
}
// Implementing the recursive solution
for(int i = 1; i <= v.length-1; i++) {
for(int j = 1; j <= sum; j++) {
if(i == 1) {
if(v[1] > j) {
aux[i][0]=999999999; //instead of Integer.MAX_VALUE
} else {
aux[i][j]=1 + aux[1][j-v[1]];
}
} else {
if(v[i] > j) { //choose best option ,discard this coin or use it.
aux[i][j] = aux[i - 1][j];
} else
aux[i][j] = Math.min(aux[i-1][j],1 + aux[i][j-v[i]]);
}
}
}
int []z=CoinCount(sum,aux,v);
return z; // Return solution to the initial problem
}
public static int[] CoinCount(int A, int[][] aux, int[] d){
int coin = d.length-1;
int limit=A;
int [] typo=new int[d.length+1]; //We create solution array, that will count no of coins
for (int k=0;k<typo.length;k++) {
typo[k]=0;
} while (coin>0 || limit>0){
if(limit-d[coin]>=0 && coin-1>=0){
if(1+aux[coin][limit-d[coin]]<aux[coin-1][limit]){
typo[coin+1]=typo[coin+1]+1;
limit=limit-d[coin];
} else {
coin=coin-1;
}
} else if(limit-d[coin]>=0) {
typo[coin+1]=typo[coin+1]+1;
limit=limit-d[coin];
} else if(coin-1>=0) {
coin=coin-1;
}
}
typo[0]= aux[d.length-1][A];
return typo; //return the final array with solutions of each coin
}
public static void main(String[] args) {
int[] coins = {1,4,6};
int sum = 8;
int[] x=CoinChange(coins,sum);
System.out.println("At least " + Arrays.toString(x) +" from set "+ Arrays.toString(coins)
+ " coins are required to make a value of " + sum);
}
}
Clarification
I don't know if you still need the answer to this question but I will try to answer it anyway.
First, there are a few things I would like to clarify. The coin change problem does not have a unique solution. If you want both the minimum of coins used to make the change and frequencies of coins usage, I think that depends on the approach used to solve the program and the arrangement of the coins.
For example: Take the coins to be [4,6,8] and amount = 12. You'll quickly see that the minimum coins required to make this change is 2. Going by your choice of output, the following are all correct: [2,0,2,0] and [2,1,0,1].
By the way, the Coin change problem can be solved in many ways. A simple recursive DP approach in Java is here. It only returns the min coins needed to make the change at O(nlog(n)) time and O(n) space.
Another approach is by using a 2D DP matrix (same with the approach you tried using) at both O(n^2) time and space. Explanation on how to use this approach is here. Please be careful with the explanation because it is not generally correct. I noticed it's almost the same as the one you used.
Your solution
I will mention a few things about your solution that may have affected the result.
The number of rows of the DP matrix is v.length not v.length + 1.
Based on your solution, this should not affect the result because I noticed you don't seem comfortable with zero indexes.
I think it is not necessary to initialize the first column of the DB matrix since the data type you used is int, which is 0 by default. Again, this does not affect the answer, though.
The way you filled row 1 (supposed to be the first row, but you ignored row 0) is not good and may affect the result of some solutions.
The only mistake I see there is that there is no uniform value to specify amounts (i.e. j) that cannot be solved using the single coin (i.e. v[0]). Negative numbers could have been better because any positive integer is a potential valid solution for the cell. You could use -1 (if you're going by the Leetcode instruction). This way, you'll easily know cells that contain invalid values while filling the rest of the matrix.
The way you compute aux[i][j] is wrong because you are using the wrong coins. you are using v[i] instead of v[i-1] since you aux.length is one bigger than the v.length.
I did not look at the countCoint method. It looks complex for a seemingly simple problem. Please see my solution.
My Solution
public int[] change(int[] coins, int amount){
int[][] DP = new int[coins.length][amount+1];
//fill the first column with 0
//int array contains 0 by default, so this part is not necessary
/*
for (int i = 0; i < coins.length; i++) {
DP[i][0] =0;
}
*/
//fill the first row.
//At 0th row, we are trying to find the min number of ways to change j amount using only
//one coin i.e. coins[0] (that is the meaning of DP[0][j];
for (int j = 1; j <= amount; j++) {
if(coins[0] > j || j % coins[0] != 0){
DP[0][j] = -1;
}else{
DP[0][j] = j /coins[0];
}
}
//iterate the rest of the unfilled DP
for (int i = 1; i < coins.length; i++) {
for (int j = 1; j < amount+1; j++) {
if(coins[i] > j){
DP[i][j] = DP[i-1][j];
}else {
int prev = DP[i-1][j];
int cur = 1+DP[i][j-coins[i]];
if(cur == 0){
DP[i][j] = DP[i-1][j];
} else if(prev == -1) {
DP[i][j] = 1 + DP[i][j - coins[i]];
}else{
DP[i][j] = Math.min(DP[i-1][j],1+DP[i][j-coins[i]]);
}
}
}
}
return countCoin(coins,amount,DP);
}
public int[] countCoin(int[] coins, int amount, int[][] DP){
int[] result = new int[coins.length+1];//The 1 added is to hold result.
int i = coins.length -1;
int j = amount;
//while the rest will contain counter for coins used.
result[0] = DP[i][j];
if(result[0] ==0 || result[0] ==-1)return result;
while (j > 0 ){
if(i-1 >= 0 && DP[i][j] == DP[i-1][j]){
i = i-1;
}else{
j = j - coins[i];
result[i+1] += 1;
}
}
return result;
}

How to prevent string overlap on a 2D array?

I'm making battleships and I've currently come across an issue where my ships overlap. I've tried to incorporate an if statement that will judge whether it can be placed. Here's an example of me placing two ships of length 3 down.
public static void PlaceCruiser(String[][] board) {
ThreadLocalRandom random = ThreadLocalRandom.current();
int timesplaced = 0;
int size = 3;
while (timesplaced < 2) {
int randomcruisercheck =(int)(Math.random()*2);
if (randomcruisercheck == 0) {
int column = random.nextInt(0,9);
int row = random.nextInt(0,7);
if (row + 2 < 11 && board[row][column] == "." && board[row + 1][column] == "." && board[row + 2][column] == ".") {
for(int i = 0; i<size; i++)
{
board[row+i][column] = "#";
}
System.out.println(board[row][column]);
}
timesplaced++;
}
else if (randomcruisercheck == 1) {
int column = random.nextInt(0,9);
int row = random.nextInt(0,7);
if (column + 2 < 11 && board[row][column] == "." && board[row][column + 1] == "." && board[row][column + 2] == ".") {
for (int i = 0; i<size; i++)
{
board[row][column + i] = "#";
}
System.out.println(board[row][column]);
}
timesplaced++;
}
}
}
Basically, I use "#" to represent a ship in a 10x10 2D array of ".". I feel like the if statement about if the row or column plus 1 then plus 2 is a dot i.e a free space, a ship will be generated but this does not seem to be the case. Can anyone help me out?
Your code works well, you only need to take care of the indexes and initialize the board:
public class Main {
public static String[][] board;
public static void main(String[] args) {
PlaceCruiser pc = new PlaceCruiser();
board = new String[10][10];
// Initialize the board
for (int i=0;i<10;i++) {
for (int j=0;j<10;j++) {
board[i][j]=".";
}
}
pc.placeCruiser(board);
// Show thew board
for (int i=0;i<10;i++) {
for (int j=0;j<10;j++) {
System.out.print(board[i][j]);
}
System.out.println();
}
}
}
Result:
..........
..###.....
..........
..........
....#.....
....#.....
....#.....
..........
..........
..........
Also check that your initial position is not already "#".
Stylistical remarks:
if you use ThreadLocalRandom for generating position, you should also use it for other randomness (in other words: (int)(Math.random()*2) could rather be random.nextBoolean(), because actually a boolean could decide if ship should be horizontal or vertical)
nextInt(0,x) is just a longer variant of nextInt(x).
Actual bugs:
due to a presumably copy-paste issue, column (0-"9") and row (0-"7") are generated in the same way in both cases, making it possible to index out of the array when placing a vertical ship
which you seem to have noticed, but fixed it with that row + 2 < 11 check which has two problems in itself:
when row+2 ends up being 10 (which is <11), that is an invalid index (valid indices are 0...9)
as row stays between 0 and "7", there will not be horizontal ships in the last few rows
nextInt(a,b) generates numbers a...b-1, so it will not generate b itself
as the other answer points out string comparison with == generally and usually does not work, use equals()
Generally I would suggest having a single check+placement function, which can deal with an entire rectangle (given position+size). Also, I switched to array of characters, that simplifies both comparisons and printing.
boolean tryPlace(int x,int y,int width,int height) {
for(int i=0;i<height;i++) {
for(int j=0;j<width;j++) {
if(board[y+i][x+j]!='.') {
return false; // ship can not be placed
}
}
}
// if we reach here, ship can be placed
for(int i=0;i<height;i++) {
for(int j=0;j<width;j++) {
board[y+i][x+j]='#';
}
}
return true; // ship placed successfully
}
This routine could be called to place a pair of 3-long ships this way:
board=new char[10][10];
for(int i=0;i<10;i++)
for(int j=0;j<10;j++)
board[i][j]='.';
int size=3;
int amount=2;
while(amount>0) {
if(random.nextBoolean()) {
// horizontal
if(tryPlace(random.nextInt(10-size+1),random.nextInt(10),size,1)){
amount--; // one placed
}
} else {
// vertical
if(tryPlace(random.nextInt(10),random.nextInt(10-size+1),1,size)){
amount--; // one placed
}
}
}
// and a 4x2 mothership
while(!(random.nextBoolean()
?tryPlace(random.nextInt(7),random.nextInt(9),4,2)
:tryPlace(random.nextInt(9),random.nextInt(7),2,4)
));
for(int i=0;i<10;i++)
System.out.println(board[i]); // char[] has special overload for print/ln()
Test: https://ideone.com/DjYqjB
However, when I was a kid we had a rule that ships could not match, there had to be empty space (or a border of the board) around them. If you need that, tryPlace() could check a larger block, and put the ship into the middle of it. Also, a usual trick of implementing board games is that you can keep a larger array in the memory than what you will actually display. So instead of fighting with "check if field is empty or it is outside the board", it is simpler to have a 12x12 board, and place ships into the middle 10x10 portion of it:
boolean tryPlaceWithBorder(int x,int y,int width,int height) {
for(int i=0;i<height;i++)
for(int j=0;j<width;j++)
if(board[y+i][x+j]!='.')
return false; // ship can not be placed
// if we reach here, ship can be placed
for(int i=1;i<height-1;i++)
for(int j=1;j<width-1;j++)
board[y+i][x+j]='#';
return true; // ship placed successfully
}
and modified usage:
board=new char[12][12];
for(int i=0;i<12;i++)
for(int j=0;j<12;j++)
board[i][j]='.';
int size=3;
int amount=2;
while(amount>0) {
if(random.nextBoolean()) {
// horizontal
if(tryPlaceWithBorder(random.nextInt(12-size-1),random.nextInt(10),size+2,3))
amount--; // one placed
} else {
// vertical
if(tryPlaceWithBorder(random.nextInt(10),random.nextInt(12-size-1),3,size+2)){
amount--; // one placed
}
}
}
// and a 4x2 mothership
while(!(random.nextBoolean()
?tryPlaceWithBorder(random.nextInt(7),random.nextInt(9),6,4)
:tryPlaceWithBorder(random.nextInt(9),random.nextInt(7),4,6)
));
for(int i=1;i<11;i++)
System.out.println(String.valueOf(board[i],1,10));
Test: https://ideone.com/LXAD7T

How to compress primitive integer data for an array?

I am teaching myself java using the cs106a course from Stanford.
Currently I am on chapter 10 of the book "The Art and Science of Java".
The problem is to write a 3x3 Magic Square.
The exercise:
You have to write a 3x3 array
Each side of the array(Magic Square) has to equal 15
The problem:
The program I wrote works, the assignment is complete, this question is for self learning. As a beginner I would like to improve the method SumOfSides() and make it smaller and more efficient. I tried iterating the array in this method but still have issues. Is there a way to make it more efficient?
public void run() {
//set the font
setFont("Helvetica-40");
//fill the array
fillArray();
//sum up all sides
SumOfSides();
//check if all of the sides in the magic square array equal 15:
checkSides(mSqr);
//I used this for debugging purposes only:
//showSides();
}
//for debugging purposes:
public void showSides() {
println(sumRight0);
println(sumRight1);
println(sumRight2);
println(sumBottom0);
println(sumBottom1);
println(sumBottom2);
println(sumDiagonalUp);
println(sumDiagonalDown);
}
public void SumOfSides() {
sumRight0 = mSqr[0][0] + mSqr[0][1] + mSqr[0][2];
sumRight1 = mSqr[1][0] + mSqr[1][1] + mSqr[1][2];
sumRight2 = mSqr[2][0] + mSqr[2][1] + mSqr[2][2];
sumBottom0 =mSqr[0][0] + mSqr[1][0] + mSqr[2][0];
sumBottom1 =mSqr[0][1] + mSqr[1][1] + mSqr[2][1];
sumBottom2 =mSqr[0][2] + mSqr[1][2] + mSqr[2][2];
sumDiagonalUp = mSqr[2][0] + mSqr[1][1]+ mSqr[0][2];
sumDiagonalDown = mSqr[0][0] + mSqr[1][1] + mSqr[2][2];
}
/*This predicate method checks if the sides
of the array add up to 15: */
public boolean checkSides(int[][] myArray) {
if (sumRight0 ==15 && sumRight1 ==15&& sumRight2==15 && sumBottom0==15&& sumBottom1==15&&
sumBottom2==15&& sumDiagonalUp==15&&sumDiagonalDown==15) {
println("True, this is a Magic Square");
return true;
} else {
println("False, the sides do not equal 15");
return false;
}
}
public void fillArray() {
int num =0;
for(int row=0; row <3; row++) {
for (int col=0; col<3; col++) {
num=readInt("");
mSqr[row][col]=num;
}
}
/*Test array values here to see
* if they were entered correctly.
*/
//println(mSqr[1][2]); //should be 6
//println(mSqr[2][0]); //should be 7
}
//instance variables:
int[][] mSqr= new int[3][3];
List<List<Integer>> new1 = new ArrayList<>();
private int sumRight0;
private int sumRight1;
private int sumRight2;
private int sumBottom0;
private int sumBottom1;
private int sumBottom2;
private int sumDiagonalUp;
private int sumDiagonalDown;
}
Perhaps the only thing is readability. You could take the values and move them into more readable variables:
int topLeft = mSqr[0][0];
int topMid = mSqr[0][1];
...
int sumLeft = topLeft + midLeft + bottomLeft;
int sumRight = topRight = midRight + bottomRight;
...
To address your concern of making it smaller, I would argue that converting the sums into loops, as you mentioned, is certainly not worth it in the case that you are doing 6 sums of 3 values each. Furthermore, each term of each sum is common to either one or two other sums, which does not provide much overlap. If you were performing larger sums (larger in number of terms in the sum, not the total value), then perhaps it would be worth it on a readability/SLOC argument.
Suppose you did want to do a loop still though, you could do something like
sumLeft = 0;
sumRight = 0;
sumTop = 0;
sumBottom = 0;
sumDiagonalUp = 0;
sumDiagonalDown = 0;
for(int i = 0; i < mSqr.length; i++) {
for(int j = 0; j < mSqr[i].length; j++) {
if (i == 0) {
sumLeft += mSqr[i][j];
}
if (i == mSqr.length - 1) {
sumRight += mSqr[i][j];
}
if (j == 0) {
sumTop += mSqr[i][j];
}
if (j == mSqr[i].length) {
sumBottom += mSqr[i][j];
}
if (i == j) {
sumDiagonalDown += mSqr[i][j];
}
if (i + j == mSqr.length - 1) {
sumDiagonalUp += mSqr[i][j];
}
}
}
The loops only provide benefit on large magic squares.
Also, I am confused by your description contrasted with your implementation. It seems you are summing each row and column, and the two diagonals of the square, as opposed to the 4 sides and the diagonals.

How to generate sums of combinations of elements of a set efficiently in terms of time and memory?

I have a random set S of integers and the cardinality (n) of this set may vary from 10 to 1000. I need to store all sums of the nCr combinations of size r generated from this set. Usually r range from 3 to 10.
E.g. if S={102,233,344,442,544,613,71289,836,97657,12} and r=4, Then The sums generated will be {0,1,2,3}=102+233+344+442, {0,1,2,4}=102+233+344+544,....so on.
I implemented a findCombi function (below) in Java which gave me all nCr combinations in terms of r sized sets of indices and then I sifted through these sets in another function to generate the sum of corresponding elements.
But the program is giving heapspace error, probably because of exponential nature and I have 100-5000 of such sets, S. Or may be there is a memory leak?
Is there a faster and lesser-memory consuming way to do it?
Note: dsize=n, combiSize=r
List <List<Integer>> findCombi(int dsize,int combiSize) {
if( (combiSize==0) || (dsize==0) ){
return null;
}
long n=dsize;
int r=combiSize;
for(int i=1;i<combiSize;i++) {
n=n*(dsize-i);
r=r*i;
}
int totalcombi=(int) n/r;
List <List<Integer>> combiData=new ArrayList<>(totalcombi);
int pos;
List <Integer> combi=new ArrayList<>(combiSize);
for(int i=0;i<combiSize;i++) {
combi.add(i,i);
}
combiData.add(new ArrayList<>(combi));
pos=combiSize-1;
while(true) {
if(combi.get(pos)<(dsize-combiSize+pos)) {
combi.set(pos,combi.get(pos)+1);
if(pos==(combiSize-1)) {
combiData.add(new ArrayList<>(combi));
}
else {
combi.set(pos+1,combi.get(pos));
pos++;
}
}
else {
pos--;
}
if(pos==-1) {
break;
}
}
return combiData;
}
I needed something like that earlier, so here is some code adapted from the project I made back then. The method allSums builds a list of indices of size r, which is used to represent all the possible combinations. At each step, the current sum is added to the result set, then the next combination is generated. Since the results are put in a set, there is no way a result could appear twice. I included a main method so you can see it work. I hope this is clear, feel free to ask questions.
import java.util.*;
public class Program {
static private Set<Integer> allSums(List<Integer> values, int r) {
HashSet<Integer> res = new HashSet<>();
if ((values.isEmpty()) || r > values.size()) {
return res;
}
// build the list of indices
List<Integer> li = new ArrayList<>();
for (int i = 0; i < r; i++) {
li.add(i);
}
li.add(values.size()); // artificial last index : number of elements in set
while (true) {
// add the current sum to the result
int sum = 0;
for (int i = 0; i < r; i++) {
sum += values.get(li.get(i));
}
res.add(sum);
// move to the next combination
// first, find the last index that can be incremented
int i = r-1;
while ((i >= 0) && (li.get(i) == li.get(i+1)-1)) {
i--;
}
// was such an index found ?
if (i == -1) {
break; // if not, it's over
}
// increment the last index and set all the next indices to their initial value
li.set(i,li.get(i)+1);
for (int j = i+1; j < r; j++) {
li.set(j, li.get(j-1)+1);
}
}
return res;
}
public static void main(String[] args) {
List<Integer> values = new ArrayList<>();
values.add(10);
values.add(100);
values.add(1000);
values.add(10000);
values.add(100000);
Set<Integer> s = allSums(values, 3);
for (int i : s) {
System.out.println(i);
}
}
}

Categories