HackerRank - Picking Numbers - java

I'm new to programming and it's my first ever question here.
I've been trying to solve this challenge https://www.hackerrank.com/challenges/picking-numbers/problem?isFullScreen=true for three consecutive days but still got 3/10 test cases failed.
Here the algorithm I use:
For each element in the main array create a subarray where all elements are equal or no more or less by 1
Resulting number of subarrays (which equals to the number of elements in the first array) are checked for validity meaning that each element is equal or no more or less by 1
Find the longest valid subarray and return it's size
Here is the code for the solution:
import java.io.*;
import java.util.*;
import java.util.stream.Stream;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
class Result {
/*
* Complete the 'pickingNumbers' function below.
*
* The function is expected to return an INTEGER.
* The function accepts INTEGER_ARRAY a as parameter.
*/
public static int pickingNumbers(List<Integer> a) {
int maxLength = 0;
boolean isValidArray = false;
List<Integer> subarray = new ArrayList<Integer>();
for (int i = 0; i < a.size(); i++) {
subarray = findValidSubarray(a, a.get(i));
isValidArray = arrayValidityCheck(subarray);
if ((isValidArray) && (subarray.size() > maxLength)) {
maxLength = subarray.size();
}
}
return maxLength;
}
private static List<Integer> findValidSubarray(List<Integer> array, Integer integer) {
List<Integer> subarray = new ArrayList<Integer>();
for (int elem : array) {
if ((elem == integer) || (elem + 1 == integer) || (elem == integer + 1)) {
subarray.add(elem);
}
}
return subarray;
}
//check that all elements are equal or not more or less than 1 to each other
private static boolean arrayValidityCheck(List<Integer> subarray) {
boolean isValid = false;
for (int i = 0; i < subarray.size(); i++) {
for (int j = 0; j < subarray.size(); j++) {
if ((subarray.get(i) == subarray.get(j)) || (subarray.get(i) + 1 == subarray.get(j)) || (subarray.get(i) == subarray.get(j) + 1)) {
isValid = true;
} else {
isValid = false;
break;
}
}
if (!isValid) {
break;
}
}
return isValid;
}
}
public class Solution {
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
String[] firstMultipleInput = bufferedReader.readLine().replaceAll("\\s+$", "").split(" ");
int n = Integer.parseInt(firstMultipleInput[0]);
List<Integer> a = Stream.of(bufferedReader.readLine().replaceAll("\\s+$", "").split(" "))
.map(Integer::parseInt)
.collect(toList());
bufferedReader.close();
int result = Result.pickingNumbers(a);
System.out.println(result);
}
}
Sample test case data which is failing:
100
and
14 18 17 10 9 20 4 13 19 19 8 15 15 17 6 5 15 12 18 2 18 7 20 8 2 8 11
2 16 2 12 9 3 6 9 9 13 7 4 6 19 7 2 4 3 4 14 3 4 9 17 9 4 20 10 16 12
1 16 4 15 15 9 13 6 3 8 4 7 14 16 18 20 11 20 14 20 12 15 4 5 10 10 20
11 18 5 20 13 4 18 1 14 3 20 19 14 2 5 13
Valid answer:
15
My answer:
13
I'm out of ideas where the bug is here.
Could you please help me?
PS: I'm aware that this algorithm is not optimal. Any optimization tips would be much appreciated.

Edit: As pointed out in the comments it is sufficient to do one type of check and only check if the other elements are 1 larger than the first element in the check. Answer modified accordingly
Your problem is that when you build your subarray, you allow numbers in it that are both 1 higher and 1 lower than the first element you start with.
You then later try to clean up your results by re-validating your generated arrays, but this will not fix the problem that you will not generate any all possible valid subarrays with your method.
My proposal to fix your code would be:
Modify your findValidSubarray method so that only allows elements that are 1 higher in it. (The cases where lower numbers would be allowed in will be handled in other iteration when that lower number is the starting element for the iteration)
remove the arrayValidityCheck as this one will no longer be needed as the above will directly only produce valid subarrays.
Modified findValidSubarray method:
private static List<Integer> findValidSubarray(final List<Integer> array, final Integer integer) {
final List<Integer> subarray = new ArrayList<Integer>();
for (final int elem : array) {
if ((elem == integer) || (elem + 1 == integer)) {
subarray.add(elem);
}
}
return subarray;
}
Calling that method:
public static int pickingNumbers(final List<Integer> a) {
int maxLength = 0;
List<Integer> subarray = new ArrayList<Integer>();
for (int i = 0; i < a.size(); i++) {
subarray = findValidSubarray(a, a.get(i));
if ((subarray.size() > maxLength)) {
maxLength = subarray.size();
}
}
return maxLength;
}

Related

Why is this code printing a negative number?

public class Program {
public static void main(String[] args) {
int x = 1;
for (int i = 1; i < 31; i++) {
x = x + 2 * x;
}
System.out.println(x);
}
}
It prints -1010140999 and I don't know why it is negative number.
Final output is a very long number which will exceed the max integer capaxity. Hence we need to use long data type. Please check the correct code below with x value at each iteration
public class Program {
public static void main(String[] args) {
long x = 1;
for (int i = 1; i < 31; i++) {
x = x + 2l * x;
System.out.println(i+ " " +x);
}
}
}
Output
1 3
2 9
3 27
4 81
5 243
6 729
7 2187
8 6561
9 19683
10 59049
11 177147
12 531441
13 1594323
14 4782969
15 14348907
16 43046721
17 129140163
18 387420489
19 1162261467
20 3486784401
21 10460353203
22 31381059609
23 94143178827
24 282429536481
25 847288609443
26 2541865828329
27 7625597484987
28 22876792454961
29 68630377364883
30 205891132094649
An integer in Java is stored with 32 bits, of which one is used to indicate whether the value is positive or negative. This means an int's value is between -2^31 and 2ˆ31 - 1.
Once you add or subtract past those limits, you wrap around in the corresponding direction since an overflow/underflow occurs.
public class OverflowExample {
public static void main(String args[]) {
int largest_int = Integer.MAX_VALUE;
int smallest_int = Integer.MIN_VALUE;
System.out.println(largest_int); // 2ˆ31 - 1 = 2147483647
System.out.println(largest_int + 1); // -2147483648
System.out.println(smallest_int); // -2^31, same as above
}
}

pyramid printing using Java

Pyramid example
Note:
System.our.printf(“%n.mf”, num) will print out a float number num with width n and m decimal places.
Calculation of a^b in Java: Math.pow(a,b)
For the above pyramid printing, you may break the pattern into three parts: spaces on the left, numbers on the left and numbers on the right. For each line i, there are total 2*i-1 numbers.
public static void main(String[] args) {
int rows = 5, k = 0, count = 0, count1 = 0;
for(int i = 1; i <= rows; ++i) {
for(int space = 1; space <= rows - i; ++space) {
System.out.print(" ");
++count;
}
while(k != 2 * i - 1) {
if (count <= rows - 1) {
System.out.print((i + k) + " ");
++count;
}
else {
++count1;
System.out.print((i + k - 2 * count1) + " ");
}
++k;
}
count1 = count = k = 0;
System.out.println();
}
}
}
I decided to give this a try, mainly because I wanted to present some concepts having to do with problem-solving.
First, I made the height of the pyramid a variable. This forced me to consider how different pyramid heights would affect the width of each segment of each line.
Next, I decided to pre-calculate the powers of two. There's no point in recalculating the values for each line. So, I wrote a method to return a precalculated array of integers.
Next, I calculated how much space the largest power of two would take up. I formatted the number using the NumberFormat class. The NumberFormat class will format the number according to the Locale in which you're running the code. I used the format method of the String class to give each number enough space.
Next, I divided each line into a blank area, a number area, and a blank area. That way, I could work on each part of a line separately. The blank area on the left side of the pyramid line is the same length as the blank area on the right side of the line, so I only had to create it one time for each line.
I used a StringBuilder to create each line of the pyramid. It's faster to use a StringBuilder than to concatenate String values. I used StringBuilder segments to create the parts of a pyramid line.
I didn't use static methods because I wanted to show how you instantiate the class in the main method. In general, I try to avoid the use of static methods.
Here's the result of one test run. I assure you, I ran several dozen tests on this code.
1
1 2 1
1 2 4 2 1
1 2 4 8 4 2 1
1 2 4 8 16 8 4 2 1
1 2 4 8 16 32 16 8 4 2 1
1 2 4 8 16 32 64 32 16 8 4 2 1
1 2 4 8 16 32 64 128 64 32 16 8 4 2 1
1 2 4 8 16 32 64 128 256 128 64 32 16 8 4 2 1
1 2 4 8 16 32 64 128 256 512 256 128 64 32 16 8 4 2 1
Here's the code.
import java.text.NumberFormat;
public class NumberPyramid {
public static void main(String[] args) {
int power = 10;
NumberPyramid np = new NumberPyramid();
np.createPyramid(power);
}
private static final NumberFormat NF =
NumberFormat.getNumberInstance();
public void createPyramid(int power) {
int[] values = createPowersArray(power);
String maximum = NF.format(values[power - 1]);
int segmentSize = maximum.length() + 2;
String format = "%" + segmentSize + "s";
for (int index = 0; index < power; index++) {
StringBuilder builder = new StringBuilder();
StringBuilder blankArea = createBlankArea(
index, power, segmentSize);
builder.append(blankArea);
builder.append(createNumberArea(index, values, format));
builder.append(blankArea);
System.out.println(builder.toString());
}
}
private int[] createPowersArray(int power) {
int[] values = new int[power];
values[0] = 1;
for (int i = 1; i < power; i++) {
values[i] = values[i - 1] * 2;
}
return values;
}
private StringBuilder createNumberArea(int index,
int[] values, String format) {
StringBuilder builder = new StringBuilder();
for (int j = 0; j <= index; j++) {
builder.append(String.format(format,
NF.format(values[j])));
}
for (int j = index - 1; j >= 0; j--) {
builder.append(String.format(format,
NF.format(values[j])));
}
return builder;
}
private StringBuilder createBlankArea(int index,
int power, int segmentSize) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < power - index - 1; i++) {
builder.append(createBlankSegment(segmentSize));
}
return builder;
}
private StringBuilder createBlankSegment(int length) {
StringBuilder builder = new StringBuilder(length);
for (int i = 0; i < length; i++) {
builder.append(" ");
}
return builder;
}
}
find the answer below:
public class Main {
static int rows = 10;
public static void main(String[] args) {
LinkedList<Integer> numbers = new LinkedList<>();
for(int i = 1 ; i <= rows ; i++){
if(i ==1 ) numbers.add(1);
else {
int totalNumber = i * 2 -1;
insertNumbers(totalNumber, numbers);
}
printNumbers(numbers, i);
System.out.println();
numbers.clear();
}
}
private static void insertNumbers(int totalNumber, LinkedList<Integer> numbers) {
int numbersOnEachSide = (totalNumber - 1) / 2;
for (int i = 0; i < numbersOnEachSide ; i++ ) numbers.add((int) Math.pow(2, i));
numbers.add((int) Math.pow(2,numbersOnEachSide));
for(int i = 0 ; i < numbersOnEachSide ; i++) numbers.add((int) Math.pow(2, numbersOnEachSide-1-i));
}
private static void printNumbers(LinkedList<Integer> numbers, int i) {
int spaceNorows = rows - i;
printSpaces(spaceNorows);
for (Integer number : numbers) {
System.out.print(number + "\t");
}
printSpaces(spaceNorows);
}
private static void printSpaces(int spaceNorows) {
for(int j = 0 ; j< spaceNorows ; j++) System.out.print("\t");
}
}
output:
1
1 2 1
1 2 4 2 1
1 2 4 8 4 2 1
1 2 4 8 16 8 4 2 1
1 2 4 8 16 32 16 8 4 2 1
1 2 4 8 16 32 64 32 16 8 4 2 1
1 2 4 8 16 32 64 128 64 32 16 8 4 2 1
1 2 4 8 16 32 64 128 256 128 64 32 16 8 4 2 1
1 2 4 8 16 32 64 128 256 512 256 128 64 32 16 8 4 2 1
p.s please take a look at https://stackoverflow.com/tour to ask a proper question in later posts.
EDIT : How to run the code in CMD
To run the application above:
1- save all the code above in a file named - for example - Main.java
2- run CMD in windows or terminal in linux and compile the Main.java using javac Main.java.
3- The compiled file will be put in the same directory as the java file.
4- run the compiled class using java Main.
change Main to whatever name you give to the file
Since you are running the code in the cmd it might not display the 10 row pyramid properly(due to screen resolution, size, etc). So,
change the row field in static int rows = 10; to 5 to see the
pyramid properly.
You can further changing the fixed row number to dynamically get it from user.

Is there something wrong with my id array?

This program pulls two columns from the input.txt file where the first column indicates the value of the object, and the second column represents the weight. The values are imported and placed into two arrays: the value array and the weight array. The knapsack calculations are then made. There are 23 objects in total represented by the rows of the arrays. My code correctly calculates the total value that is being held in the knapsack, and will print out the correct IDs if the weight capacity entered is 5, but for any other weight the IDs being held in the id array are not correct, but the total value printed out is. Here is my code for both files, and if anyone is able to figure out how to correctly save and print the IDs being held in the knapsack please let me know . . .
input.txt file:
17 5
12 8
15 22
17 11
33 21
43 15
15 4
44 35
23 19
10 23
55 39
8 6
21 9
20 28
20 13
45 29
18 16
21 19
68 55
10 16
33 54
3 1
5 9
knapsack.java file:
//We did borrow concepts from:
//http://www.sanfoundry.com/java-program-solve-knapsack-problem-using-dp/
import java.util.Scanner;
import java.util.*;
import java.lang.*;
import java.io.*;
public class knapsack
{
static int max(int a, int b)
{
if(a > b)
{
//System.out.println(a);
return a;
}
else
//System.out.println(b);
return b;
}
static int knapSack(int maxCapacity, int weight[], int value[], int n)
{
int track = 0;
int i, w;
int foo1 = 0;
int foo2 = 0;
K = new int[n+1][maxCapacity+1];
// Build table K[][] in bottom up manner
for (i = 0; i <= n; i++)
{
for (w = 0; w <= maxCapacity; w++)
{
if (i==0 || w==0)
K[i][w] = 0;
else if (weight[i-1] <= w)
{
//K[i][w] = max(value[i-1] + K[i-1][w-weight[i-1]], K[i-1][w]);
if(value[i-1] + K[i-1][w-weight[i-1]] > K[i-1][w])
{
K[i][w] = value[i-1] + K[i-1][w-weight[i-1]];
//System.out.println("A: "+i);
}
else
{
K[i][w] = K[i-1][w];
id[track++] = i;
//System.out.println("B: "+i);
}
}
else
{
K[i][w] = K[i-1][w];
}
}
//System.out.println(K[foo1][foo2]);
}
return K[n][maxCapacity];
}
public static void main(String args[])throws java.io.FileNotFoundException
{
Scanner sc = new Scanner(System.in);
int n = 23;
File file = new File("input.txt");
Scanner scanner = new Scanner(file);
id = new Integer [n];
//knapval = new int[n];
//knapweight = new int [n];
int []value = new int[n];
int []weight = new int[n];
for(int i=0; i<n; i++)
{
value[i] = scanner.nextInt();
weight[i] = scanner.nextInt();
}
System.out.println("Enter the maximum capacity: ");
int maxCapacity = sc.nextInt();
System.out.println("The maximum value that can be put in a knapsack with a weight capacity of "+maxCapacity+" is: " + knapSack(maxCapacity, weight, value, n));
System.out.println();
System.out.println("IDs Of Objects Held In Knapsack: ");
//System.out.println();
for(int z = 0; z < n && id[z] != null; z++)
{
System.out.println(id[z]);
}
if(id[0] == null)
System.out.println("All objects are too heavy, knapsack is empty.");
sc.close();
scanner.close();
}
protected static Integer [] id;
protected static int [][]K;
}
Your way of recording your solution in the id array is flawed. At the time you do id[track++] = i;, you don’t yet know whether i will be in your final solution. Because of the nested loops you may even add i more than once. This in turn may lead to overflowing the array with a java.lang.ArrayIndexOutOfBoundsException: 23 (this happens for max capacity 12 and above).
I suggest instead of using id, after your solution is complete you track your way backward through the K array (by Java naming conventions, it should be a small k). It holds all the information you need to find out which objects were included in the maximum value.
private static void printKnapsack(int maxCapacity, int weight[], int value[], int n) {
if (K[n][maxCapacity] == 0) {
System.out.println("No objects in knapsack");
} else {
int w = maxCapacity;
for (int i = n; i > 0; i--) {
if (K[i][w] > K[i - 1][w]) { // increased value from object i - 1
System.out.format("ID %2d value %2d weight %2d%n", i, value[i - 1], weight[i - 1]);
// check that value in K agrees with value[i - 1]
assert K[i - 1][w - weight[i - 1]] + value[i - 1] == K[i][w];
w -= weight[i - 1];
}
}
}
}
The above prints the objects backward. Example run:
Enter the maximum capacity:
13
The maximum value that can be put in a knapsack with a weight capacity of 13 is: 36
ID 13 value 21 weight 9
ID 7 value 15 weight 4
If you want the objects in forward order, inside the for loop put them into a list (you may for instance use id from your old attempt), and then print the items from the list in opposite order.

Checking for Duplicates in an Array Backwards

This is the same person who had trouble with the last array problem just one or two days ago.
We've a new assignment which asks us to find and replace duplicates in an array of randomly generated numbers. I wrote a code and sent it to my teacher for feedback; she responded with this solution:
So, take the first random num and store into the first slot (this can be done before the loop). Then, start a loop that creates the second random num and tests backwards to see if there are duplicates from the ones already stored. So, a backwards loops that tests for duplicates and counts down to 0 from the current location and replaces duplicates. Once that test passes, then you'll go to the next element, create a new random number, and then test the ones before it for duplicates.
I've done this here, and it's reduced the number of randomly generated numbers, but I still run into the stray duplicate:
import java.lang.Object;
import java.util.Random;
public class Prog433a {
public static void main(String[]args) {
Random randslct = new Random();
int[] list = new int[20];
int counter = 0;
int index = 0;
int min2 = 0;
System.out.println("\nAfter");
for (int k = 0; k < list.length - 1; k++) {
list [k] = randslct.nextInt(30) + 1;
for (int z = list.length - 1; z >= 0; z--) {
if (list[k] == list[z] && z!=k) {
while (list[k] == list[z]) {
list [k] = randslct.nextInt(30) + 1;
}
}
}
}
int min = list[0];
while (counter < list.length - 1) {
for (int x = 0; x < list.length - 1; x++) { // scroll through the indexes.
if (list[x] < min) {
min = list[x];
index = x; // keep the index of the biggest number.
}
}
System.out.println(list[index]);
min = 100 * (list[index]);
list[index] = 100 * (list[index]); // change the value in the original array so it won't find the same max again
counter++;
}
}
}
System Output:
After
2
5
6
10
11
12
13
15
16
17
19
22
22
24
25
27
28
29
29
After
1
2
2
4
5
7
8
9
10
13
15
16
21
24
25
26
28
29
30
After
1
2
3
5
6
7
11
12
13
14
15
16
18
21
22
25
26
27
29
After
2
3
3
4
6
10
12
14
15
16
17
20
22
23
24
25
26
27
30
After
7
8
11
12
13
14
15
16
17
17
18
19
20
21
23
24
27
29
30
I posted my output towards the bottom.
Because this is an introductory coding class, I'd prefer if the solution did not involve Sets or any of the like. But alas, beggars cannot be choosers.
Is there something I have forgotten to add?
Your problem is that when you detect a duplicate you generate a new number, but you never go back and check that the the newly generated number is not a duplicate of the numbers you already checked. When you run into a duplicate you'll need to reset the checking loop through some mechanism.
I fixed up the code to work around the problem, but it's not the prettiest solution. I also did some minor optimisation as you were looping through unnecessary indices.
import java.util.Random;
public class Prog433a {
public static void main(String[] args) {
Random randslct = new Random();
int[] list = new int[20];
int counter = 0;
int index = 0;
int min2 = 0;
System.out.println("\nAfter");
for(int k = 0; k < list.length - 1; k++) {
list[k] = randslct.nextInt(30) + 1;
boolean unique = true;
for(int z = k - 1; z >= 0; z--) {
if(list[k] == list[z]) {
if(list[k] == list[z]) {
unique = false;
break;
}
}
}
if(!unique) {
// Repeat last index
--k;
}
}
int min = list[0];
while(counter < list.length - 1) {
for(int x = 0; x < list.length - 1; x++) { // scroll through the indexes.
if(list[x] < min) {
min = list[x];
index = x; // keep the index of the biggest number.
}
}
System.out.println(list[index]);
min = 100 * (list[index]);
list[index] = 100 * (list[index]); // change the value in the original array so it won't find the same max again
counter++;
}
}
}
Your mistake is when you try to add a new number. You just check, if it isn't the same as the one before, but not if it is the same as twice before. You can do this as follow:
boolean isDuplicate(int index, int[] list){
for(int i=index-1; i>=0;i--){
if(int[i]==int[index])
return false
}
return true;
}
instead of your inner of the for-loop you can now write:
do{
list[k] = randslct.nextInt(30) + 1;
}while(isDuplicate(k, list));
Also you should change your output, e.g. give the already written output a negative value and ignore negative values. If you want to change the numbers up to e.g. 200 your code now won't work.
Lets take this by example. Consider that the current list that has been generated is:
list = [5, 7, 9, 3, 8, 9]
where 9 is the current number.
Now in the for-loop, you iterate from list[6] to list[0]. Here, in comparision, you come to 2nd index (list[2]) where the condition
list[k] == list[z] && z != k
turns out to be true and a new random number is generated. Lets assume that here the new random number that you generated is '8'. The loop terminates successfully and your array now has a duplicate.

Project Euler #18: Maximum Path Sum I

So basically I interpreted this problem as follows:
3
7 4
2 4 6
8 5 9 3
The two number below the starting should be compared and the larger should be picked as the new number. So in this case, it would be 3, then 7, then 4, then 9. Sum them up, get the answer of 23. I wrote a program to achieve this:
public class ProblemEighteen {
private static int pos = 1;
public static void main(String[] args) {
try {
Scanner in = new Scanner(new File("Problem18Text"));
int sum = 0;
while (in.hasNextLine()) {
final String line = in.nextLine();
int big = getBiggestNum(line);
sum += big;
System.out.println(big);
}
System.out.println(sum);
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static int getBiggestNum(String line) {
final String[] numbers = line.split(" ");
if (numbers.length == 1) {
pos = 1;
return Integer.parseInt(numbers[0]);
} else {
int i = 1;
int numOne = -1;
int numTwo = -1;
for (final String num : numbers) {
if (pos == i) {
numOne = Integer.parseInt(num);
} else if (pos + 1 == i) {
numTwo = Integer.parseInt(num);
}
i++;
if (numOne != -1 && numTwo != -1)
break;
}
if (numOne > numTwo) {
return numOne;
} else {
pos += 1;
return numTwo;
}
}
}
It works fine for the example I gave above, but when I put in the actual problem to solve, it said I got it wrong (I got 1064). I added a print statement to see what numbers it was selecting and it got them all right (based on how I understood what I was trying to find) but I still got it wrong... Anyone know why?
It's been a while since I've solved this problem, but you'll find that it's best that you start at the bottom of the triangle and work your way up. Especially, when you get to problem 67.
If you read your data into an array as baum suggested, you'd have data that looks like this:
3 0 0 0
7 4 0 0
2 4 6 0
8 5 9 3
So start at the bottom taking two numbers at a time and comparing a sum to their adjacent number in the next above row.
8 + 2 = 10 or 5 + 2 = 7. 10 is greater so replace the 2 with the 10.
5 + 4 = 9 or 9 + 4 = 13. 13 is greater so replace the 4 with the 13.
9 + 6 = 15 or 3 + 6 = 9. 15 is greater so replace the 6 with 15.
Now move up one row and perform the same checks until you get to the very top and the very top should contain the correct answer.

Categories