Given an array of integers. Find the Inversion Count in the array - java

I tried to solve this problem but I,m getting the Wrong Answer
Inversion Count: For an array, inversion count indicates how far (or close) the array is from being sorted. If the array is already sorted then the inversion count is 0. If an array is sorted in the reverse order then the inversion count is the maximum.
Formally, two elements a[i] and a[j] form an inversion if a[i] > a[j] and i < j.
enter link description here
class Solution
{
// arr[]: Input Array
// N : Size of the Array arr[]
//Function to count inversions in the array.
static long count = 0;
static long inversionCount(long arr[], long n)
{
// Your Code Here
long merged[] = mergeSort(arr, 0, n - 1);
return count;
}
static long[] merge(long left[], long right[])
{
long res[] = new long[left.length + right.length];
long i = 0, j = 0, k = 0;
while (i < left.length && j < right.length)
{
if (left[(int)i] <= right[(int)j])
{
res[(int)k] = left[(int)i];
k++;
i++;
}
else
{
count = count + (left.length - i);
res[(int)k] = right[(int)j];
k++;
j++;
}
}
while (i < left.length)
{
res[(int)k] = left[(int)i];
i++;
k++;
}
while (j < right.length)
{
res[(int)k] = right[(int)j];
k++;
j++;
}
while (i < left.length)
{
res[(int)k] = left[(int)i];
i++;
k++;
}
return res;
}
static long[] mergeSort(long a[], long lo, long hi)
{
if (hi == lo)
{
long temp[] = {a[(int)hi], };
return temp;
}
long mid = (hi + lo) / 2;
long left[] = mergeSort(a, lo, mid);
long right[] = mergeSort(a, mid + 1, hi);
long merged[] = merge(left, right);
return merged;
}
}

As gfg uses many test cases to check your code , the answer that you get on the first test cases gets hold to the static variable(count) and will never be reset.
So only the first test case will be correct and the rest of the test cases gets the wrong answer.
So try declaring the count variable outside the method and initiate it within the method.Whenever a new test case is executed your count variable will be reset to zero.
static long count;
static long inversionCount(long arr[], long n)
{
// Your Code Here
count = 0;
long merged[] = mergeSort(arr, 0, n - 1);
return count;
}

Related

I am trying out to do the "Count Reverse Pairs" and I can't understand why parentesis() are necessary on this line

I know that addition is commutative therefore I want to perform a storing operation with shorthand operation += at line 46 but the answer differs only when I put the parenthesis, also when when I don't put parenthesis I get wrong answer.
The line is in the merge function.
CODE:
public class ProblemA {
public static void main(String[] args) {
ArrayList<Integer> arr = new ArrayList<Integer> (Arrays.asList(1, 3, 2, 3, 1));
int n = arr.size();
//calling mergesort
int total = countPair(arr, n);
System.out.println(total);
}
public static int countPair(ArrayList<Integer> arr, int n) {
int total = mergeSort(arr, 0, n - 1);
return total;
}
public static int mergeSort(ArrayList<Integer> arr, int low, int high) {
//termination condition
if (low >= high) return 0;
//firstly we'll disassociate the elements of array on elementary level
int mid = (low + high) / 2;
//we'll store our count value inside the counter variable
int inv = mergeSort(arr, low, mid);
inv += mergeSort(arr, mid + 1, high);
inv += merge(arr, low, mid, high);
return inv;
}
public static int merge(ArrayList<Integer> arr, int low, int mid, int high) {
//AIM: make a double loop and traverse through the elements and increase the right side pointer
//whenever condition (arr[i]>2*arr[j] is satisfied)
//int i = 0;
int total = 0;
int j = mid + 1;
for (int i = low; i<= mid; i++) {
//looping till we run out the right hand side or condition is not satisfied
while (j<= high && arr.get(i) > 2 * arr.get(j)) {
j++;
} **
* total += (j - (mid + 1)); ** * //parenthesis error here
}
//Now we can move to merging part
ArrayList<Integer> temp = new ArrayList<Integer> ();
int left = low, right = mid + 1;
while (left<= mid && right<= high) {
if (arr.get(left)<= arr.get(right)) {
temp.add(arr.get(left++));
} else {
temp.add(arr.get(right++));
}
}
//for the last right or left remaining element
while (left<= mid) {
temp.add(arr.get(left++));
}
while (right<= high) {
temp.add(arr.get(right++));
}
//now we can copy the remaining elements from temp list to arr
for (int i = low, k = 0; i<= high; i++) {
arr.set(i, temp.get(k++));
}
return total;
}
}
OUTPUT(with parenthesis) "total += (j-(mid+1))":
2
OUTPUT(without parenthesis) "total += j-mid+1":
16
This is happening because if you use parenthesis, java will decide which expression you want to evaluate first. If you don't use parenthesis then everything goes executed from left to right.
Example:
int total=1;
int total1=1;
int total2=1;
total+=total1-total2+1;
System.out.println(total);
Output : 2
The reason is here, expression got evaluated as total=total+total1-total2+1;
i.e. total=1+1-1+1=2;
For parenthesis based expression, it gets evaluated first & then others:-
int total=1;
int total1=1;
int total2=1;
total+=(total1-(total2+1));
System.out.println(total);
Output : 0 , evaluation will happen like below :-
total=total+(1-(1+1));
total=1+(1-(2));
total=1+(-1);
total=0;
Reference : https://docs.oracle.com/javase/tutorial/java/nutsandbolts/expressions.html

Why this merge procedure is slightly slower?

Recently I was testing two variations of the merge method in Mergesort and one turns our to be slightly faster than the other. For a large enough input (say, an array of 10-100 million or more randomly ordered elements), one merge method takes around 100ms longer than the other.
Here's the one taking more time:
private static void merge(int[] a, int low, int mid, int hi) {
int temp[] = new int[(hi - low) + 1];
int cLeft = low;
int cRight = mid + 1;
int cTemp = 0;
while (cLeft <= mid && cRight <= hi) {
if (a[cLeft] <= a[cRight]) {
temp[cTemp++] = a[cLeft++];
} else {
temp[cTemp++] = a[cRight++];
}
}
//copy the remaining left elements to the right end
System.arraycopy(a, cLeft, a, low + cTemp, mid - cLeft + 1);
//copy temp to a
System.arraycopy(temp, 0, a, low, cTemp);
}
...and this is the faster one
private static void merge(int[] list, int lowIndex, int midIndex, int highIndex) {
int[] L = new int[midIndex - lowIndex + 2];
for (int i = lowIndex; i <= midIndex; i++) {
L[i - lowIndex] = list[i];
}
L[midIndex - lowIndex + 1] = Integer.MAX_VALUE;
int[] R = new int[highIndex - midIndex + 1];
for (int i = midIndex + 1; i <= highIndex; i++) {
R[i - midIndex - 1] = list[i];
}
R[highIndex - midIndex] = Integer.MAX_VALUE;
int i = 0, j = 0;
for (int k = lowIndex; k <= highIndex; k++) {
if (L[i] <= R[j]) {
list[k] = L[i];
i++;
} else {
list[k] = R[j];
j++;
}
}
}
Both variations of MergeSort are given different arrays of same length with same elements at identical positions as their input. In other words, input of one algorithm is a copy of input of the other.
Although the difference in running time is negligible (the average running time doesn't change, i.e. remains 100ms, no matter how much we increase the size after 1 million mark.), I am eager to know what makes the faster merge faster. For me, the former method is cleaner and easier to implement. However, if the other one remains faster, I probably will switch to that.

Given an array and a sum, find the max length continous subarray less than the sum

I have an array[1,2,3] and sum as 4. so all the continous sub arrays are [1],[1,2][2,3] ans [1,2,3]. So the max length subarray less than or equal to sum is [1,2]and the length is 2.
I have approached in a the following way to find all the subarrays and to check the sum of the subarrays as below. But this approach is not working with negative numbers.
{1,2,1,1,3,-2,-3,7,9}; - Ans : 7
private static void maximumSubArray(int[] a, int sum) {
int start = 0;
int end =0;
int mylen =-1;
int subarrSum =0;
for(int i=0;i<a.length;i++){
subarrSum += a[i];
end++;
while(subarrSum > sum){
subarrSum-= a[start];
start +=1;
}
mylen = Math.max(mylen, end-start);
}
System.out.println(mylen + " -- My len");
}
This is a variation of the classical maximum contiguous subarray problem. You can use dynamic programming (memorization) to solve this problem. Try something like this:
private static void maximumSubArray(int[] a, long sum, int maxLen) {
long maximumSoFar = Long.MIN_VALUE;
long maximumEndingHere = Long.MIN_VALUE;
for (int i = 0; i < a.length; i++) {
// if you're inside the array beyond maxLen, start dropping off the previous start element
int prevStart = i >= maxLen ? a[i - maxLen] : 0;
maximumEndingHere = Math.max(a[i], maximumEndingHere + a[i] - prevStart);
if (maximumEndingHere > maximumSoFar && maximumEndingHere <= sum) {
maximumSoFar = maximumEndingHere;
} else if (a[i] > maximumSoFar && a[i] <= sum) {
maximumSoFar = a[i];
} else if (maximumEndingHere > sum) {
maximumEndingHere -= prevStart;
}
}
System.out.println(maximumSoFar);
}
If I had some more time, I'd write the logic inside for loop in a cleaner way, but this should work and it works in O(n) time.

Need assistance JAVA quicksort recursion

For school I have to write a quicksort for an Array of strings. I think my partition is good but I keep getting error with the recursion.
public static int partition(String[] input, int max) {
// pivot is dividing point
// I keeps track of lesser values
// count is just a counter
// Pivots in place
int pivot = 0;
int i = 1;
int count = 1;
while (count <= max) {
if (input[count].compareTo(input[pivot]) < 0) {
input[i] = input[count];
i = i + 1;
}
if (count == max) {
input[i] = input[pivot];
input[pivot] = input[i];
}
count++;
}
return pivot;
}
public static void qSort(String[] input) {
int index = partition(input, input.length - 1);
int count = 0;
if (count < index - 1) {
partition(input, index - 1);
}
if (index + 1 < count && count < input.length) {
partition(input, input.length - 1);
}
count++;
}
Your implementation has a lot of mistakes. First of all, you're always choosing the pivot to be the element at index 0 of the array. The idea of quicksort is that you choose some pivot, partition the array around it, then recursively apply quicksort on both partitions around the chosen pivot. How do you identify the start and end of the partitions you'll call quicksort recursively on? You need to pass those as arguments to your partition method as others have mentioned in the comments, same thing for the quicksort method itself.
public void swap (String [] array, int i, int j) {
String tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
public static int partition (String [] array, int low, int high) {
String pivot = array[low];
int index = low+1;
for (int i = low+1; i <= high; i++) {
if (pivot.compareTo(array[i]) > 0) {
swap(array, i, index);
index++;
}
}
swap(array, low, index-1);
return index-1;
}
public static void qsort(String [] array, int low, int high) {
if (low < high) {
int p = partition(array, low, high);
qsort(array, low, p);
qsort(array, p+1, high);
}
}
Obviously this isn't the best way to choose the pivot as some arrays will make the algorithm perform very poorly. A better method would be to use a random pivot each time.

Converting a Java Method into a recursive method? (insertion sort)

I'm trying to understand recursion and how to turn my currently iterative insertion sort into a recursive one.
What would I need to do to my code to make it recursive?
I think I need a base case so it doesn't become an infinite loop.
I'm not sure I entirely understand recursion. Maybe you can make it clearer for me?
I've done a lot of reading but I still don't know where to start.
Here is my code:
public class InsertionSort
{
public static void main(String a[])
{
int i;
int array[] =
{ 8, 33, 12, 99, 0, 17 };
System.out.println("Values of Array before the sort: ");
for (i = 0; i < array.length; i++)
{
System.out.print(array[i] + " ");
}
insertion_srt(array, array.length);
System.out.println("");
System.out.println("Values of Array after the sort: ");
for (i = 0; i < array.length; i++)
{
System.out.print(array[i] + " ");
}
}
public static void insertion_srt(int array[], int n)
{
for (int i = 1; i < n; i++)
{
int j = i;
int B = array[i];
while ((j > 0) && (array[j - 1] > B))
{
array[j] = array[j - 1];
j--;
}
array[j] = B;
}
}
}
This is great approach I personally likes. It does use three methods but they're very simple to understand. Think of the insertionOut as the outer for loop and the insertionIn as the inner nested for loop
public static void insertionRecursive(int[] a){
if(a.length > 0){ // base case
insertionOut(a, 1, a.length);
}
}
private static void insertionOut(int[] a, int i, int length){ //outer loop
if(i < length){ // iterates from 1 to the length
int temp = a[i]; // temp value
int k = i;
insertionIn(a, k, temp);
insertionOut(a, i + 1, length); // iterates through the loop
}
}
private static void insertionIn(int[] a, int k, int temp){ // inner loop
if(k > 0 && a[k - 1] > temp){
//this does a basic swap
a[k] = temp;
a[k] = a[k - 1];
a[k - 1] = temp;
insertionIn(a, k - 1, temp); // iterates through the loop
}
}
Transforming the outer for loop is kind of trivial. To overcome the while loop you need a little recursive helper function. You have to call the function in your main as insertion_srt(array, 0, array.length):
public static void insertion_srt(int array[], int beg_index, int n) {
if(beg_index >= n-1)
return;
int i = beg_index + 1;
int j = i;
int B = array[i];
j=helper(array, j, B);
array[j] = B;
insertion_srt(array, beg_index + 1, n);
}
private static int helper(int[] array, int j, int B) {
if(j <= 0 || array[j-1] <= B)
return j;
array[j] = array[j - 1];
return helper(array, j-1, B);
}
A good way to understand how recursion works is to understand the concept of Divide and conquer algorithm. This technique is a basis of efficient algorithms for all kinds of problems.
The idea behind it is to divide a problem into smaller subproblems that can all be solved in the same way:
Divide into 2 (or more) subproblems.
Solve each subproblem recursively.
Combine the results.
Insertion sort is not the best example of a divide and conquer algorithm, but it can still be approached this way. You can divide the problem into 2 subproblems:
last element
everything else
This way you will obtain so called tail recursion. All loops are relatively easy to transform into tail recursions.
public static void insertion_srt(int array[], int n, int j) {
if (j < n) {
int i;
int temp = array[j];
for (i=j; i > 0 && array[i-1] > temp; i--) array[i] = array[i-1];
array[i] = temp;
insertion_srt(array,n, j+1);
}
}
Try this simple recursive approach:
public static void insertionSort(int[] array, int index) {
if(array.length == index + 1) return;
insertionSort(array, index + 1);
// insert array[index] into the array
}

Categories