简体   繁体   中英

Counting the number of inversions in a vector

Background Information:

This is a daily coding problem from Google.

We can determine how "out of order" an array A is by counting the number of inversions it has. Two elements A[i] and A[j] form an inversion if A[i] > A[j] but i < j.That is, a smaller element appears after a larger element.

Given an array, count the number of inversions it has.Do this faster than O(N ^ 2) time.

You may assume each element in the array is distinct.

For example, a sorted list has zero inversions.The array[2, 4, 1, 3, 5] has three inversions: (2, 1), (4, 1), and (4, 3).The array[5, 4, 3, 2, 1] has ten inversions : every distinct pair forms // an inversion.

Brute force solution:

auto num_inversions(std::vector<int>& nums)
{
    int count = 0;
    for (int i = 0; i <= nums.size(); ++i)
    {
        for (int j = i + 1; j < nums.size(); ++j)
        {
            if (nums[i] > nums[j])
                ++count;
        }
    }
    return count;
}

Potential better solution idea:

My idea is to use a priority_queue to achieve this something like this:

auto num_inversions1(std::vector<int>& nums)
{
    auto compare = [](int lhs, int rhs)
    {
        return lhs > rhs;
    };
    std::priority_queue<int, std::vector<int>, decltype(compare)> q(compare);
    for (auto num : nums)
        q.push(num);
    print_queue(q);
}

Now if I know how many times the compare lambda was used then I think that will determine the number of inversions I had. Is it possible to count the number of times the lambda expression was used in the priority queue? If so, would this approach work?

Update:

Following the advice from the link provided without looking at the answer too much besides one modifying mergesort I tried it out but I am not getting the correct result.

Here is my code:

#include <iostream>
#include <vector>

int merge(std::vector<int>& data, std::vector<int>& temp, int low, int middle, int high) {

    // create a temporary array ... O(N) memory complexity !!!      
    // copy the data to a temporary array 
    for (int i = low; i <= high; i++) {
        temp[i] = data[i];
    }

    int i = low;
    int j = middle + 1;
    int k = low;

    int inv_count = 0;
    // Copy the smallest values from either the left or the right side back
    // to the original array
    while ((i <= middle) && (j <= high)) {
        if (temp[i] <= temp[j]) {
            data[k] = temp[i];
            i++;
        }
        else {
            data[k] = temp[j];
            j++;
            inv_count = inv_count + (middle - i);
        }

        k++;
    }

    // Copy the rest of the left side of the array into the target array
    while (i <= middle) {
        data[k] = temp[i];
        k++;
        i++;
    }

    // Copy the rest of the right side of the array into the target array
    while (j <= high) {
        data[k] = temp[j];
        k++;
        j++;
    }
    return inv_count;
}

int merge_sort(std::vector<int>& data, std::vector<int>& temp, int low, int high)
{
    int mid, inv_count = 0;
    if (high > low)
    {

        mid = (low + high) / 2;
        inv_count = merge_sort(data, temp, low, mid);
        inv_count += merge_sort(temp, temp, mid + 1, high);
        inv_count += merge(data, temp, low, mid, high);
    }

    return inv_count;
}

int sort(std::vector<int>& data, std::vector<int>& temp)
{
    return merge_sort(data, temp, 0, data.size() - 1);
}

int main()
{
    std::vector<int> data = { 2, 4, 1, 3, 5 };
    auto n = data.size();
    std::vector<int> temp(n, 0);
    std::cout << "The number of inversions is " << sort(data, temp);

    std::cin.get();
}

The answer should be 3 but I am getting just 1

Use a counter:

auto num_inversions1(std::vector<int>& nums)
{
    int cmpCounter = 0;
    auto compare = [&cmpCounter](int lhs, int rhs)
    {
        cmpCounter++;
        return lhs > rhs;
    };
    std::priority_queue<int, std::vector<int>, decltype(compare)> q(compare);
    for (auto num : nums)
        q.push(num);
    print_queue(q);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM