【问题标题】:Insert elements from one array to another such that inversions are minimised将元素从一个数组插入到另一个数组,从而最小化反转
【发布时间】:2022-10-23 12:16:27
【问题描述】:

假设我有数组 A 和 B (总是相等的大小) A = 5 4 2 1

B = 8 3 6 7

我要将元素从 B 插入到 A 中,同时保持 A 的相对顺序,同时尽量减少反转。

所以答案是 3 5 4 1 2 6 7 8(7 个倒置)

我尝试先对 B 进行排序,然后将 min(a[0] b[0]) 弹出到数组 C 中,但情况如下 A = 99999 1 2 3

B = 5 6 7 8

给出错误的 5 6 7 8 99999 1 2 3(15 次反转)

正确时为 99999 1 2 3 5 6 7 8 (7 反转)

我迷路了,请帮忙

【问题讨论】:

  • 请提供足够的代码,以便其他人可以更好地理解或重现该问题。

标签: arrays performance sorting inversion


【解决方案1】:

好的,这是一个有趣的问题。我当前的解决方案适用于 O(nlog(n))。

这个解决方案背后的逻辑可以在这里找到:https://cs.stackexchange.com/questions/140295/complexity-to-insert-subset-of-array-to-minimize-order-inversions

但是,由于那里没有实现,我决定把它放在这里。

整体逻辑依赖于两件事:

  1. 对于不需要维护顺序的数组,按O(n log n)排序。
  2. 找到中间元素,并将其插入到数组中最小化反转的位置。这可以在 T(2n) = O(n) 中完成。
  3. 排序数组中该中间元素左侧的元素应位于组合数组中该元素的左侧,以最大程度地减少反转。排序数组中该中间元素右侧的元素应位于组合数组中该元素的右侧,以最小化反转。这种知识减少了您必须搜索的空间,以找到每次迭代具有最少反转的插入点。因此,您可以通过将上述逻辑应用于排序数组的左半部分和组合数组的左半部分来进行递归。

    现在,进入代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    long long merge(vector<int>& v, int temp[], int left, int mid, int right) {
        int i,j,k;
        long long inv_count = 0;
    
        i = left;
        j = mid;
        k = left;
    
        while ((i <= mid - 1) && (j <= right)) {
            if (v[i] <= v[j]) {
                temp[k++] = v[i++];
            } else {
                temp[k++] = v[j++];
                inv_count += mid - i;
            }
        }
    
        while (i <= mid - 1)
            temp[k++] = v[i++];
        
        while (j <= right)
            temp[k++] = v[j++];
     
        for (i = left; i <= right; i++)
            v[i] = temp[i];
        
        return inv_count;
    }
    
    long long _mergeSort(vector<int>& v, int temp[], int left, int right) {
        int mid; 
        long long inv_count = 0;
        if (v.size() < 2) return 0;
        if (right > left) {
            mid = (right + left) / 2;
            inv_count += _mergeSort(v, temp, left, mid);
            inv_count += _mergeSort(v, temp, mid + 1, right);
            inv_count += merge(v, temp, left, mid + 1, right);
        }
        return inv_count;
    }
    
    long long countInversionsInVector(vector<int>& v) {
        int temp[v.size()];
        return _mergeSort(v, temp, 0, v.size() - 1);
    }
    
    void solveHelper(vector<int> &a, int sa, int ea, vector<int>& b, int sb, int eb, vector<int>& I) {
        if (sb >= eb) return;
        int mb = (sb + eb) / 2;
        int b_elem = b[mb];
        
        vector<int> sliced_a(ea - sa + 1);
    
        for (auto index = a.begin() + sa; index < a.begin() + ea; index++) {
            sliced_a.push_back(*index);
        }
    
        long long invCount = 0;
        for (long long i = sa; i < ea; i++) {
            if (a[i] < b_elem) {
                invCount += 1;
            }
        }
    
        long long minInvCount = invCount;
        int insertionIndex = sa;
    
        for (int i = sa; i < ea; i++) {
            if (a[i] < b[mb]){
                invCount -= 1;
            } else {
                invCount += 1;
            }
    
            if (invCount < minInvCount) {
                minInvCount = invCount;
                insertionIndex = i + 1;
            }
        }
    
        I[mb] = insertionIndex;
        
        solveHelper(a, sa, insertionIndex, b, sb, mb, I);
        solveHelper(a, insertionIndex, ea, b, mb + 1, eb, I);
        return;
    }
    
    void mergeFinal(vector<int>& a, vector<int>& b, vector<int>& I, vector<int>& final) {
        int index_a = 0;
        int index_b = 0;
        for (int i = 0; i < 2 * a.size(); i++) {
            if (i == I[index_b] + index_b) {
                final[i] = b[index_b];
                index_b++;
            } else {
                final[i] = a[index_a];
                index_a++;
            }
        }
    }
    
    long long solve(vector<int>& a, vector<int>& b) {
        sort(b.begin(), b.end());
        vector<int> I(b.size());
        solveHelper(a, 0, a.size(), b, 0, b.size(), I);
        
        vector<int> final(2*a.size());
        mergeFinal(a, b, I, final);
        
        return countInversionsInVector(final);
    }
    
    int main() {
        int n;
        ios_base::sync_with_stdio(false); // speed up reading input
        cin >> n;
        vector<int> a(n), b(n);
        for(int i = 0; i < n; i++) {
            cin >> a[i];
        }
        for(int i = 0; i < n; i++) {        
            cin >> b[i];
        }
    
        cout << solve(a, b) << "
    ";
    }
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多