Need help to spot flaws in my java code - java

I am working on a school assignment and I have the following question:
I am given a number of sticks (with distinct or similar length), and am tasked to find out the minimum number of sticks required to form a longer stick of given length.
For instance,
Given 6 sticks of length 1,1,1,1,1,3 to form a longer stick of length 5, the output would be 3.
NOTE: Sticks cannot be reused.
However, if it is impossible to form the given length, output -1.
For instance,
Given 3 sticks of length 1,2,6, to form a longer stick of length 5, output would be -1.
I have the following code, which have passed all public test cases. However, I failed the private test cases which I cannot figure out my mistake.
Here's my code:
import java.util.*;
class Result {
static int min = 100000;
public static int solve(int pos, int currSum, int len, int numStk) {
// implementation
for (int i=1; i<=Stick.data.length - pos; i++){
if (currSum > len){
continue;
}
else if (currSum < len){
if (pos+i >= Stick.data.length){
break;
}
else{
solve(pos+i,currSum+Stick.data[pos+i], len, numStk+1);
}
}
else if (currSum == len){
if (numStk < min){
min = numStk;
}
}
}
return min;
}
}
class Stick {
static int[] data;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int sticks = sc.nextInt();
data = new int[sticks];
int len = sc.nextInt();
for (int i=0; i<sticks; i++){
data[i] = sc.nextInt();
}
for (int i=0; i<sticks; i++){
Result.solve(i,0,len,1);
}
if (Result.min == 100000){
System.out.println(-1);
} else {
System.out.println(Result.min-1);
}
}
}

Things I notice about your code:
Bug: In main,
Result.solve(i,0,len,1);
assumes that stick i is taken (hence numsticks = 1 in the arguments list), but currSum is given as 0. Shouldn't that be data[i]?
Better code quality: The checks for currSum > len and currSum == len can be done outside the for loop, which is more efficient.

Related

Find different index in arrays compare

I'm trying to learn a bit Java with tutorials and currently I'm struggling with piece of code where I should find on which index is difference between arrays (if there is difference at all)
My code
Scanner scanner = new Scanner(System.in);
int[] arrOne = Arrays.stream(scanner.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
int[] arrTwo = Arrays.stream(scanner.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
int sumArrOne = 0;
int index = 0;
boolean diff = false;
for (int k : arrOne) {
if (Arrays.equals(arrOne, arrTwo)) {
sumArrOne += k;
} else {
for (int i : arrTwo) {
if (k != i) {
index = i;
diff = true;
break;
}
}
}
}
if (diff) {
System.out.println("Found difference at " + index + " index.");
} else {
System.out.println("Sum: " + sumArrOne);
}
So, if arrays are identical I'm sum array elements in arrOne. If they are not identical -> must show at which index they are not.
With this code when I input
1 2 3 4 5
1 2 4 3 5
I should get that difference is at index 2 instead I've got index 1.
I'm not quite sure why and would be glad if someone point me out where is my mistake.
I updated your code. Looks like you're misunderstanding the concept of indexes yet.
Use one common index to check with in both arrays, in my example it's simply called i:
import java.util.Arrays;
import java.util.Scanner;
public class BadArray {
static private final int INVALID_INDEX = Integer.MIN_VALUE;
public static void main(final String[] args) {
try (final Scanner scanner = new Scanner(System.in);) {
final int[] arrOne = Arrays.stream(scanner.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
final int[] arrTwo = Arrays.stream(scanner.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
int sumArrOne = 0;
int diffIndex = INVALID_INDEX;
final int minLen = Math.min(arrOne.length, arrTwo.length);
for (int i = 0; i < minLen; i++) {
sumArrOne += arrOne[i];
if (arrOne[i] != arrTwo[i]) {
diffIndex = i;
break;
}
}
if (diffIndex != INVALID_INDEX) {
System.out.println("Found difference at " + diffIndex + " index.");
} else if (arrOne.length != arrTwo.length) {
System.out.println("Arrays are equal but have different length!");
} else {
System.out.println("Sum: " + sumArrOne);
}
}
}
}
I also put the scanner into a try-resource-catch to handle resource releasing properly.
Note you could also do the array lengths comparison right at the start if different array lengths play a more crucial role.
You are trying to find out which index has the first difference so you should iterate via the index rather than using a for-each loop (aka enhanced for loop). The following method should work for this.
/**
* Returns the index of the first element of the two arrays that are not the same.
* Returns -1 if both arrays have the same values in the same order.
* #param left an int[]
* #param right an int[]
* #return index of difference or -1 if none
*/
public int findIndexOfDifference(int[] left, int[] right) {
// short-circuit if we're comparing an array against itself
if (left == right) return -1;
for (int index = 0 ; index < left.length && index < right.length ; ++index) {
if (left[index] != right[index]) {
return index;
}
}
return -1;
}
In your code you compare, where the indexes are different, not the values at the indexes. Also your code has several other issues. I'll try to go through them step by step:
// compare the whole array only once, not inside a loop:
diff = !Arrays.equals(arrOne, arrTwo));
if (!diff) {
// do the summing without a loop
sumArrOne = Arrays.stream(arrOne).sum();
} else {
// find the difference
// it could be the length
index = Math.min(arrOne.length, arrTwo.length);
// or in some different values
for (int i = 0; i < index; i++) { // do a loop with counter
if (arrOne[i] != arrTwo[i]) {
index = i;
break;
}
}
}
It doesn't matter that I set index here above the loop as it's value will be overwritten anyways inside the loop, if relevant.

Java program to find the second smallest number in console input

I am really trying to grasp this problem but could not continue further without help.
My logic is in order but for some reason it will not execute properly.
On execution I want to enter a line of numbers for example 10 12 5 9 3 and the program should return me the second smallest number.
As I want to control the basics first I am refraining from using any other imported classes except for the two used.
If someone could shed some light on why this does not work I would be very grateful.
package secondSmallest;
import java.util.Scanner;
import java.io.PrintStream;
public class secondSmallest {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
PrintStream out = new PrintStream(System.out);
int smallest = 1;
int secsmallest = 0;
int hold = 0;
while(scan.hasNext()); {
hold = scan.nextInt();
if (hold < smallest) {
smallest = secsmallest;
smallest = hold;
} else {
hold = scan.nextInt();
}
out.printf(" %d", secsmallest);
}
}
}
First of all:
My logic is in order but for some reason it will not execute properly.
means that your logic is not in order (unless there is just a typo, or other syntax error, blocking flawless result);
Second:
Scanner#hasNext(), which you have as a while condition:
Returns true if this scanner has another token in its input. This method may block while waiting for input to scan. The scanner does not advance past any input.
and you should, somewhere, somehow, indicate when you want your while loop to end. In your example, your loop is going on infinitely, as it does not have any base case. Even the "Enter" keystroke is a data, and pressing it will keep entering new-line control character;
Third:
You have your smallest initialized as 1, which is not really a clean design to statically assign the constant to the current minimum. Think of a possibility when your input is different;
Fourth:
You are printing the secsmallest inside your while loop, which, I suppose, is not what you meant to do;
Fifth:
By reading in your else block hold = scan.nextInt(); you are effectively ommiting one input, as the moment your while iterates one step forward, you have another hold = scan.nextInt(); and you jump one iteration;
Sixth:
There are many ways to design "find-second-smallest" algorithm (sorting it first and then taking the second element; introducing two pointers; etc.), but if you insist to follow something close to your way, this works as expected:
public class Main {
public static void main(String[] args) {
int[] arr = {10, 12, 5, 9, 32, 5, 123, 4, -34, 12, -534, -53, -1, 432, 53};
int res = secondSmallest(arr);
System.out.println(res);
}
public static int secondSmallest(int[] arr) {
int smallest = arr[0];
int secsmallest = arr[1];
int i = 2;
while (i < arr.length-1) {
int current = arr[i];
if (current < smallest) {
secsmallest = smallest;
smallest = current;
}
else if(current < secsmallest) {
secsmallest = current;
}
i++;
}
return secsmallest;
}
}
Outputting:
-53
Your program should look like this
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
PrintStream out = new PrintStream(System.out);
int smallest = Integer.MAX_VALUE;
int secSmallest = smallest;
int hold = 0;
while (scan.hasNextInt()) {
hold = scan.nextInt();
if (hold < smallest) {
secSmallest = smallest;
smallest = hold;
} else if (hold < secSmallest) secSmallest = hold;
}
out.printf(" %d", secSmallest);
}

Having trouble in printing the largest array number from the 20 randomly generated numbers

Ok so I been working on this assignment all day for the past 3 days but I haven't had any luck. I wasn't going to ask for help but I finally gave up. But there is also one more thing I need to implement to the code. This is what I gotta implement "Find the length of the longest continuous series of positive numbers in the array data. If the contents were: 4 5 0 2 . . . -1 88 78 66 -6. The length would be 3. For this problem, 0 is considered non-negative but not positive". Plus I have an issue where I can't print the largest int in the array of 20.
import java.util.Random;
import java.util.ArrayList;
public class arrayops {
public static int findLargest(ArrayList<Integer> nums) {
int greatestnum = nums.get(0);
for (Integer item : nums) {
if (item > greatestnum) {
greatestnum = item;
}
}
return greatestnum;
}
public static int randomData(ArrayList<Integer> nums) {
int[] array = new int [20];
Random random = new Random();
for (int i = 0; i < array.length; i++) {
array[i] = -100 + random.nextInt(201);
}
return -100 + random.nextInt(201);
}
public static void main(String[] args) {
ArrayList<Integer> nums = new ArrayList<Integer>();
nums.add(1);
nums.add(4);
nums.add(13);
nums.add(43);
nums.add(-25);
nums.add(17);
nums.add(22);
nums.add(-37);
nums.add(29);
System.out.println("The Greatest Number from the hardcoded numbers " + findLargest(nums));
System.out.println("The Greatest number from the random numbers " + randomData(nums));
}
}
The findLargest method:
public static int findLargest(ArrayList<Integer> nums) {
int greatestnum = 0;
int greatestLen = 0;
for (Integer item : nums) {
if (item > 0) {
greatestLen++ ;
if(greatestLen > greatestnum)
greatestnum = greatestLen;
}
else
greatestLen = 0;
}
return greatestnum;
}
Logic used:
Keep the length of the longest chain encountered, and the length of current chain, in two separate variables (greatestnum and greatestLen respectively)
Increment greatestLen every time a positive number is encountered. If the number if less than or equal to zero, reset this count.
If the length of current chain is greater than the previous longest chain, sent the longest chain size to current chain size.
The problem is you created a list with random numbers but never put that list into the findLargest method. You also never created a method to find the consecutive positive numbers. If you didn't know how to go about coding it, I recommend drawing out an algorithm on paper.
Largest value in ArrayList...
public static int findL(ArrayList<Integer> nums)
{
int top = nums.get(0);
for(int i = 0; i<nums.size(); i++)
{
if(nums.get(i)>top)
{
top = nums.get(i);
}
}
return top;
}
Largest number of consecutive positives...
public static int positiveString(ArrayList<Integer> nums)
{
int longest = 0;
int count = 0;
for(int i = 0; i<nums.size(); i++)
{
if(nums.get(i) > 0)
{
count++;
}
else
{
if(longest<count)
{
longest = count;
}
count = 0;
}
}
return longest;
}
If you want to arrange the numbers into order you can simply use java.util.TreeSet. Then use the method last() to get the largest number.
public static int findLargest(ArrayList<Integer> nums) {
return new TreeSet<Integer>(nums).last();
}

Checking if the graph exist (java)

Determine whether there exists a graph with a sequence of degrees of vertices (s = s1, s2...sn).
What is the best and most optimized algorithm for solving this problem.
Input:
the first line contains `t<100` - amount of sequnces.
the second line contains value `n <= 1000000`(length of a sequence).
the third line contains contains `n` non-negative integer numbers. And so on.
Output:
if the graph can exist print "yes" otherwise print "no".
For example:
Input:
3
5
1 2 3 2 1
4
3 3 2 2
3
1 3 2
Output:
No
Yes
Yes
The maximum execution time should be 0.4 second.
Here is my code (If the number of odd vertices is even, then the graph exists):
import java.util.Scanner;
public class Main {
public static final Scanner in = new Scanner(System.in);
public static void isGraph (int []a, int n) {
int k=0;
for(int i=0; i< n; i++) {
if(a[i] %2 != 0) {
k++;
}
}
if(k%2 == 0)
System.out.println("Yes");
else
System.out.println("No");
}
public static void main(String[] args) throws Exception{
double t1 = System.nanoTime();
int n;
int []a;
int t = Integer.parseInt(in.nextLine());
while(t-- > 0) {
n = in.nextInt();
a = new int[n];
for(int i=0; i<n; i++)
a[i] = in.nextInt();
isGraph(a,n);
}
System.out.println(System.nanoTime() - t1);
}
}
But the execution time of this program is more than 0.4 second. I get run time exceeded. How I can optimize code and speed up runtime. May be there is another algorithm to solve this task, please help me.
I think I have a faster way for you. Please verify this. If you are concerned about the final outcome of even/odd, then there seems to be no reason to keep track of the k counter. You can keep a dynamic value of whether the running sequence is even or odd:
public static void isGraph (int []a, int n) {
int k = 0;
for(int i=0; i< n; i++) {
k += a[i] & 1;
}
if(k%2 == 0)
System.out.println("Yes");
else
System.out.println("No");
}
This might help your reading: I have no experience with it however, I got it from a competition website:
Slow way to read:
/** Read count integers using Scanner */
static int scanInteger(int count) {
Scanner scanner = new Scanner(input);
int last = 0;
while (count-- > 0) {
last = scanner.nextInt();
}
return last;
}
Faster way:
static int readIntegers(int count)
throws IOException {
BufferedReader reader = new BufferedReader(
new InputStreamReader(input) );
StringTokenizer tokenizer = new StringTokenizer("");
int last = 0;
while (count-- > 0) {
if (! tokenizer.hasMoreTokens() ) {
tokenizer = new StringTokenizer(reader.readLine());
}
last = Integer.parseInt(tokenizer.nextToken());
}
return last;
}
EDIT: to show how to avoid two phases where Phase 1 is the read loop, and Phase 2 is the algorithm:
public static void main(String[] args) throws Exception{
double t1 = System.nanoTime();
int n;
// int []a; // Not necessary
int t = Integer.parseInt(in.nextLine());
while(t-- > 0) {
n = in.nextInt();
// a = new int[n]; // Not necessary
int k = 0;
int a;
for(int i=0; i<n; i++) {
a = in.nextInt();
k += a & 1;
}
// isGraph(a,n); // Not necessary
if(k % 2 == 0)
System.out.println("Yes");
else
System.out.println("No");
}
System.out.println(System.nanoTime() - t1);
}
May be there is another algorithm to solve this task
That's not the problem (IMO).
Hint 1: since you know the length of the sequence beforehand, you can create the array and parse the sequence faster than this:
a = Arrays.stream(s.split(" ")).mapToInt(Integer::parseInt).toArray();
(Java 8+ streams are elegant, but they are not the fastest way.)
Hint 2: using Scanner is probably faster than reading strings and parsing them.
Hint 3: you could probably avoid creating an array entirely. (It would be poor coding practice IMO ... but if performance is critical ...)

Better minimum and maximum algorithm using an array in Java

I was trying to write a simple max and min method, as I wrote it I just cant help feeling it shouldn’t be this complicated….maybe Im wrong?
My maximum code works like this, excuse my poor pseudo code:
Fill an array with 10 random numbers.
Create a max variable initialised to 0, because 0 is the lowest max.
Compare each element against the max
If the element is greater then max, replace the value of max with the element in question
I don’t like the fact I have to initialise max to 0, I feel there might be a better way then this?
My min code works similar except I:
Compare my min is lower then the array element.
If the element is lower replace min.
What I really don’t like about this is I have to initialise my min to the maximum random number, in this case 50.
My questions are:
Is there a better way to do this?
Is there a more efficient way to write this code?
import java.util.Random;
public class Main {
public static void main(String[] args) {
//Declare min and max
int max=0;
int min;
//Array of 10 spaces
int[] ar=new int[10];
//fill an array with random numbers between 0 and 50
for(int i=0;i<10;i++)
{
ar[i]=new Random().nextInt(50);
}
//Test max algorithm
//loop trough elements in array
for(int i=0;i<10;i++)
{
//max is set to 0, there should always be a maximum of 0
//If there isnt 0 will be the maximum
//If element is greater then max
//replace max with that element
if(ar[i]>max)
{
max=ar[i];
}
}
System.out.println("The max is "+ max);
//Test min
//Initialising min to maximum Random number possible?
min=50;
for(int i=0;i<10;i++)
{
if(ar[i]<min){
min=ar[i];
}
}
System.out.println("The min is "+min);
}
}
You can always grab the first element of the array (i.e. numbers[0]) as the initial value and start the loop from the second element.
int[] numbers = new int[10];
int max, min;
...
min = max = numbers[0];
for(int i = 1; i < numbers.length; ++i) {
min = Math.min(min, numbers[i]);
max = Math.max(max, numbers[i]);
}
Ok, while others were already posting answers, I have taken the time to edit your code into something I think would be more usable.
Make static methods. Those can be reused.
Use an ellipsis (...) because you then can either call the methods on array arguments like in your code, but also with a variable number of arguments as min(5,3,8,4,1).
Initialize with the smallest/biggest possible number the data type provides
To check that your code works, you have to print out the items in the array first, since when you don't know what's in it, there's no way to tell the result is correct.
Base your code on the existing methods in the standard library because these are known to be thoroughly tested and work efficiently (I know, min/max looks like a too trivial example).
I wouldn't bother too much about performance unless you really can show there is a performance problem in your code. Priority should be more like 1st correctness, 2nd readability/maintainability, 3rd performance.
Most of this has been already mentioned by others, but anyway, here's the code:
import java.util.Random;
public class MinMax {
public static int min(int... args) {
int m = Integer.MAX_VALUE;
for (int a : args) {
m = Math.min(m, a);
}
return m;
}
public static int max(int... args) {
int m = Integer.MIN_VALUE;
for (int a : args) {
m = Math.max(m, a);
}
return m;
}
public static void main(String[] args) {
// fill an array with random numbers between 0 and 50
int[] ar = new int[10];
for (int i = 0; i < 10; i++)
{
ar[i] = new Random().nextInt(50);
System.out.println(ar[i]);
}
int maxValue = max(ar);
int minValue = min(ar);
System.out.println("The max is " + maxValue);
System.out.println("The min is " + minValue);
}
}
Few tips:
Initialize min with first element and start from the second:
int min = ar[0];
for(int i=1;i<10;i++)
...or start from:
int min = Integer.MAX_VALUE;
this approach is better if you expect your array can be empty.
Use Math.min to avoid explicit condition (some may say it's slower though):
for(int i=0;i<10;i++)
{
min = Math.min(min, ar[i]);
}
Initialize max to 0 & min to 50 won't work when the numbers change. A more appropriate way is:
1. initialize them to the first element of the array.
2. Use length instead of a constant.
max = ar[0];
for(i=0;i<ar.length; i++)
{
if(ar[i]>max)
{
max=ar[i];
}
}
Same for min:
min = ar[0];
for(i=0;i<ar.length; i++)
{
if(ar[i]<min)
{
min=ar[i];
}
}
public static void main(String[] args) {
int[] myArray = {9, 7,9, -40, -10, 40};
//int[] myArray = {};
//int[] myArray = {4};
System.out.println("Difference between max and min = "
+ findDifference(myArray));
}
// Find difference between Max and Min values for a given array
public static int findDifference(int[] arr) {
if (arr.length == 0) {
// Log
System.out.println("Input Array is empty");
return Integer.MIN_VALUE;
}
int min = arr[0];
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] < min)
min = arr[i];
else if (arr[i] > max)
max = arr[i];
// Just to check if logic works fine
System.out.println("Min=" + min + " Max=" + max);
}
return max - min;
}
import java.io.*;
public class MultiDimensionalArrayIO {
public static void main(String[] args)throws IOException {
BufferedReader c= new BufferedReader (new InputStreamReader (System.in) );
System.out.print ( "Enter Number Column : " );
int column = Integer.parseInt(c.readLine());
System.out.print ( "Enter Number Row : " );
int row = Integer.parseInt(c.readLine());
int array [][] = new int [column][row];
int max = array [0][0];
int min = array [0][0];
int sum= 0;
for ( int i=0 ; i < array.length; i++){
for (int j=0 ; j<array[i].length; j++){
System.out.print("Enter Array Values ["+i+"]["+j+"]: " );
array[i][j]= Integer.parseInt (c.readLine());
min = Math.min(min , array[i][j]);
max = Math.max(max , array[i][j]);
sum += array[i][j];
}
}
System.out.println("The Min Number :"+ min);
System.out.println("The Max Number :"+ max+ " total is "+ sum);
}
}
Depending on whether you'd want the max and min-functions in the same method you also have to consider the return type.
So far most suggestions have kept the two separate, meaning it's fine to return an int. However, if you put the max and min-functions into a findLargestDifference-method you'd have to return a long seeing as the largest difference between any given numbers in the int array can be the size of 2 ints. You'd also getting rid of having to loop over the int array twice.
Furthermore I recommend writing unit tests for corner and edge cases instead of printing in a main-method. It helps test your logic early on when implementing it and thus often makes the code cleaner.
See example code below.
public class LargestDifference {
public static long find(int[] numbers) {
if (numbers == null || numbers.length == 0) {
throw new IllegalArgumentException("Input cannot be null or empty.");
}else {
long currentMax = numbers[0];
long currentMin = numbers[0];
for (int i=0; i < numbers.length; i++) {
if (currentMin > numbers[i]) {
currentMin = numbers[i];
}else if (currentMax < numbers[i]) {
currentMax = numbers[i];
}
}
return currentMax - currentMin;
}
}

Categories