How do I optimize the Hourglass program from Hackerrank? [closed] - java

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 5 years ago.
Improve this question
This is the hourglass problem which can be found on Hackerrank website.
Here is a link to the problem : Hourglass
Here is the code that I wrote for the Hourglass problem :
public class Solution
{
public static int hourglass(int[][] a, int n)
{
int max = -999;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
int sum = 0;
boolean flag = false;
if ((i+2) < n && (j+2) < n)
{
sum += a[i][j] + a[i][j+1] + a[i][j+2] + a[i+1][j+1] + a[i+2][j] + a[i+2][j+1] + a[i+2][j+2];
flag = true;
}
if (sum > max && flag == true)
max = sum;
}
}
return max;
}
public static void main(String[] args)
{
Scanner scanner = new Scanner(System.in);
int n = 6;
int[][] a = new int[6][6];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
a[i][j] = scanner.nextInt();
int maxSum = hourglass(a, n);
System.out.println(maxSum);
}
}
My Question
Now, the above code compiled and ran successfully and even passed all the test cases. However, my code takes O(n^2) time (here the size of the matrix is 6, but if the size were n, then it would take O(n^2) time to finish.)
It takes O(n^2) time to create the array, and that I am not concerned about. What I am interested is to optimise the hourglass() method where it takes O(n^2) time to calculate the sum of the hourglass.
So, is there any way to implement the above problem with further optimisation?
Is it possible to solve the problem in O(n) time?
In fact, I tried to solve the problem in O(n) time by removing the inner loop in the hourglass() method but it did not seem to work.
P.S. I do not need a working code, all I need is some pointers to possible improvements (if any) or an algorithm at the most.
Thanks in advance!

Technically, you're solution is already O(n). You're defining "n" as though it were one side of the 2d array, but if you regarded n as a unique placement on your board, n is a combination of row * col. Redefined this way, you can't beat O(n) on this problem.
You can, however, optimize some. You're essentially laying a 3x3 tile onto a 6x6 board. If a placement were to be defined by the top left corner of your 3x3 tile, then you're trying all 36 placements. If you think about it, many of those placements would leave your tile hanging off the edge of the board. You really only need to consider the first 4x4 positions rather than all 6x6 positions. It's still an O(n) solution, but it would cut 36 iterations down to 16.

Related

Naive matrix multiplication improvement

My CS teacher asked us to "add a small change" to this code to make it run with time complexity of N3 - N2 instead of the normal N3. I cannot for the life of me figure it out and I was wondering if anyone happened to know. I don't think he is talking about strassens method.
from when I looked at it, maybe it could take advantage of the fact that he only cares about a square (diagonal) matrix.
void multiply(int n, int A[][], int B[][], int C[][]) {
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
C[i][j] = 0;
for (int k = 0; k < n; k++)
{
C[i][j] += A[i][k]*B[k][j];
}
}
}
}
You cannot achieve Matrix multiplication in O(N2). However, you can improve the complexity from O(N3). In linear algebra, there are algorithms like the Strassen algorithm which reduces the time complexity to O(N2.8074) by reducing the number of multiplications required for each 2x2 sub-matrix from 8 to 7.
An improved version of the Coppersmith–Winograd algorithm is the fastest known matrix multiplication algorithm with the best time complexity of O(N2.3729).

rolling dice using arrays [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 9 years ago.
Improve this question
simple beginner Java question. I just learned how to use arrays and it's still a little confusing to me. My goal is to simply roll a number of dice a number of times and then project it as a sum, frequency, and percentage. I'm sure I'm doing something dumb, but I'm overlooking it!
import javax.swing.JOptionPane;
import java.util.Random;
public class Lab1 {
private static int N = 0;
private static int M = 0;
private static int total = 0;
private static Random rnd = new Random();
public Lab1(){
}
public static void main(String[] args) {
N = Integer.parseInt(JOptionPane.showInputDialog("How many dice would you like to roll?"));
System.out.println("Dice: "+N);
M = Integer.parseInt(JOptionPane.showInputDialog("How many times would you like to roll?"));
System.out.println("Rolls: "+M);
int total[] = new int[(6*Lab1.N)+1];
for (int i=0; i<=total.length; i++)
total[i] = 0;
for (int roll=1; roll<=M; roll++){
N = 1+rnd.nextInt(6);
total[N]++;
}
System.out.printf("%3s%12s%12s\n", "Sum","Frequency", "Percentage " );
for(int k=2; k<total.length; k++);{
int percent = total[k]/(360);
System.out.printf("%3s%12s%12s\n", k, total[k], percent);
}
}
}
From what I can see the question is how can you store the previous roles of the dice. And I believe your problem is with this method:
for (int roll=1; roll<=M; roll++){
N = 1+rnd.nextInt(6);
total[N]++;
}
I would change this to
for (int roll=1; roll<=M; roll++){
total[roll] = rnd.nextInt(6);
}
This will build up an array storing each dice roll - if that is of course what you are looking for...
Two things.
First, this loop will inevitably throw ArrayIndexOutOfBoundsException ("element" total[total.length] is out of bounds)
for (int i=0; i<=total.length; i++)
total[i] = 0;
You should use < instead of <=.
for (int i=0; i<total.length; i++)
total[i] = 0;
Second, this line here:
for(int k=2; k<total.length; k++);{
You have an empty loop here. You should remove the semicolon before the {:
for(int k=2; k<total.length; k++){
Now your code compiles, doesn't throw exceptions on the start, and prints a pretty table.
That's a start.
for(int k=2; k<total.length; k++);{
You need to remove the ; symbol from your loop as 'k' will not be resolved in the loop as you have terminated it. The format is for(x, x, x) {
The next thing to look at now is:
Dice: 1
Rolls: 1
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 7
at Lab1.main(Lab1.java:26)
Hint:
total[i] = 0; // this line is the problem.
Look at your <= in the loop.
for (int i=0; i<total.length; i++)
Simply chaging it to < results in this:
Dice: 1
Rolls: 1
Sum Frequency Percentage
2 1 0
3 0 0
4 0 0
5 0 0
6 0 0

Efficient way of generating all combinations of 12 numbers that add to 100 in Java [duplicate]

This question already has an answer here:
How to iterate through array combinations with constant sum efficiently?
(1 answer)
Closed 9 years ago.
I have 12 products at a blend plant (call them a - l) and need to generate varying percentages of them, the total obviously adding up to 100%.
Something simple such as the code below will work, however it is highly inefficient. Is there a more efficient algorithm?
*Edit: As mentioned below there are just too many possibilities compute, efficiently or not. I will change this to only having a maximum of 5 or the 12 products in a blend and then running it against the number of ways that 5 products can be chosen from the 12 products.
There is Python code that some of you have pointed to that seems to work out the possibilities from the combinations. However my Python is minimal (ie 0%), would one of you be able to explain this in Java terms? I can get the combinations in Java (http://www.cs.colostate.edu/~cs161/Fall12/lecture-codes/Subsets.java)
public class Main {
public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
for(int a=0;a<=100;a++){
for(int b=0;b<=100;b++){
for(int c=0;c<=100;c++){
for(int d=0;d<=100;d++){
for(int e=0;e<=100;e++){
for(int f=0;f<=100;f++){
for(int g=0;g<=100;g++){
for(int h=0;h<=100;h++){
for(int i=0;i<=100;i++){
for(int j=0;j<=100;j++){
for(int k=0;k<=100;k++){
for(int l=0;l<=100;l++){
if(a+b+c+d+e+f+g+h+i+j+k+l==100)
{
System.out.println(a+" "+b+" "+c+" "+d+" "+e+" "+f+" "+g+" "+h+" "+i+" "+j+" "+k+" "+l);
}}}}}}}}}}}}}
}
}
Why make it so difficult. Think simple way.
To explain the scenario simpler, consider 5 numbers to be generated randomly. Pseudo-code should be something like below.
Generate 5 random number, R1, R2 ... R5
total = sum of those 5 random number.
For all item to produce
produce1 = R1/total; // produce[i] = R[i]/total;
Please, don't use nested for loops that deep! Use recursion instead:
public static void main(String[] args) {
int N = 12;
int goal = 100;
generate(N, 0, goal, new int[N]);
}
public static void generate(int i, int sum, int goal, int[] result) {
if (i == 1) {
// one number to go, so make it fit
result[0] = goal - sum;
System.out.println(Arrays.toString(result));
} else {
// try all possible values for this step
for (int j = 0; j < goal - sum; j++) {
// set next number of the result
result[i-1] = j;
// go to next step
generate(i-1, sum + j , goal, result);
}
}
}
Note that I only tested this for N = 3 and goal = 5. It absolutely makes no sense to try generating all these possibilities (and would take forever to compute).
Let's take your comment that you can only have 5 elements in a combination, and the other 7 are 0%. Try this:
for (i = 0; i < (1<<12); ++i) {
if (count_number_of_1s(i) != 5) { continue; }
for (j = 0; j < 100000000; ++j) {
int [] perc = new int[12];
int val = j;
int sum = 0;
int cnt = 0;
for (k = 0; k < 12; ++k) {
if (i & (1 << k)) {
cnt++;
if (cnt == 5) {
perc[k] = 100 - sum;
}
else {
perc[k] = val % 100;
val /= 100;
}
sum += perc[k];
if (sum > 100) { break; }
}
else { perc[k] = 0; }
}
if (sum == 100) {
System.out.println(perc[0] + ...);
}
}
}
The outer loop iterates over all possible combinations of using 12 items. You can do this by looping over all numbers from 1:2^12, and the 1s in the binary representation of that number are the elements you're using. The count_number_of_1s is a function that loops over all the bits in the parameter and returns the number of 1s. If this is not 5, then just skip this iteration because you said you only want at most 5 mixed. (There are 792 such cases).
The j loop is looping over all the combinations of 4 (not 5) items from 0:100. There are 100^4 such cases.
The inner loop is looping over all 12 variables, and for those that have a 1 in their bit-position in i, then it means you're using that one. You compute the percentage by taking the next two decimal digits from j. For the 5th item (cnt==5), you don't take digits, you compute it by subtracting from 100.
This will take a LONG time (minutes), but it won't be nearly as bad as 12 nested loops.
for(int a=0;a<=100;a++){
for(int b=0;b<=50;b++){
for(int c=0;c<=34;c++){
for(int d=0;d<=25;d++){
for(int e=0;e<=20;e++){
for(int f=0;f<=17;f++){
for(int g=0;g<=15;g++){
for(int h=0;h<=13;h++){
for(int i=0;i<=12;i++){
for(int j=0;j<=10;j++){
for(int k=0;k<=10;k++){
for(int l=0;l<=9;l++){
if(a+b+c+d+e+f+g+h+i+j+k+l==100)
{
// run 12 for loops for arranging the
// 12 obtained numbers at all 12 places
}}}}}}}}}}}}}
In Original approach(permutation based), the iterations were 102^12 = 1.268e24. Even though the 102th iteration was false, it did check the loop terminating condition for 102th time.
So you had 102^12 condition checks in "for" loops, in addition to "if" condition checks 101^12 times, so in total, 2.4e24 condition checks.
In my solution(combination based),No of for loop checks reduces to 6.243e15 for outer 12 loops, &
if condition checks = 6.243e15.
Now, the no of for loops(ie inner 12 for loops) for every true "if" condition, is 12^12 = 8.9e12.
Let there be x number of true if conditions. so total condition checks
=no of inner for loops*x
= 8.9e12 * x + 6.243e15
I'm not able to find the value of x. however, I believe it wouldnt be large enough to make total conditon checks greater than 2.4e24

Chutes and Ladders Game Random Placement Issue

I'm a student, working on a Chutes and Ladders game. I'm using methods to determine how many chutes and ladders should be placed on the game board. I'm specifying 10 for each in main using parameters but I keep getting anywhere from 6 to 11 placed across the board.
Is there something going on with the two methods interfering with each other?
Or is there a problem with the way I set up the for loops for random placement?
I'm new to this site, please let me know if you need more clarification, I didn't want to place the whole program in here. Thanks.
//main
ChutesAndLadders cl = new ChutesAndLadders();
cl.setBoard(new String[100]);
cl.makeChutes(10);
cl.makeLadders(10);
//methods
public String [] board;
private int chutes, ladders;
public int position;
public Random rand = new Random();
//set board
public void setBoard(String [] n){
board = n;
for(int i = 0; i < board.length; i++)
board[i] = " ";
}
//set and place chutes
public void makeChutes(int n){
chutes = n;
for(int i = 0; i <= chutes; i++)
board[rand.nextInt(board.length)] = "C" + chutes;
}
//set and place ladders
public void makeLadders(int n){
ladders = n;
int lcell = 0;
for(int i = 0; i <= ladders; i++)
board[rand.nextInt(board.length)] = "L" + ladders;
Firstly, you wrote:
for(int i = 0; i <= chutes; i++)
board[rand.nextInt(board.length)] = "C" + chutes;
The assignment statement in the loop will run chutes+1 times. (Eleven times in your case.) [Use i < chutes instead.] This is the same in your ladders code. This explains why you might have up to 11 chutes or ladders when the code is done running.
Secondly, you do not take care to prevent the same space being assigned a chute or ladder multiple times. rand.nextInt(board.length) is not guaranteed to generate unique values each time it is run (otherwise it wouldn't really be random.) This explains why you may not see as many as 11 chutes and ladders when the code is done running.
To make this clearer, put a constant value in there:
for(int i = 0; i < chutes; i++)
board[11] = "C" + chutes;
and notice that you end up with one chute (at space eleven)--unless the ladder code overwrites it with a ladder.
Hope that helps.
Good luck!
At first glance my guess is that you are winding up with overlapping entries. Because you generate a random placement and don't check to see if there is already a chute or ladder there, you are likely winding up with overlaps.
It should be fairly straightforward to generate the random position and then check if there is something there prior to placement. If a collision is found, just generate another random and repeat until you can place it.
Also, as an aside, it is always a good practice to avoid for loops and if statements without curly braces. It is very easy to add a second like to the block and wonder why it is not executing as part of the block.
Your for loops have an inclusive upper limit check, 0 .. 10 yields 11 entries.
Like Mike said, the lower number of results are due to collisions, you can prevent those by setting up the board by filling it with the elements needed and then shuffling the board to get the end result, something like:
public void setupBoard(String [] n, int nrLadders, int nrChutes){
board = n;
int index = 0;
while (index < board.length && 0 < nrLadders--) {
board[index++] = "L" + nrLadders;
}
while (index < board.length && 0 < nrChutes--) {
board[index++] = "C" + nrChutes;
}
while (index < board.length) {
board[index++] = " ";
}
board = Collections.shuffle(Arrays.asList(board)).toArray(new String[board.length]);
}
This is like creating a deck of cards containing a number of ladder cards, a number of chute cards, a larger number of empty spot cards and shuffling that deck to get the game board.

Total number of ways to count the possible combination for coin [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to count possible combination for coin problem
In this case suppose the amount is 15 and coins are 1, 6, 7 then total number of ways to it is 6. Below code works fine but its not that much efficient. Any suggestions will be appreciated.
public class CoinProblem {
public static void main(String[] args) {
int amount = 15;
int coinTypes[] = {1,6,7};
int combinations = 0;
for (int i = 0; i * 7 <=15; i++) {
for (int j = 0; j * 6 + i * 7 <= 15; j++) {
combinations++;
}
}
System.out.println(combinations);
}
}
If you are looking for a dynamic programming solution (that can work if you have a larger number of coins and a larger total sum), one idea that I have is:
int[] ways = new int[amount+1];
ways[0] = 1; //There is only one way to have 0 money, no coins
for (int coin : coinTypes)
{
for (int i = 1; i <= amount; i++)
{
ways[i] += ways[i-coin];
}
}
Standard disclaimer, I did not run this code. It may have bugs, but it does look like it will work. It has at least two: 1. You need to initialize the ways array to 0. 2. You need to guard against array underflows (taking array indexes less than 0).
The way that it works is that you store how many ways you can get every total count using only one type of coin, then two types of coin, and finally all three. For each amount y, you know that you can achieve that amount with a coin of value x by looking all the ways that you can get a value of y-x and then adding a coin of value x.

Categories