Java - Comparing a long list of integers - java

My code is timing out as it is inefficient. Program takes in a line of n integers. Each consecutive pair of integers represents a single point (x, y)
this is an example of input :
-5 -10 20 25 30 2 -1 -40
Output:
java.awt.Point[x=-5,y=-10]
java.awt.Point[x=-1,y=-40]
java.awt.Point[x=20,y=25]
java.awt.Point[x=30,y=2]
4
I have the code to sort all the points. They are sorted from smallest to biggest. Where "x" values are equal, I then check the y value.
The PROBLEM is this: I need to count how many times a point is bigger than every other point (both x and y). So in the above example, the answer is 4.
The fourth point is bigger than the first and second point.
The third point is bigger than the first and second.
Which results in 4.
If points are equal, also increase the counter.
For really really longer line of integers, my program times out (killed). I can't provide the input here as it is way too long. How else can I improve the complexity?
public void calculateDomination(){
int counter =0;
int sizeOfList = this.coordinateList.size();
for(int i = 0; i < sizeOfList ; i++){
for(int j = i+1; j < sizeOfList ; j++){
if(((this.coordinateList.get(i).x) < (this.coordinateList.get(j).x)) && ((this.coordinateList.get(i).y) < (this.coordinateList.get(j).y)) ){
counter++;
}
else if(((this.coordinateList.get(i).x) == (this.coordinateList.get(j).x)) && ((this.coordinateList.get(i).y) == (this.coordinateList.get(j).y)) ){
counter++;
}
}
}
System.out.println(counter);
}

The first idea I posted, now removed, would not actually work. The one that does work:
Use an incremental sorting/counting of encountered y values:
As you go through the list, maintain a TreeMultiset of all the y values encountered so far. At each point, check the size() of the headMultiset() of nodes before the current y value. Since only values from points with lower x values will have been added to it yet, that will give you the current point's count.
I think all involved operations of TreeMultiset are O(log(n)), so this will drop your algorithm from O(n^2) to O(n * log(n)).

Related

How can I utilize merge sort approach to reduce running time of my program

I have a function that takes in an int[] array with the expectation that all elements are sorted from largest to smallest.
I want to find how many pairs violate this expectation ( a larger element x in the array is present AFTER a smaller element x + array.length() while not going out of bounds)
For instance,
if array = [7,3,5,4,1] the answer would be 2 because the pairs that violate the order are 3 and 5 and 3 and 4, since 3 is smaller than them and should've been ahead of them.
Here is my current code:
public static int countBad(int[] array){
int counter = 0;
for (int x = 0; x < array.length; x++){
for (int y = x + 1; y <= x + array.length && y < array.length; y++){
if(array[x] < array[x+y]){
counter++;
}
}
}
return counter;
}
Even though my code works, it is extremely inefficient, which is why I wish to reduce the time complexity. I've been told about a merge sort approach to this issue. However, I'm struggling to grasp how to convert my existing method into a merge sort approach.
Can anyone please help explain how to do this?

Minimal calls to subArrayLeftShift method for sorting array (interview question)

Suppose you have a method subArrayLeftShift(a,i) which shifts left the sub array a[i,...,n-1] when n is the array length. That means that the elements a[i+1],...,a[n-1] are moving one place to the left, and the original a[i] will become the last one.
More formally, here is the function implementation:
public static void subArrayLeftShift(int[] a, int i){
if (a.length == 0) return;
int last = a.length - 1;
int insertToLast = a[i];
for (; i < last; i++){
a[i] = a[i + 1];
}
a[last] = insertToLast;
}
Now for the question: implement a function that receives an unsorted array, and returns the minimal number of calls to subArrayLeftShift for sorting the array.
In the interview I couldnt find the way to do it. I succeed to find the minimal number of calls for every example I wrote for intuition, but couldn't find a way for generalizing it.
Do you know how to solve it?
I propose the following algorithm to solve the problem:
Find the minimum number in the array that is not sorted ( has a smaller number on the right in the array). Let this number be x.
Count how many numbers in the array are greater than the previously found number x. Let this number be y.
Since for each call to the function, the unsorted number will end up at the last position, the optimum strategy is to call the function for each unsorted number in increasing order. Using what was found previously we start with x. We continue with the next unsorted number bigger than x, because in this way, it will end up on the right of x, hence it will be sorted. Continue in the same fashion. How much? How many bigger number than x we have? Well, that's y. So as a total, the number of calls to the function is 1 + y.
public static int minimumCalls(int[] a) {
int minCalls = 0;
for (int i = 0; i < a.length - 1; i++) {
for (int j = i+1; j < a.length; j++) {
if (a[i] > a[j]) {
minCalls++;
break;
}
}
}
return minCalls;
}
The idea behind my thinking is that you must invoke the method once whenever there exists in the SubArray any value less than the current i. The name of the method subArrayShiftLeft, i feel, is designed to throw you off and drag your attention away from thinking of this easily.
If there's any values less than the current one further on in the array, just invoke the method.
It's much easier to think of this as moving a single larger value to the end of the array than trying to shift the smaller ones to the left.

How to write this algorithm more efficiently

I have an assignment where I have to write an algorithm which 'splits' the array in two. Left side should be odd numbers, and right side should be even numbers. Both sides should be sorted in ascending order. I'm not allowed to use temp arrays or existing api.
I have managed to make a working method, problem is with an array of say 100 000 integers, it takes approximately 15 seconds to finish. The requirement is 0,1 seconds, so I obviously have a lot to improve. I'm not looking for someone to spoon-feed me the answer, just a nudge in the right direction. Please don't write any working code for me, though I would like to know if and why something I've written is bad!
What I have so far:
public static void delsortering(int[] a){
int oddnum = 0;
int n = a.length;
for(int k : a){ //finds how many odd numbers there are
if((k & 1) != 0) oddnum++;
}
for(int i = 0; i < n; i++){
if((a[i] & 1) != 0){ //finds odd numbers
for(int j = 0; j < n; j++){
if((a[j] & 1) == 0) //looks for even numbers to change pos with
switch(a, j, i);
}
}
}
for (int i = 0; i < n; i++){
int from = i < oddnum ? 0 : oddnum;
int to = i < oddnum ? oddnum - i: n - i + oddetall;
int m = maxValue(a, from, to); //finds max value in specified range
switch(a, m, to - 1); //puts said max value at specified index
}
}
Appreciate all the help I can get!
A better solution would be:
Firstly keep two variables that point to the first and last elements of the array e.g x=0; y=N-1.
Then start moving x to the right until you find an even number (all numbers until now are odd !!!), then start moving y to the left until you find an odd number (all number you examine while decreasing-moving left y are even until the first one odd you find !!!)
Swap values x,y ,increase x,y and repeat the same procedure until x,y get crossed.
Then you have the array with evens on the right and odd on the left but not ordered. So you could count during the above procedure the number of odds and evens in order to know where there are separated in the array let's say in k index.
Sort array[0 - k], Sort array[k+1 - N].
Complexity: O(n) for the first part (x,y are only once moving to one direction) and O(nlogn) for both sorts so O(nlogn) which is better than O(n^2) that is your solution.

What is this algorithm doing?

I got a pseudocode:
Input: Array A with n (= length) >= 2
Output: x
x = 0;
for i = 1 to n do
for j = i+1 to n do
if x < |A[i] - A[j]| then
x = |A[i] - A[j]|;
end if
end for
end for
return x;
I have converted that to a real code to see better what it does:
public class Test
{
public static void main (String[] args)
{
int A[] = {1,2,3,4,5,6,7,8,9};
int x = 0;
for (int i = 1; i < A.length; i++)
{
for (int j = i + 1; j < A.length; j++)
{
if (x < Math.abs(A[i] - A[j]))
{
x = Math.abs(A[i] - A[j]);
}
}
}
System.out.println(x);
}
}
The output was 7 with the array in the code.
I have used another array (1 to 20) and the putput was 18.
Array 1-30, the output was 28.
The pattern seems clear, the algorithm gives you the antepenultimate / third from last array value. Or am I wrong?
I think the pseudo code tries to find the greater of the difference between any 2 elements within an array.
Your real code however, starts from 1 instead of 0 and therefore excludes the first element within this array.
I think pseudocode is trying to find the greatest difference between two numbers in an array. It should be the difference between the minimum and maximum value of the array.
I personally think this is a really poor algorithm since it is doing this task in O(n^2). You can find the min and maximum value of an array in O(n). and take the difference between those numbers and result will be the same. check the pseudocode
Input: Array A with n (= length) >= 2
min=A[0];max = A[0];
for i = 1 to n do
if min > A[i] then
min = A[i];
end if
if max < A[i] then
max = A[i]
end if
end for
return (max-min);
The code gives the biggest difference between any two elements in the array.
There are 2 nested loops, each running over each element of the array. The second loop starts at the element after the first loop's element, so that each possible pair is considered only once.
The variable x is the current maximum, initialized to 0. If x is less than the absolute value of the current pair's difference, then we have a new maximum and it is stored.
However, because you directly copied the pseudocode's starting index of 1, you are inadvertently skipping the first element of the array, with index 0. So your Java code is giving you the maximum difference without considering the first element.
If you have an array of values between 1 and n, you are skipping the 1 (in index 0) and the returned value is n - 2, which happens to be the third-to-last value in the array. If you had shuffled the values in the array as a different test case, then you would see that the returned value would have changed to n - 1 as now both 1 and n would be considered (as long as n itself wasn't in the first position).
In any case, you would need to set the index of the first element to 0 so that the first element is considered. Then {1,2,3,4,5,6,7,8,9} would yield 8 (or any other order of those same elements).
Assuming all positive integers, the algorithm in a nutshell finds the difference between the maximum and the minimum value in the array. However, it will not work correctly unless you initialize i to 0 in the for loop.
for (int i = 0; i < A.length; i++)

Finding a minmuim swaps in an array

I have found a problem on a net for generating some sequence.
A = [A1, A2, ..., AN]
and
where A1 < A2 < ... < Am > Am+1 > ... > AN for some index m, with m between 1 and N inclusive).
I want to find the minimum swaps to accomplish this
For Ex
1 8 10 3 7
Swap between 3 and 7 will give me the required seq.
Ans=1
I found this code in the editorial:
boolean[] done = new boolean[n];
for(int i=0;i<n;i++) {
int index = -1;
for(int j=0;j<n;j++) {
if(!done[j] && (index == -1 || values[j] < values[index]))
index = j;
}
int left = 0, right = 0;
for(int j=0;j<index;j++)
if(!done[j])
left++;
for(int j=index+1;j<n;j++)
if(!done[j])
right++;
res += Math.min(left, right);
done[index] = true;
}
return res;
I can't understand the code what its doing How can i found the minimum swap ? Is this a standard algorithm question.And time complexity is O(n^2) is this good.
(Note: swap seems to mean swap of two adjacent elements.)
The idea behind the code is as follows. The minimum element x must be moved either to the first or last position in the array. The number of swaps to move x does not depend on which swaps not involving x are performed. For every valid solution, the swaps not involving x are a solution for the array with x removed. Thus, there exists an optimal solution that moves x to the first or last position and then recursively deals with the remaining elements.
The structure of the code is to find the minimum unprocessed element (inner loop 1; done[j] is a flag indicating whether the element at position j has been processed), determine how many swaps are needed to move it to the first position (inner loop 2), and determine how many swaps are needed to move it to the last position (inner loop 3). We don't count swaps over processed elements because, when we're moving the current element, those elements already have been moved out of the way.
The running time could be improved to O(n log n) by substituting merge sort for the implicit selection sort and using a Fenwick tree to count the number of unprocessed elements in a range.

Categories