How do you find second highest number in an integer array? [duplicate] - java

This question already has answers here:
Finding the second highest number in array
(45 answers)
Closed 9 years ago.
How do you find second highest number in an integer array?
Is this a good implementation?
Is there a better way to do this?
public class Find2ndHighest {
public static void main(String[] args) {
int b[] = {2,3,1,0,5};
TreeMap<Integer,Integer> tree = new TreeMap<Integer,Integer>();
for(int i = 0; i<b.length;i++){
tree.put(b[i], 0);
}
System.out.println(tree.floorKey(tree.lastKey()-1));
}
}

You can sort the array and fetch second last element which executes in O(nlogn), but this works only if you are sure that there are no duplicates in the array else this method is unreliable.
You can iterate through the array maintain counters for highest and second highest and return 2nd highest. This executes in O(n)
Example:
int highest = Integer.MIN_VALUE+1;
int sec_highest = Integer.MIN_VALUE;
for(int i : b) //b is array of integers
{
if(i>highest)
{
sec_highest = highest; //make current highest to second highest
highest = i; //make current value to highest
}
else if(i>sec_highest && i != highest)
{
sec_highest = i;
}
}
Another solution is:
int b[] = {1, 2, 31,22,12,12};
Arrays.sort(b);
System.out.println(b[b.length-2]);

The easiest solution would be:
public static void main(String[] args) {
int b[] = {2,3,1,0,5};
int highest = Integer.MIN_VALUE;
int highest2nd = Integer.MIN_VALUE;
for(int i :b )
if (i>=highest) {
highest2nd = highest;
highest = i;
} else if (i>= highest2nd)
highest2nd = i;
System.out.println(highest2nd);
}
Then you walk through the list only once, which is the best you can do from a 'Big O' standpoint.
PS: depending on whether you want the second highest unique value, or the value that is stricly lower than the highest value, you could choose to put i>highest in the if-statement, instead of i>=highest.

There are multiple ways to find the second highest element in an unsorted array:
You can sort the array and take the second last element - runs in O(n log n).
You can store the elements in a TreeSet instead of an array, which is what you are doing - runs in O(n log n) as well.
Suppose for a while you want to get the highest element - all you have to do is to iterate over the whole aray once, while keeping the maximum in a variable.
This way you can achieve O(n) performance.
You can do the same thing for the second highest element, but instead of keeping the highest element, you will keep the two highest elements.
This way you can easily achieve O(n) performance.
The only problem with the last solution is that it does not scale well with the increasng k.
There is however a linear time algorithm to find the k-th highest element in an unsorted array - runs in O(n) for any k (http://en.wikipedia.org/wiki/Selection_algorithm)

Related

Optimize the time complexity of program which computes the number of different pairs of numbers like described below

As I am pretty new to java, I'm struggeling with optimization of the time complexity of my programs. I have written a simple code which takes an array, and counts how many pairs of numbers there are for which the element with the lower index in the array is greater than the element with the greater index.
For example, if you have the array: [9,8,12,14,10,54,41], there will be 4 such pairs: (9,8),(12,10),(14,10) and (54,41).
I tried to optimize the code by not just comparing every element with every other one. I aimed for a time complexity of n log n. I have not yet figured out a way to write this code in a more efficient manner. I hope my question is clear.
The code(I have omitted adding the heapsort code, as it's not related to my question.)
import java.util.Scanner;
class Main4 {
static int n;
static int[] A;
// "A" is the input vector.
// The number of elements of A can be accessed using A.length
static int solve(int[] A) {
int counter = 0;
int[] B = new int[n];
B = A.clone();
heapSort(B);
for (int i = 0; i < A.length; i++) {
for (int j = 0; j < A.length; j++) {
while( B[j] == Integer.MIN_VALUE&&j+1<n) {
j=j+1;
}
if (A[i] != B[j]) {
counter++;
} else {
B[j] = Integer.MIN_VALUE;
break;
}
}
}
return counter; }
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int ntestcases = scanner.nextInt();
for (int testno = 0; testno < ntestcases; testno++) {
n = scanner.nextInt();
A = new int[n];
for (int i = 0; i < n; i++)
A[i] = scanner.nextInt();
System.out.println(solve(A));
}
scanner.close();
}
}
Divide and conquer 1 (merge-sort like)
Split the whole list W into two parts L and R of early equal lengths. The count for W is the sum of
counts for L and R
the number of pairs (l, r) with l > r where l and r belong to L and R respectively.
The first bullet is recursion. The second bullet does not depend of the ordering of the lists L and R. So you can sort them and determine the result using a single pass through both lists (count all smaller r in sorted R for the first element of sorted L, the count for the second can now be computed incrementally, etc).
The time complexity is given by
T(n) = T(n/2) + T(n/2) + O(n log n)
which I guess is O(n log n). Anyway, it's much smaller than O(n*n).
You could improve it a bit by using merge sort: You need sorted L and this can be obtained by merging sorted LL and sorted LR (which are the two parts of L in the recursive step).
Divide and conquer 2 (quick-sort like)
Select an element m such that the number of bigger and smaller elements is about the same (the median would be perfect, but a randomly chosen element is usable, too).
Do a single pass through the array and count how many elements smaller than m are there. Do a second pass and count the pairs (x, y) with x placed to the left of y and x >= m and m > y.
Split the list into two parts: elements e >= m and the remaining ones. Rinse and repeat.
You are looking for all possible pairs.
You can check from left to right to find all the matches. That's O(n^2) solution. As suggested by Arkadiy in the comments, this solution is okay for the worst case of the input.
I came up with the idea that you might want to store elements in sorted order AND keep the original unsorted array.
You keep the original array and build binary search tree. You can find the element with original index i in time O(lgn) and remove it in O(lgn), which is great. You can also determine the number of values smaller than ith element with tiny additional cost.
To be able to count the elements smaller than, each node has to store the number of its children + 1. When you remove, you simply decrement the number of children in each node on your way down. When you insert, you increment the number of children in each node on your way down. When you search for a node you store the value root node has in variable and
do nothing when you go to the right child,
subtract the number child has from your variable when you go to the left child
Once you stop (you found the node), you subtract the value right child has (0 if there is no right child) and decrement the value.
You iterate over the original array from left to right. At each step you find element in your tree and calculate how many elements that are smaller are in tree. You know how many smaller than your current are there and you also know that all elements in the tree have greater index than the current element, which know how many elements you can pair it up with! You remove this element from the tree after you calculate the number of pairs. You do that n times. Lookup and removing from the tree is O(lgn) == O(nlgn) time complexity! The total time is O(nlgn + nlgn) = O(nlgn)!!
Chapter 12 of Introduction to algorithms (3rd edition) explains in depth how to implement BST. You may also find many resources on the Internet that explain it with pictures.

Count the number of times going through a list from beginning

I am trying to solve problem A (called Task Management) in the following website: http://codeforces.com/gym/101439/attachments/download/5742/2017-yandexalgorithm-qualification-round-en.pdf
Basically, we are given a unsorted list of integers from 1 to n and we want to visit integers in order(i.e from 1,2,3,4,5,.... n). How many times do we have to go to the beginning of the list until we have visited all integers from 1 to n in increasing order.
Let's say we have a list like: 3 2 1. during the first run through the list we visit only the number 1, during the second run through the list, we visit only the number 2, and during the third run we finally visit the number 3. So we have to go through the list 3 times.
Here is my code:
import java.util.Scanner;
import java.util.ArrayList;
class TaskManagement{
// arr: array of tasks
static int countNumberOfLoops(ArrayList<Integer> arr){
int targetTask = 1;
// Last task to close
int finalTask = arr.size();
int index=0;
int count =0;
while(targetTask != finalTask+1){
if(index%arr.size()==0) count++;
if(arr.get(index%arr.size())==targetTask) targetTask++;
index++;
}
System.out.println(count);
return count;
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
// make a static array of size n
ArrayList<Integer> arr = new ArrayList<Integer>();
for (int i=0; i<n; i++) {
int item = scan.nextInt();
arr.add(item);
}
countNumberOfLoops(arr);
}
}
The problem is: my code is not efficient enough, O(n^2) and for a very large data set, it will be slow.
Is there any way I can implement the code in a more efficient way?
Loop through all the numbers and store the index of their occurrence in a hash table or a normal array since numbers are between 1-n.
For example if, the numbers were 3, 4, 5, 2, 1
which would result in hash like this. (let's call this Index)
{
1 -> 4,
2 -> 3,
3 -> 0,
4 -> 1,
5 -> 2
}
Loop from 1 to n-1 and find the index for ith and (i+1)th element.
loopCount = 0;
loopCount = 0;
for (int i=1; i<n; i++) {
if (Index[i] > Index[i+1]) {
loopCount++;
}
}
Time complexity O(n)
An editorial has been posted here:
Consider a solution with the complexity O(n^2). Use a variable to track the
last closed task and go through the list of tasks from the beginning
to the end. Increase the counter when passing through the element
corresponding to the next task. The constraints are quite large, so
this solution doesn't fit the timelimit.
What is the case when we can
not find any suitable tasks up to the end of the list? There is only
one case: the task number (x + 1) is closer to the beginning of the
list then the closed task number x. Therefore, to solve the problem we
can determine position of each task in the task list and count the
number of distinct numbers x such that the position of task number
(x + 1) is less than the position of task number x.
Don't forget to
consider the first pass through the task list. The final complexity of
the solution is O(n).

How to find the smallest distance between two numbers next to each others in an array?

I have a sorted array. Let's say it is int [] numArr=new int[]{6, 9, 10, 27};
The smallest distance is between the 9 and the 10, and it is 1. The program should print this 1.
I am not expecting code, but I hope someone can give me an idea of how to proceed.
Declare a variable to hold the current minimum distance. It can be initialized to a really large number Integer.MAX_VALUE so that the first distance calculated becomes the initial minimum distance.
Use a for loop to loop over the values. You'll be accessing the element at the current index and the next index, so stop your for loop early to prevent an ArrayIndexOutOfBoundsException.
In the for loop, calculate the difference. If the difference is less than the current minimum, then update the current minimum to the current difference.
public static final int findSmallestDistance(final int[] pArray) {
int lMinimumDistance = Integer.MAX_VALUE;
for(int i = 1; i < pArray.length; i++) {
int lDifference = pArray[i] - pArray[i - 1];
if(lDifference < lMinimumDistance) {
lMinimumDistance = lDifference;
}
}
return lMinimumDistance;
}
Step 1: create a variable to save the actual smallest distance
Step 2: iterate through your array
Step 3: compare your actual number with the previous on your array (if this is the first element jump this step) and if it's smaller than your smallest save the result
Step 4: if the array has more elements, get the next one, else print your result
Here's some pseudocode:
Be smallest = a number surely greater than the one you're looking for
For each element i in array except the first
Be n = array[i] - array[i-1]
If n < smallest then
smallest = n
End If
End For
int numArr[] = {6, 9, 10, 27};
for(int i=0;i<numArr.length-1;i++){
if(numArr[i+1]-numArr[i]>0){
System.out.println("distance between " +numArr[i]+ " and "+numArr[i+1]+ " is: "+ (numArr[i+1]-numArr[i]));
}
}
int smallest = 100000
for (int i = 0; i < array.length; i++)
if(array[i+1]-array[i]<smallest)
{
smallest = array[i+1]-array[i];
}
System.out.println(smallest);

java code regarding grades and averages

For my assignment I have to create a code that reads in 10 assignment grades, and calculates and displays the largest value, the smallest value, and the average. So far, I have been able to get my code to read in the 10 grades and calculate and display the average, however I need help with the part that displays the largest value entered and the smallest value entered.
I believe I will be using if statements for that.
Thanks for your time and help
I'm definitely not giving you code, but I'll suggest a start.
Set max to 0 and min to something huge, like Integer.MAX_VALUE.
When you read each value, if it's larger than the max, set the max to that value. If it's smaller than the min, set the min to that value.
Have two local variables.
int high = 0, lo=Integer.MAX_VALUE;
as your reading in values.
if ( value > high ) high = value;
if ( value < low ) low = value;
I will definitely not provide you with code either, but I will offer an approach to how you can do it:
Create a double[] with a size of 10
Read in 10 decimal numbers and assign them at different indexes within the array (index 0 = first input number, index 1 = second input number, index 2 = third input number, etc...)
Calculate the average of the array (sum of all elements / size of array)
Sort the array (you should probably use bubble sort or Arrays#sort if you're allowed)
Depending on how you sort it, the smallest value will be at index 0 (or 9) and the largest value will be at index 9 (or 0)
Print out the appropriate information
Add all the grades to an int array, then use these functions i've made for you
//This will find the largest number in your int array
public static int largestNumber(int[] numbers){
int largest = numbers[0];
for(int i = 0; i < numbers.length - 1; i++){//for each number in the array
if(numbers[i] > largest){//Check if that number is larger than the largest int recorded so far
largest = numbers[i];//If that number is larger, record it to be the largest, and continue on to the next number
}
}
return largest;//After checking each number, return the largest in the array
}
//This will find the lowest number in your int array, it works the same way as the last function does
public static int lowestNumber(int[] numbers){
int lowest= numbers[0];
for(int i = 0; i < numbers.length - 1; i++){
if(numbers[i] < lowest){
lowest= numbers[i];
}
}
return lowest;
}
Hope this helps you out! :)
Assign the first element of the array as the max and min ..
Then start traversing the array , and compare it with the other array elements.
if(a[i]>max)
max=a[i]
if(a[i]<min)
min=a[i]
at the end of the loop , you will have your answer

How to get the highest and lowest value in the array in this code?

I need help to get the highest and lowest value in an array. I saw some people use Math.max and Math.min but how do you apply it? in this code?
import java.util.Scanner;
public class CaseStudy2A {
public static void main(String[] args) {
Scanner inp = new Scanner (System.in);
int inpNum;
System.out.print("Enter Number: ");
inpNum = inp.nextInt();
int num[]=new int [inpNum];
int y=0;
int accu;
for(int x=0;x<inpNum;x++) {
y=y+1;
System.out.print("\nNumber [" + y + "] : ");
accu = inp.nextInt();
num[x]=accu;
}
for(int x=0;x<inpNum;x++)
System.out.print(num[x] + " ");
}
}
If performance is irrelevant you could create a collection from the array and use collection max and min.
If you want to solve your homework by Math.* you could use this snippet:
int max= Integer.MIN_VALUE;
int min= Integer.MAX_VALUE;
for(int x=0;x<inpNum;x++){
max = Math.max(max,x);
min = Math.min(min,x);
I get the feeling this is homework... but there's a few ways of doing it. You can loop through each element in the array, store the first one you hit into a variable and then check each one after that to see if it's larger than the one currently stored. If it is, overwrite the variable with that one and continue. At the end you will have the largest one.
Another method would be to sort the array and then take the first and last element in it, giving you the largest and smallest.
[There was an attempt to edit my post, so I decided to improve it myself]
Introduce
int min=0, max=0;
then, after the first "for" loop, when all array values are known, do the following:
min=max=num[0];
for(int x=1; x<inpNum; x++) {
if(num[x]<min) {
min=num[x];
}
else if(num[x]>max) {
max=num[x];
}
}
This is faster than calling Math.min/max. Actually, this is the fastest way to compute both minimum and maximum since almost always you end up with less than 2n comparisons (where n is the array length), because when you find a new minimum you don't check for a new maximum. And that's why the ternary (?:) comparison is not used.
(You also have to check that inpNum is positive.)

Categories

Resources