Is there an algorithm to count array inversions in linear time? - c

I know that the number of inversions in an n-element array can be counted in O(n log(n)) operations using an enhanced merge sort.
However, I came across a different solution, which somehow manages to count the number of inversions in O(n) time, provided that the input is a permutation of (1, 2, 3, ..., n−1, n):
EDIT:-
I am sorry for the code I pasted as it doesn't work in all the cases . Actually this code was used for this question and it passed all the cases . But I am still leaving the code so that it may serve as some intuition and maybe a linear time solution for this problem will come up.
NOTE :- The Below Mentioned Code is Incorrect.
/* int in = 0;
for (int i = 0; i < n; i++) {
a[i] = a[i] - i - 1;
}
for (int i = 0; i < n; i++) {
if (a[i] > 0)
in = in + a[i];
else if (a[i] < -1)
in = in - a[i] - 1;
} */
Now the question is can we come up with a linear time solution for this problem ?

The obvious answer is that it doesn't. For example, for n = 4 and a = {2, 3, 4, 1}, you code gives the answer 5, even though the correct inversion count is clearly 3.

The approach is WRONG!
Consider the example below!
int a[] = { 2, 3, 1 };
int in = 0;
for (int i = 0; i < n; i++) {
a[i] = a[i] - i - 1;
}
// a[] = { 1, 1, -2 };
for (int i = 0; i < n; i++) {
if (a[i] > 0)
in = in + a[i];
else if (a[i] < -1)
in = in - a[i] - 1;
}
// in = 1 + 1 - (-1) = 3
The correct answer is 2 but it returns 3 here!

Related

Finding the max sum of n consecutive numbers where sum < k

I am given an array and asked to find the maximum possible sum of n consecutive numbers, where the maximum sum is less than a given value k.
For example:
array = {1, 3, 1, 2, 3, 4, 1}
k = 7
Here, the answer must be 6, because the max sum that we can obtain that is less than 7 is: arr[1] + arr[2] + arr[3] = 3 + 1 + 2 = 6
How can I write an algorithm to find such a value?
(I have done it with a nested for loop, but it takes too much time, is there any other way to make this program work?)
Basic Foundation
First off, I'd suggest you read up a bit more about time complexity. There are enough good resources out there, and Complexity Theory is one of them. This should help you understand why your solution is not fast enough.
O(n^3) Solution
A brute-force approach is to check all possible subarrays, by iterating over the start and end points of the subarray, and adding up all elements in between.
Given an array arr of size n, the way to do that would be as follows:
for (int l = 0; l < n; ++l) {
for (int r = l; r < n; ++r) {
long sum = 0;
for (int pos = l; pos <= r; ++pos) {
sum += arr[pos];
}
if (sum < k)
max = Math.max(max, sum);
}
}
The final answer is stored in max.
O(n^2) Solution
A faster solution would eliminate the third loop by making use of prefix sums. This can be done as follows, with the help of an auxiliary array preSum of the same size as the main array, where preSum[i] stores the sum of the first i elements:
preSum[0] = arr[0];
for (int i = 1; i < n; ++i)
preSum[i] = preSum[i - 1] + arr[i];
for (int l = 0; l < n; ++l) {
for (int r = l; r < n; ++r) {
long sum = preSum[r];
if (l > 0)
sum -= preSum[l - 1];
if (sum < k)
max = Math.max(max, sum);
}
}
O(n) solution
The most efficient solution to this problem uses a sliding window/two-pointer approach. Note that we assume that negative numbers are not allowed.
We start with both l and r at the beginning of the array. There are two possible cases at every stage:
Sum of the current subarray <k: We can be hopeful and try to add more elements to the subarray. We do this by moving r one step further to the right.
Sum of the current subarray >=k: We need to remove some elements to make the sum satisfy the given constraint. This can be done by moving l one step to the right.
This is repeated till we hit we need to increment r, but have reached the end of the array. The code looks something like this:
long max = 0;
int l = 0;
int r = 0;
long sum = arr[0];
while (true) {
if (sum >= k) {
sum -= arr[l];
++l;
} else {
if (r == n - 1)
break;
else {
++r;
sum += arr[r];
}
}
if (sum < k)
max = Math.max(max, sum);
}

Insertion Sort C programming

Since this year I'm starting studying C programming at university.
In particular today I was trying to understand the insertion sort.
I wrote this code that is perfectly working:
void insertionSort (int v[], int s)
{
int i;
int j;
int value;
for (i = 1; i < s; i++)
{
value = v[i];
for (j = i - 1; (j >= 0) && (value < v[j]); j --)
{
v[j + 1] = v[j];
}
v[j + 1] = value; // why v[j+1]?
}
}
My question is about the last code line: v[j + 1] = value. If I understand correctly, j (that decreases every time), at the end of the for cycle, has a value of -1 and that's why is correct to write v[j + 1] = value.
Am I right or am I missing something? Really thanks for anybody who wants to help me by explaining me better.
The way you have your code setup right now, you need v[j + 1] because j will always be one before where you want to insert.
For example:
int v[6] = {1, 34, 2, 50, 4, 10}
s = sizeof(v) / sizeof(v[0]) = 6
Stepping through your code:
i = 1, j = 0
value = v[i] = 34
34 < 1 is false so it doesn't go into the inner
for loop
v[j + 1] = 34 which is right where 34 should be
Looping your entire code a second time: value = 2, j = 1, i = 2
Both conditions are met where j = 1 && 2 < 34 and you go into your inner loop
Since you already stored v[2] earlier when you did value = v[i], v[2] = 34 at this point is where you decrease j by 1 making j = 0
Looking at your array, it looks like this:
1, 34, 34
The inner for loop will try to loop again but fail the second check
At this point, j is 0 and when you do v[j + 1] = value, you're storing value (2) in its proper place.
Your array at this point looks like 1, 2, 34
So again, the significance of v[j + 1] is to insert in the correct place. If the value is already in the correct place than you swap with itself.
This is the process of Insertion Sort. It will swap if the numbers are not ordered.
Over here you can find an visualized example: https://visualgo.net/en/sorting
Here you have an example in C:
#include <stdio.h>
int main()
{
int n, array[1000], c, d, t;
printf("Enter number of elements\n");
scanf("%d", &n);
printf("Enter %d integers\n", n);
for (c = 0; c < n; c++) {
scanf("%d", &array[c]);
}
// Insertion Sort
for (c = 1 ; c <= n - 1; c++) {
d = c;
while ( d > 0 && array[d] < array[d-1]) {
t = array[d];
array[d] = array[d-1];
array[d-1] = t;
d--;
}
}
printf("Sorted list in ascending order:\n");
for (c = 0; c <= n - 1; c++) {
printf("%d\n", array[c]);
}
return 0;
}
mark first element as sorted
for each unsorted element
'extract' the element
for i = lastSortedIndex to 0
if currentSortedElement > extractedElement
move sorted element to the right by 1
else: insert extracted element

Sort Even and Odd numbers in array while maintaining order

http://www.geeksforgeeks.org/segregate-even-and-odd-numbers/ I was looking up interview questions and came upon this interesting one. The algorithm seems simple enough but I was wondering if it was possible to maintain the order of the even and odd numbers while still maintaining the time complexity of O(n) without using any extra space.
For example
input: {12, 34, 45, 9, 8, 90, 3}
output: {12, 34, 8, 90, 45, 9, 3}
Edit: If it's not possible without extra space, can it work with the integers only rearranged in place? As in the swaps can only occur in the array
I think it's unlikely possible as without extra space (dependent on n) you'll have to swap elements and thus disorder them (or you can shift chunks in the array, but that would likely require non-linear overall time; using other data structures like linked lists is not allowed in the problem, as far as I understand).
This problem can be treated as stable in-place non-comparison sort where all even elements are mapped to zero and all odd elements are mapped to one for comparison, and it seems there's no algorithm that matches these criteria (stable, time O(n), extra memory O(1)) (see e.g. "Non-comparison sorts" table at https://en.wikipedia.org/wiki/Sorting_algorithm#Comparison_of_algorithms).
Yes It's possible. The Idea is to count total even numbers, then move odd numbers one by one to correct position.
public void segregateEvenOddWithOrder(int[] arr) {
int countEven = 0;
int length = arr.length;
for (int i = 0; i < length; i++) {
if (arr[i]%2 == 0){
countEven++;
}
}
int i = 0;
int j = i+1;
while (i != countEven){
if (arr[i]%2 == 0){
i++;
j = i + 1;
}else if (arr[i]%2 == 1 && j < length){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
j++;
}
}
}
This is my solution:
public static void segregateEvenOdd_Sorted_Optimized(int[] arr, int n) {
List<Integer> evenNums = new ArrayList<>();
List<Integer> oddNums = new ArrayList<>();
for (int i = 0; i < n; i++) {
if (arr[i] % 2 == 0) {
evenNums.add(arr[i]);
}
if (arr[i] % 2 == 1) {
oddNums.add(arr[i]);
}
}
Collections.sort(evenNums);
Collections.sort(oddNums);
for (int i = 0; i < evenNums.size() + oddNums.size(); i++) {
if (i < evenNums.size()) {
arr[i] = evenNums.get(i);
} else {
arr[i] = oddNums.get(i - evenNums.size());
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}

Design the binomial coefficient algorithm using a single dimensional array

I have already designed the following algorithm that determines the binomial coefficient using a two dimensional array. For example, to calculate the binomial coefficient of n choose k, we can create a two dimensional array like so:
int[][] arr = new int[n][k];
We can populate the array in the following way:
for(int i = 0; i <= n; i++){
for(int j = 0; j <= minimum(i, k); j++){
if(j == 0 || i == j){
arr[i, j] = 1;
} else{
arr[i, j] = arr[i - 1, j - 1] + arr[i - 1, j];
}
}
}
However, I need to redesign this algorithm to use a one dimensional array from indexes 0-k. I am having a lot of trouble pinpointing how to do this. I have started in small steps, and realized some common occurrences:
If k = 0, arr[0] will be 1, and that will be returned regardless of n.
If k = 1, arr[0] will be 1, arr[1] should be n, if I'm designing it in a loop.
When I say k = 2, this is where it gets tricky, because the value of arr[2] will really depend on the previous values. I believe that as I loop (say from i = 0 to i = n), the values of arr[] will change but I can't quite grasp how. I've started with something along these lines:
for(int i = 0; i <= n; i++){
for(int j = 0; j <= minimum(i, k); j++){
if(j == 0 || i == j){
arr[j] = 1;
} else if(j == 1){
arr[j] = i;
} else{
arr[j] = ??; // I can't access previous values, because I didn't record them?
}
}
}
How should I handle this?
Here is a code which uses only one one dimensional array:
int[] coefficients = new int[k + 1];
coefficients[0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = k; j >= 1; j--) {
coefficients[j] += coefficients[j - 1];
}
}
Why is it correct? To compute coefficients[j] for a fixed i, we need to know the value of coefficients[j - 1] and coefficients[j] for i - 1. If we iterate from k down to 0, we can safely record a new value for the current position because we will never need its old value.

Strange C function - What is this function doing?

I encountred this function without any comment. I wonder what is this function doing? Any help?
int flr(int n, char a[])
{
#define A(i) a[((i) + k) % n]
int l[n], ls = n, z[n], min = 0;
for (int i = 0; i < n; i++)
{
l[i] = i;
z[i] = 1;
}
for (int k = 0; ls >= 2; k++)
{
min = l[0];
for (int i=0; i<ls; i++) min = A(l[i])<A(min) ? l[i] : min;
for (int i=0; i<ls; i++) z[A(l[i])!=A(min) ? l[i] : (l[i]+k+1)%n] = 0;
for (int ls_=ls, i=ls=0; i<ls_; i++) if (z[l[i]]) l[ls++] = l[i];
}
return ls == 1 ? l[0] : min;
}
What a fun problem!
Other posters are correct that it returns the index of a minimum, but it's actually more interesting than that.
If you treat the array as being circular (i.e. when you get past the end, go back to the beginning), the function returns the starting index of the minimum lexicographic subsequence.
If only one element is minimal, that element is returned. If multiple elements are minimal, we compare the next element along from each minimal element.
E.g. with an input of 10 and {0, 1, 2, 1, 1, 1, 0, 0, 1, 0}:
There are four minimal elements of 0, at indices 0, 6, 7 and 9
Of these two are followed by a 1 (the 0 and 7 elements), and two are followed by a 0 (the 6 and 9 elements). Remember that the array is circular.
0 is smaller than 1, so we only consider the 0s at 6 and 9.
Of these the sequence of 3 elements starting at 6 is '001' and the sequence from 9 is also '001', so they're still both equally minimal
Looking at the sequence of 4 elements, we have '0010' from element 6 onwards and '0012' from element 9 onwards. The sequence from 6 onwards is therefore smaller and 6 is returned. (I've checked that this is the case).
Refactored and commented code follows:
int findStartOfMinimumSubsequence(int length, char circular_array[])
{
#define AccessWithOffset(index) circular_array[(index + offset) % length]
int indicesStillConsidered[length], count_left = length, indicator[length], minIndex = 0;
for (int index = 0; index < length; index++)
{
indicesStillConsidered[index] = index;
indicator[index] = 1;
}
// Keep increasing the offset between pairs of minima, until we have eliminated all of
// them or only have one left.
for (int offset = 0; count_left >= 2; offset++)
{
// Find the index of the minimal value for the next term in the sequence,
// starting at each of the starting indicesStillConsidered
minIndex = indicesStillConsidered[0];
for (int i=0; i<count_left; i++)
minIndex = AccessWithOffset(indicesStillConsidered[i])<AccessWithOffset(minIndex) ?
indicesStillConsidered[i] :
minIndex;
// Ensure that indicator is 0 for indices that have a non-minimal next in sequence
// For minimal indicesStillConsidered[i], we make indicator 0 1+offset away from the index.
// This prevents a subsequence of the current sequence being considered, which is just an efficiency saving.
for (int i=0; i<count_left; i++){
offsetIndexToSet = AccessWithOffset(indicesStillConsidered[i])!=AccessWithOffset(minIndex) ?
indicesStillConsidered[i] :
(indicesStillConsidered[i]+offset+1)%length;
indicator[offsetIndexToSet] = 0;
}
// Copy the indices where indicator is true down to the start of the l array.
// Indicator being true means the index is a minimum and hasn't yet been eliminated.
for (int count_before=count_left, i=count_left=0; i<count_before; i++)
if (indicator[indicesStillConsidered[i]])
indicesStillConsidered[count_left++] = indicesStillConsidered[i];
}
return count_left == 1 ? indicesStillConsidered[0] : minIndex;
}
Sample uses
Hard to say, really. Contrived example: from a circular list of letters, this would return the index of the shortest subsequence that appears earlier in a dictionary than any other subsequence of the same length (assuming all the letters are lower case).
It returns the position of the smallest element within the substring of a ranging from element 0..n-1.
Test code
#include <stdio.h>
int flr(int n, char a[])
{
#define A(i) a[((i) + k) % n]
int l[n], ls = n, z[n], min = 0;
for (int i = 0; i < n; i++)
{
l[i] = i;
z[i] = 1;
}
for (int k = 0; ls >= 2; k++)
{
min = l[0];
for (int i=0; i<ls; i++) min = A(l[i])<A(min) ? l[i] : min;
for (int i=0; i<ls; i++) z[A(l[i])!=A(min) ? l[i] : (l[i]+k+1)%n] = 0;
for (int ls_=ls, i=ls=0; i<ls_; i++) if (z[l[i]]) l[ls++] = l[i];
}
return ls == 1 ? l[0] : min;
}
int main() {
printf(" test 1: %d\n", flr(4, "abcd"));
printf(" test 3: %d\n", flr(6, "10e-10"));
printf(" test 3: %d\n", flr(3, "zxyghab");
printf(" test 4: %d\n", flr(5, "bcaaa"));
printf(" test 5: %d\n", flr(7, "abcd"));
return 0;
}
This code gives following output:
[root#s1 sf]# ./a.out
test 1: 0
test 2: 3
test 3: 1
test 4: 2
test 5: 4
1. 0 is the position of `a` in the first case
2. 3 is the position of `-` in second case.
3. 1 is the position of `x` in third case.
4. 2 is the position of the second `a`.
5. 4 is the position of the `\0`
So the function returns the position of smallest element of a character pointer pointed by a and it will consider n elements. (Thats why it returned the position of x in the third case).
But when multiple smallest element available, it does not seems to be work in a predictable way, as it does not return the first occurrence, nor the last.
It should do a error checking for out of bound cases. Which may lead to problem in future.
so i'm running tests on this.
int flr(int n, char a[])
{
#define A(i) a[((i) + k) % n]
int l[n], ls = n, z[n], min = 0;
for (int i = 0; i < n; i++)
{
l[i] = i;
z[i] = 1;
}
for (int k = 0; ls >= 2; k++)
{
min = l[0];
for (int i=0; i<ls; i++) min = A(l[i])<A(min) ? l[i] : min;
for (int i=0; i<ls; i++) z[A(l[i])!=A(min) ? l[i] : (l[i]+k+1)%n] = 0;
for (int ls_=ls, i=ls=0; i<ls_; i++) if (z[l[i]]) l[ls++] = l[i];
}
return ls == 1 ? l[0] : min;
}
int main()
{
int in = 10;
char array[] = {0, 1, 1, 1, 1, 1, 0, 1, 1, 0};
int res = flr(in, array);
printf("expecting res to be 6;\tres = %d\n", res);
system("pause");
return 0;
}
output was res=9;

Resources