Two smallest numbers in a set - java

I am trying to find the two smallest numbers in a set WITHOUT USING ARRAYS. Here is the code:
Scanner in = new Scanner(System.in);
int N = in.nextInt();
int min = in.nextInt();
for(int i = 1; i < N; i++){
int a = in.nextInt();
if(a < min){
min = a;
}
}
System.out.println(min);
It find the smallest number but there is nothing about the second smallest number.
How do I do that?
Please, note that I am a complete beginner to Java so easy explanation and help will be much appreciated)

It´s very very easy:
Scanner in= new Scanner(System.in);
int N = in.nextInt();
int min,min2 = Integer.MAX_VALUE,Integer.MAX_VALUE;
for(int i = 0; i < N; i++){
int a = in.nextInt();
if( a < min){
min = a;
min2 = min;
}
else if( a < min2){
min2 = a;
}
}
System.out.println(min);
System.out.println(min2);

It is about one condition you have to add:
Scanner in = new Scanner(System.in);
int N = in.nextInt();
int min = Integer.MAX_VALUE;
int secondMin = Integer.MAX_VALUE;
for(int i = 0; i < N; i++){
int a = in.nextInt();
if(a < min){
secondMin = min; // the current minimum must be the second smallest
min = a; // allocates the new minimum
}
else if (a < secondMin) {
secondMin = a; // if we did not get a new minimum, it may still be the second smallest number
}
}
System.out.println(min);
System.out.println(secondMin);

General hint: You should call the close method of your Scanner, preferably in a try-with-ressources block:
try(Scanner in = new Scanner(System.in)) {
// other code here
}
That way the stream gets closed, which you should do, if you open a stream.
Solution 1:
The easiest way, that uses your existing code, would be also tracking the second smallest number:
Scanner in = new Scanner(System.in);
int N = in.nextInt();
int min = in.nextInt();
int sMin = Integer.MAX_VALUE;
for(int i = 1; i < N; i++){
int a = in.nextInt();
if(a < min){
sMin = min;
min = a;
} else if(a < sMin) {
sMin = a;
}
}
System.out.println(min);
System.out.println(sMin);
Explanation 1:
The two cases, that can occure with a new Value are:
The new value is smaller than min and sMin. Then you have to set the value of min into smin and afterwards set min to the new min value.
The new value is larger than min and smaller than sMin. Then you only have to set the value of sMin to the new value.
Both min-values are smaller. Then nothing is to do.
Solution 2:
Another, more generic approach would be using a PriorityQueue:
int N = in.nextInt();
PriorityQueue<Integer> minQueue = new PriorityQueue<>();
for(int i = 0; i < N; i++) {
int value = in.nextInt();
minQueue.add(value);
}
int minValue = minQueue.poll();
int secondMinValue = minQueue.poll();
This way you can get the n smallest numbers given by using a loop in which you call the poll() method. (n may be a number < N).
Explanation 2:
The Priority Queue is a datastructure, that internally orders the given elements by the natural order. In the case of Integers this order is given by <,> and =. So when calling poll() you remove the smallest element, that the PriorityQueue has yet encountered.

Try this:
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int min2 = in.nextInt();
int min1 = min2;
for(int i = 1; i < n; i++){
int a = in.nextInt();
if( a < min2){
if(a < min1){
min2 = min1;
min1 = a;
}
else{
min2 = a;
}
}
}
System.out.println(min1 + " " + min2);

This problem can be solved in multiple ways, and the first step in choosing the right solution is to decide what is the most important for you:
Space efficiency, that is, use the minimum possible amount of storage. ThreeFx does this, (s)he only uses constant additional space for the variables N, a, min, and secondMin. "Constant space" means that the amount of data that you store does not depend on how many numbers you are going to read from the stream. In contrast, Tarlen uses linear space, storing all the numbers read from the stream. This means that the amount of space required is directly proportional to N instead of being constant.
Time efficiency, that is, perform as few computations as possible. I believe that ThreeFx's solution is one of the most efficient from this point of view. Tarlen's solution will be a bit slower, because managing the priority queue might require more comparisons.
Extensibility, that is, how easily you could adapt your code when the requirements change slightly. Say that your boss makes you solve the problem that you just posted, to find the two smallest numbers. The next day, he wants the first three, and so on, until the end of the week. You get tired of changing your code every day, so you write a general solution, that will work for any number of elements that he asks for. This is where Tarlen's solution is better.
Readability, that is, how short and easy to understand your code is. I will introduce my own solution here, which is based on a simple idea: put all the numbers in a list, sort it, and take out the first two numbers. Note that this is quite wasteful when it comes to resources: the space is linear (I am storing N numbers), and the time efficiency is O(N log N) at best. Here is my code:
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < N; i++) list.add(in.nextInt());
Collections.sort(list);
System.out.println(list.get(0));
System.out.println(list.get(1));

Related

Terminated due to timeout for my hacker rank solution

Hello all please check the problemHackerRank Problem Statement
This is my solution for the above problem(link)
static int migratoryBirds(List<Integer> arr) {
int ar[]=new int[arr.size()];
for(int i=0;i<arr.size();i++){
ar[i] = Collections.frequency(arr,arr.get(i));
// ar[i] = obj.occuranceOfElement(arr,arr.get(i));
}
int maxAt = 0;
for (int i = 0; i < ar.length; i++) {
maxAt = ar[i] > ar[maxAt] ? i : maxAt;
}
return arr.get(maxAt);
}
my code is unable to handle when the array size is bigger,example 17623 elements in array.
Terminated due to timeout
The problem is in the second for loop which iterates over the array and gives me the index of the largest number in the array.Is there any other way that I could increase the performance.
Your problem is in this part:
for(int i = 0; i < arr.size(); i++)
ar[i] = Collections.frequency(arr, arr.get(i));
This is O(N²): Collections.frequency() iterates over whole list to calculate frequency for only one element. Manually, you can iterate over the list to calculate frequencey for all elements.
Moreover, ther're only 5 birds, so you need only 5 length array.
static int migratoryBirds(int[] arr) {
int max = 1;
int[] freq = new int[6];
for (int val : arr)
freq[val]++;
for (int i = 2; i < freq.length; i++)
max = freq[i] > freq[max] ? i : max;
return max;
}
Your problem is the call to Colletions.frequency, which is an O(N) operation. When you call it from inside a loop it becomes O(N²) and that consumes all your time.
Also, are you sure which implmentation of List you receive? You call list.get(i) which might also be O(N) if the implementation is a LinkedList.
The target of this exercise is to calculate the frequency of each value in one pass over the input. You need a place where you store and increase the number of occurrences for each value and you need to store the largest value of the input.
You have also skipped over a crucial part of the specification. The input has limits which makes solving the problem easier than you now think.
Here's another one:
static int migratoryBirds(List<Integer> arr) {
int freq[]=new int[6];
for(int i=0;i<arr.size();i++){
++freq[arr.get(i)];
}
int maxAt = 1;
for (int i = 2; i < freq.length; i++) {
if (freq[i] > freq[maxAt]) {
maxAt = i;
}
}
return maxAt;
}
We can determine the type number of the most common bird in one loop. This has the time complexity O(n).
static int migratoryBirds(int[] arr) {
int highestFrequency = 0;
int highestFrequencyBirdType = 0;
int[] frequencies = new int[5]; // there are 5 bird types
for (int birdType : arr) {
int frequency = ++frequencies[birdType - 1];
if (frequency > highestFrequency) {
highestFrequency = frequency;
highestFrequencyBirdType = birdType;
} else if (frequency == highestFrequency && birdType < highestFrequencyBirdType) {
highestFrequencyBirdType = birdType;
}
}
return highestFrequencyBirdType;
}
For each element in the array arr we update the overall highestFrequency and are storing the corresponding value representing the highestFrequencyBirdType . If two different bird types have the highest frequency the lower type (with the smallest ID number) is set.

How can I change the values exceeding the int data type to the long data type in this code?

In the last portion of this code (where the last for loop and if statements are), I'm trying to change the data type of the integers to long when they exceed the integer data type limit. What am I doing wrong in this code? When I run, I get the same values as before I even tried to change them to long (which are increasingly huge integers until they get negative).
public class UniqueElements {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
int maxValue = 0;
int numElements = 0;
int programRuns = 12;
Scanner sc = new Scanner(System.in);
for (int newExecution = 0; newExecution <= programRuns; newExecution++ ) {
System.out.print("Enter the maximum value for an element: ");
//prompt user to enter the maximum value
maxValue = sc.nextInt(); //user input for max value
System.out.print("Enter the number of elements in the array: ");
numElements = sc.nextInt(); //number of elements in an array
int A[] = new int[numElements];
//array comprising of the number of elements chosen by the user
int totalComp = 0; //set total comparisons to 0
for (int runs = 1; runs <= 100; runs++) { //program runs 100 times
Random rand = new Random(System.nanoTime());
//initiate the random number generator
int numComp = 0; //set number of comparisons to 0
for (int index = 0; index < numElements; index++) {
A[index] = rand.nextInt(maxValue);
//length of array is the number of elements the user puts in
}
for (int i = 0; i < A.length; i++) { //for each integer in the array
for (int j = i + 1; j < A.length; j++) {
//for each integer following i
if (A[i] == A[j]) { //if the are equal to eachother
//end the if statement
break;
}
if (numComp == (int)numComp) {
numComp++;
}
else {
Long.valueOf(numComp);
numComp++;
}
}
}
totalComp+= numComp;
} //end 100 loops
if (totalComp == (int)totalComp)
System.out.println("Average number of comparisons: " + totalComp / 100);
else {
System.out.println("Average number of comparisons: " +
Long.valueOf(totalComp) / 100L);
}
}
}
}
update:
somehow.... changing the total number of runs to 2 and dividing the totalComp variable by 2 and 2L made it work. Anyone know how that changed it?
You can't change the type of a variable after it's already been declared. You can cast that variable to another type, or "interpret" it as another type (as in your Long.valueOf()), but the variable still remains whatever type you declared it as.
In your code, you've declared totalComp to be an int, which in Java means it holds 32 bits (one of which is a sign bit). There's no way to make Java store more than 32 bits in an int. If you continue to add beyond Integer.MAX_VALUE, or subtract below Integer.MIN_VALUE, the value in the variable will simply under/overflow. So this statement after your for loop isn't doing what you expect, and will always be true: if (totalComp == (int)totalComp)
In other words, you can't go "back in time" and re-declare your primitive int as a long because you found out at runtime that you need to store larger values. The easiest way to solve this problem would be to declare totalComp as a long. If for some reason you can't change the type of totalComp, it is possible to detect overflow/underflow before performing the calculation; see this answer for details.

How to get the largest number in an array?

I am trying to find the largest number in an array of 10 numbers. Here is my code:
public static void getNumber() {
int NumbersArray[] = new int[11];
int num1;
int num2;
int largestNumber = 0;
Scanner scanner = new Scanner(System.in);
for(int i=1; i<11; i++){
System.out.println("Enter number " + i );
int no1 = scanner.nextInt();
NumbersArray[i] = no1;
}
scanner.close();
for(int i=1; i<11; i++)
{
System.out.println(NumbersArray[i]);
num1 = NumbersArray[i];
for(int j=10; j>0; j--)
{
num2 = NumbersArray[j];
if(num1>num2){
largestNumber = num1;
}
}
}
System.out.println("the largest number is " + largestNumber);
}
I found a real simple soultion to this here.
But the reason I am posting this is to find out what mistake have I made.
The first portion gets 10 numbers from the users and the second portion is my code to find the largest number.
Going off Pshemo's suggestion, keep a record of the largest int as the user is typing. This reduces the size of your method by half and makes it much simpler and more readable.
Program with 0-based indexing. So use int NumbersArray[] = new int[10] instead of int NumbersArray[] = new int[11]. When you declare the size of your array, simply put your desired size, you don't have to worry about 0 indexing or anything. For your for-loop, start at int i=0 and end at i<10.
public static void getNumber(){
int NumbersArray[] = new int[10];
int largestNumber = 0;
Scanner scanner = new Scanner(System.in);
for(int i=0; i<10; i++){
System.out.println("Enter number " + i );
int no1 = scanner.nextInt();
NumbersArray[i] = no1;
if(no1 > largestNumber)
largestNumber = no1;
}
scanner.close();
System.out.println("The largest number is: " + largestNumber);
}
The problem is that you are iterating through the list twice (in a nested way). Let's say you have the following numbers: [5, 7, 3, 4]. As you go through the inner loop the first time you'll end up comparing numbers against 5. Only 7 is larger so largestNumber will be set to 7. Then you'll go through again, this time comparing against 7. Nothing is larger than 7, so it'll be left alone. Next you'll compare against 3. The last comparison there is 3 vs. 4, and since 4 is larger you end up setting largestNumber to 4, which is incorrect.
These lines:
for(int i=1; i<11; i++)
{
System.out.println(NumbersArray[i]);
num1 = NumbersArray[i];
for(int j=10; j>0; j--)
{
num2 = NumbersArray[j];
if(num1>num2){
largestNumber = num1;
}
}
}
Don't search for the largest number in the array, but simply search for any value in NumbersArray a value that is bigger than the current element. Thus largestNumber isn't the largest number in the array, but the last number in NumbersArray that is larger than the last element of NumbersArray, unless the last element of NumbersArray is the biggest element, in this case the largestNumber will be the last value in NumbersArray.
A working solution would be:
int max = Integer.MIN_VALUE;
for(int i : NumbersArray)
if(max < i)
max = i;
Though the most efficient solution would be to directly keep track of the currently largest input while reading the input.
And keep in mind that java-arrays are 0-based. This means that the first element is at NumbersArray[0], not NumbersArray[1], like in your code.
As far as I know you can use Java Math max() method to get largest number.
i.e. : dataType max(int number1, int number2), Math.max(number1, number2) gets the maximum between number 1 and 2.

Adding numbers within a certain range. How?

So far I cant figure out how to do it. It only adds the start and the end of the range, it doesnt add the numbers within the range or I think its not what I input as a range that it adds but instead it adds the number between x an y.
I am trying to add numbers between a certain range of array.
int[] range = new int[10];
for (int x = 0; x < range.length; x++) {
System.out.print("Enter number: ");
range[x] = in.nextInt();
}
System.out.println("Enter the numbers for the start and end of the range. ");
int start = in.nextInt();
int end = in.nextInt();
start = range[start];
end = range[end];
for(; start < end; end = end -1) {
start =end+ start;
}
System.out.println(start);
Sorry if the question has already been asked.
Try doing a less exotic loop. Something like this should do it.
int sum = 0;
for(int i=start; i <= end; i++){
sum = sum + range[i];
}
System.out.println(sum);
well, first thing:
start = range[start];
end = range[end];
When you initialize array you make user to input numbers, and what you want for a range - not numbers, but indexes. And be sure - you will forget what you tried to do with this code in a month, so you have to make it more readable - make additional variable for the result (and comments ofc).
So that's how i see a code that will work fine:
int start = in.nextInt();
int end = in.nextInt();
int result=0;
for(;start <= end; start++){
result += range[start];
//any other operations with numbers incide your range
}
System.out.println(result);

Is this way standard to calculate the smallest number in Java

I wrote a program that calculate the smallest number. But I don't know how programers would do it.
I did it by "IF statement", which is working, but not sure if it is the standard or common way of coding it.
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
System.out.print("Enter three values: ");
int num1 = in.nextInt();
int num2 = in.nextInt();
int num3 = in.nextInt();
System.out.print(smallest(num1, num2, num3));
}
public static int smallest(int num1, int num2, int num3)
{
if (num1 < num2 && num1 < num3){return num1;}
else if (num2 < num1 && num2 < num3){return num2;}
else return num3;
}
There is Math#min method. You can use that one:
minimum = min(n1, min(n2, n3))
Another idea would be to not even store all of the numbers but instead just keep track of the smallest, if that's all you're looking for:
int smallest = in.nextInt();
for (int i = 0; i < 2; i++) { // take 2 more inputs
int next = in.nextInt();
if (next < smallest)
smallest = next;
}
If you indeed do not need to access inputs other than the smallest later on, this approach would likely be optimal.
You can solve the more general problem of finding the smallest value of an array (or a list). It is a bad idea to sort() the structure, as you only need to find the smallest element. A really basic technique for doing so would be something like that:
public int smallest(int[] array) {
if(array.length == 0) throw new IllegalArgumentException();
int min = array[0];
for(int i=1 ; i<array.length ; i++)
if(array[i] < min)
min = array[i];
return min;
}
This has a O(n) complexity which is minimal for a non-sorted array because you have to go through the entire array anyway.
This is of course only optimal in the general case of an array that's already full of number. If you only need to get the minimum from user's inputs then you should definitely go for arshajii's algorithm to save a bit of memory because it allows you not to store the entire array.
I would do this:
public static int smallest(int... nums) {
Arrays.sort(nums);
return nums[0];
}
Not only is it minimal elegant code, by using a varargs parameter, it can handle any quantity of ints.
And the code that calls it need not be altered.
A way of doing this is by creating an array of integers, and then sorting it and grabbing the first element.
Something like:
int[] input = new int[]{in.nextInt(), in.nextInt(), in.nextInt()};
Arrays.sort(input);
int min = input[0];
Also seeing as you have made a function for it, you could turn that one into the following, instead of my above approach:
public static int smallest(int... numbers) {
if (numbers.length == 0) {
throw new IllegalArgumentException("numbers: numbers.length == 0");
}
Arrays.sort(numbers);
return numbers[0];
}
In this example you are using varargs, meaning that you can put in as many ints as you want. The varargs argument is essentially an array once it gets into your function, so then you can just work with it like any array. Be sure to do a check on the number of items in the array though, as varargs can also be 0.
You can call the code the same way as the old one:
int smallest = smallest(5, 10, 15); will return 5.

Categories