My program is working fine, in terms of output, but for some of my test cases it takes too long to find an answer (sometimes taking 18 seconds). I would like to know how I can improve the performance of my code.
What my code does:
It's a take on Pebble Solitaire. The user inputs n number of games and after that inputs a strings of length 23 that contains a combinations of only 'o' (pebble) and '-' (empty space). If there are 2 adjacent pebbles and an empty space on either side, ie (oo- OR -oo), then you remove the middle pebble and you swap other two pieces with each other, ex 'oo-' will turn into '--o'.
My current approach is pretty much an exhaustive approach where it tries out every possible move and results the move set with the least number of pebbles left.
I would like to know how I can improve this solution without making it multi-threaded.
Here is what I have:
package Pebble;
import java.util.Scanner;
public class PebbleSolitaire {
public static void main(String[] args){
Scanner input = new Scanner(System.in);
int numOfGames = Integer.parseInt(input.nextLine());
while (numOfGames > 0){
char[] values = input.nextLine().toCharArray();
long startTime = System.nanoTime();
System.out.println(solve(values));
System.out.println("Time to finish in ms: " + (System.nanoTime() - startTime) / 1000000);
numOfGames--;
}
input.close();
}
private static int solve(char[] game){
if(game != null && game.length == 0){
return -1;
}
int result = 0;
for (int i = 0; i < game.length; i++){
if(game[i] == 'o'){
result++;
}
}
//print(game);
for (int i = 0; i < game.length; i++ ){
char[] temp = new char[game.length];
copyArray(temp, game);
if (i-2 >= 0 && temp[i] == '-' && temp[i-2] == 'o' && temp[i-1] == 'o'){//move pebble forwards
temp[i-1] = temp[i-2] = '-';
temp[i] = 'o';
result = Math.min(result, solve(temp));
}
copyArray(temp, game);
if(i+2 < temp.length && temp[i] == '-' && temp[i+1] == 'o' && temp[i+2] == 'o'){//move pebble backwards
temp[i+1] = temp[i+2] = '-';
temp[i] = 'o';
result = Math.min(result, solve(temp));
}
}
return result;
}
private static void copyArray(char[] copy, char[] og){
for(int x = 0; x < copy.length; x++){
copy[x] = og[x];
}
}
private static void print(char[] c){
for(char ch: c){
System.out.print(ch);
}
System.out.println();
}
}
My sample input and output:
2
-o----ooo----o----ooo--
6
Time to finish in ms: 0
oooooooooo-ooooooooooo-
4
Time to finish in ms: 18149
EDIT: Would making this completely iterative drastically improve the performance?
Maybe you can improve this parte:
for (int i = 0; i < game.length; i++ ){
char[] temp = new char[game.length];
copyArray(temp, game);
if (i-2 >= 0 && temp[i] == '-' && temp[i-2] == 'o' && temp[i-1] == 'o'){//move pebble forwards
temp[i-1] = temp[i-2] = '-';
temp[i] = 'o';
result = Math.min(result, solve(temp));
}
copyArray(temp, game);
if(i+2 < temp.length && temp[i] == '-' && temp[i+1] == 'o' && temp[i+2] == 'o'){//move pebble backwards
temp[i+1] = temp[i+2] = '-';
temp[i] = 'o';
result = Math.min(result, solve(temp));
}
}
to:
for (int i = 0; i < game.length; i++ ){
char[] temp = null;
if (i-2 >= 0 && game[i] == '-' && game[i-2] == 'o' && game[i-1] == 'o'){//move pebble forwards
temp = new char[game.length];
copyArray(temp, game);
temp[i-1] = temp[i-2] = '-';
temp[i] = 'o';
result = Math.min(result, solve(temp));
}
if(i+2 < game.length && game[i] == '-' && game[i+1] == 'o' && game[i+2] == 'o'){//move pebble backwards
if(temp == null) temp = new char[game.length];
copyArray(temp, game);
temp[i+1] = temp[i+2] = '-';
temp[i] = 'o';
result = Math.min(result, solve(temp));
}
}
Basically, only creating and "copyArray(temp, game);" when strictly necessary.
Related
The examples look like this, Input : "a-(b+c)" output "a-b-c", Input : "a-(a+b)" output "b"
I came up with this method, but the result for input: "a-(a+b)" is "a-a-b", which the correct one should be "b", how to improve that?
public String simplify(String str)
{
int len = str.length();
char res[] = new char[len];
int index = 0, i = 0;
Stack<Integer> s = new Stack<Integer> ();
s.push(0);
while (i < len) {
if (str.charAt(i) == '+') {
if (s.peek() == 1)
res[index++] = '-';
// If top is 0, append the same operator
if (s.peek() == 0)
res[index++] = '+';
} else if (str.charAt(i) == '-') {
if (s.peek() == 1)
res[index++] = '+';
else if (s.peek() == 0)
res[index++] = '-';
} else if (str.charAt(i) == '(' && i > 0) {
if (str.charAt(i - 1) == '-') {
// x is opposite to the top of stack
int x = (s.peek() == 1) ? 0 : 1;
s.push(x);
}
else if (str.charAt(i - 1) == '+')
s.push(s.peek());
}
else if (str.charAt(i) == ')')
s.pop();
else
res[index++] = str.charAt(i);
i++;
}
return new String(res);
}
I have a vector of vectors filled with characters from a text file. It is essentially a simple outbreak simulator, with 'i' characters being infected, and 's' characters being susceptible to infection. The point is to run through the matrix and if it comes across an 'i', it then changes all 's' around it into an 'i'. I run into a problem when checking the elements around it due to checking positions out of the bounds on the edges of the matrix. Is there a way to check these bounds in my if statements?
Here is the code:
for (int i = 0; i < population.size(); i++) {
for(int j = 0; j < population[i].size(); j++) {
if(population[i][j] == 'i') {
if(population[i-1][j] == 's') {
population[i-1][j] = 'i';
}
if(population[i-1][j+1] == 's') {
population[i-1][j+1] = 'i';
}
if(population[i][j+1] == 's') {
population[i][j+1] = 'i';
}
if(population[i+1][j+1] == 's') {
population[i+1][j+1] = 'i';
}
if(population[i+1][j] == 's') {
population[i+1][j] = 'i';
}
if(population[i+1][j-1] == 's') {
population[i+1][j-1] = 'i';
}
if(population[i][j-1] == 's') {
population[i][j-1] = 'i';
}
}
}
}
Instead of directly referencing a particular array entry, you could do something like the following:
void checkForInfectionAndInfectIfNeeded(int i, int j) {
for (int row = -1; row <= 1; row++) {
for (int column = -1; column <=1; column++) {
infect(i + row, j + column);
}
}
}
void infect(int i, int j) {
if (i < 0 || i >= population.size() || j < 0 || j >= population[j].size()) {
return;
} else {
population[i][j] = 'i';
}
}
This way, the infect method is the only that checks the boundaries, and you replace your long list of manually checking the surrounding locations with two loops.
I'm trying to #2 of the Canadian Computing Contest, but my solution doesn't work. It only reads the first few characters(the first three I believe) and just ends the loop, then proceeding to provide the adequate output based only on the first three characters.
Here is the past paper:http://cemc.uwaterloo.ca/contests/computing/2015/stage%201/juniorEn.pdf
My code
Scanner input = new Scanner(System.in);
String lines = input.next();
char[] line = lines.toCharArray();
int happy = 0;
int sad = 0;
int i = 0;
while(i < line.length)
{
if(line[i] == ':' && line[i+1] == '-')
{
if(line[i+2] == ')')
happy++;
else if(line[i+2] == '(')
sad++;
i+=3;
}
else i++;
}
if(happy == 0 && sad == 0)
System.out.print("none");
else if(happy == sad)
System.out.print("unsure");
else if(happy>sad)
System.out.print("happy");
else if (sad>happy)
System.out.print("sad");
consider that with
while(i < line.length)
if i == line.length - 1
then if you do
line[i+1]
you will exceeed the length or your array and get an OutOfBoundsException
I am working on Conway game of college problem. I have been able to print the first generation and the second but when it comes to the following ones they all copy the second generation. I was wondering if y'all can help me out.
public void computeNextGeneration(int generation)
{
char[][] newBoard = new char[board.length][board[0].length];
for(int i = 0; i < board.length; i++)
{
for(int j = 0; j < board[0].length; j++)
{
if(board[i][j] == '0' && numOfNeighbors(i,j) == 3)
{
newBoard[i][j] = 'X';
}
else if(board[i][j] == 'X' && numOfNeighbors(i,j) < 2)
{
newBoard[i][j] = '0';
}
else if(board[i][j] == 'X' && numOfNeighbors(i,j) >3)
{
newBoard[i][j] = '0';
}
else if(board[i][j] == 'X' && numOfNeighbors(i,j) == 2 || numOfNeighbors(i,j) == 3)
{
newBoard[i][j] = 'X'; //change x to 0
}
else{
newBoard[i][j] +=board[i][j];
}
}
}
for (int i = 0; i < newBoard.length; i++)
{
for(int j = 0; j < newBoard[0].length; j++)
{
System.out.print(newBoard[i][j]);
}
System.out.println();
}
}
After you calculate the new board you have to assign it back to the class field board. Add as the last line of computeNextGeneration board = newboard.
You start counting your generations from 2 for(int i = 2; i <= gen; i++) as the constructor doesnt generate a starting generation this should be a 0.
I am a beginner here to Java. So I tried to run this code here, but it kept giving me this error:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 4.
I need some help. Here is my code:
import java.util.Scanner;
public class TestFour
{
public static void main(String[]args)
{
String inp= new String();
Scanner scan = new Scanner(System.in);
System.out.println("Enter Word ");
inp = scan.nextLine();
int output = 1;
int [] board = new int[40];
int points = 0;
int totalpoints = 0;
int input;
//start of for loop
for(int i = 0; i < 5; i++)
{
input = scan.nextInt();
for (int j = 0; j < inp.length(); j++)
{
//values of letters
if(inp.charAt(i) == 'a' || inp.charAt(i) == 'e')
{
points = 1;
}
else if(inp.charAt(i) == 'd' || inp.charAt(i) == 'r')
{
points = 2;
}
else if(inp.charAt(i) == 'b' || inp.charAt(i) == 'm')
{
points = 3;
}
else if(inp.charAt(i) == 'v' || inp.charAt(i) == 'y')
{
points = 4;
}
else if(inp.charAt(i) == 'j' || inp.charAt(i) == 'x')
{
points = 8;
}
else
{
points = points;
}
//checking if double letter or triple letter and executing program
if ( input % 3 == 0 && input % 6 != 0)
{
points = points * 2;
}
else
{
points = points;
}
if (input % 5 == 0 && input != 15)
{
points = points * 3;
}
else
{
points = points;
}
totalpoints = totalpoints + points;
input = input + 1;
}//end of for loop
input = input - 4;
//checking if double word or triple word and executing program
for (int k = 0; k < inp.length(); k++)
{
if (input % 7 == 0 && input != 21 && input != 25)
{
totalpoints = totalpoints * 2;
}
else
{
totalpoints = totalpoints;
}
if (input % 8 == 0 && input != 40)
{
totalpoints = totalpoints * 3;
}
else
{
totalpoints = totalpoints;
}
input = input + 1;
}
}
System.out.println(totalpoints);
}
}
The problem starts at the for loop the fifth time I enter the input. Thank you for your time. I really don't get how to fix it even though I know what is going on.
You are using the wrong iteration counter, replace inp.charAt(i) with inp.charAt(j).