当前位置: 首页 > 知识库问答 >
问题:

在两个数组中计数反转

罗安和
2023-03-14

数组中的反转是一对索引(i,j),使得a[i]

给定2个数组A和B,我们必须返回这样的对的数目,这样A[i]

例子:

设n=3,A[]=[5,6,7],B[]=[1,2,3],则答案为3。3对为(5,2)、(5,3)和(6,3)。

我的代码:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int len;
    scanf("%d",&len);
    int a[len];
    int b[len];
    for(int i = 0; i < len; i++)
       scanf("%d",&a[i]);
    for(int i = 0; i < len; i++)
       scanf("%d",&b[i]);
    int count = 0;
    for (int i = 0;i < len; i++)
    {
        for(int j = i+1; j < len; j++)
        {
             if(a[i] > b[j])
             {
                 count++;
             }
         }
     }
     printf("%d",count);
}

但这是O(N^2)解。我需要一个更好的解作为N

共有3个答案

樊腾
2023-03-14

有一个想法:
1。合并两个原始数组,使具有相同索引的每对元素彼此相邻。(您需要放置元素,使较低的元素位于较高的元素之前)
3。计算结果数组中的反转数,如下所述。

编辑:对不起,我误解了这个问题。如果只需要从a(I)到b(j)的反转,那么可以使用另一个字段arraytype(a或b)标记每个元素。然后,在合并排序时,只有当反转从arraytype a到b时,才能增加计数。

孟成文
2023-03-14

您可以使用合并排序思想找到两个数组之间的倒置!

假设你有两个大小相同的数组,让我们称它们为A、B,如果我们分别表示A的前半部分、A1和A的后半部分、A2和B1和B2,那么我们可以得出结论:

  1. A1和B1之间的反转
  2. A2和B2之间的反转
  3. A1和B2之间的反转

递归调用函数可以支持前两个元素,但是如何计算第三个元素呢?

我们的想法是从左到右遍历A1和B2,其中B1中的元素大于A1中的元素,然后A1中尚未访问的元素应相加为反转数,最后我们只将A1和A2排序为A,将B1和B2排序为B

下面是python中的代码:

def find_inv(A, B):

if len(A) <= 1:
    return 0
mid = len(A) // 2
A1 = A[:mid]
A2 = A[mid:]
B1 = B[:mid]
B2 = B[mid:]

if len(A1) >= 1 and len(B2) >= 1:
    ans = find_inv(A1, B1) + find_inv(A2, B2)
else:
    A.sort()
    B.sort()
    ans = 0
len_A = len(A1)
index_A = 0
len_B = len(B2)
index_B = 0

for k in range(len_A + len_B):

    if A1[index_A] <= B2[index_B]:

        index_A += 1
        if index_A == len_A:
            merge(A1, A2, A)
            merge(B1, B2, B)

            return ans
    else:
        index_B += 1
        ans += (len_A - index_A)

        if index_B == len_B:
            merge(A1, A2, A)
            merge(B1, B2, B)
            return ans

def merge(A1, A2, dest):
i = 0
j = 0


while i < len(A1) and j < len(A2):
    if A1[i] < A2[j]:
        dest[i+j] = A1[i]
        i += 1
    else:
        dest[i+j] = A2[j]
        j += 1
while i < len(A1):
        dest[i+j] = A1[i]
        i += 1

while j < len(A2):
        dest[i+j] = A2[j]
        j += 1
尉迟晔
2023-03-14

我在过去写过关于如何使用Fenwick树计算倒置的文章,这是一种非常有效的二叉树类型,可让您计算序列上的前缀聚合。

以下是针对您的场景的临时修改:

long long inversions(const vector<int>& a, const vector<int>& b) {
  int n = a.size();
  vector<int> values(a);
  for (int x: b) values.push_back(x);
  sort(begin(values), end(values));
  vector<int> counts(2*n + 1);
  long long res = 0;
  for (int i = n - 1; i >= 0; --i) {
    // compute sum of prefix 1..rank(a[i]) - 1
    for (int v = lower_bound(begin(values), end(values), a[i]) - begin(values);
         v; 
         v -= v & -v)
      res += counts[v];
    //add 1 to point rank(b[i])
    for (int v = lower_bound(begin(values), end(values), b[i]) - begin(values) + 1;
         v <= 2*n;
         v += v & -v)
      counts[v]++;
  }
  return res;
}

基本上,我们从右到左遍历数组,维护一个表示后缀中已经看到的a值的数据结构。对于每个元素b[i],我们将数据结构中元素x的数量与x一起添加到最终结果中

数组值用于将值的范围压缩为1。。2n因为芬威克树在范围大小上呈线性空间。我们可以通过选择一个功能更全面的数据结构来避免这一步,比如平衡的bjnary搜索树,并增加子树的大小。

复杂度为O(n log n),常数因子很低。

 类似资料:
  • 我如何找到两个数组共有的值?在这种情况下,应返回和。

  • 假设我有这两个数组: 如何从ARR2获取arr1中的出现次数。两个数组中的所有字符串都是唯一的,不会有重复的。显然,在这个具体案例中的结果是2。 我试过的: 问题是我必须在很少的情况下使用它,并且变量总是在变化,这取决于您单击的内容,而您不能依赖它的值。 提前谢谢!

  • 问题内容: 我见过类似的问题,但没有一个提供我所要的答案,因此,如果这被认为是重复的,我在此致歉。我正在尝试将数组{1,2,3}和{4,5,6}合并为{1,2,3,4,5,6}。我做错了什么?我是java的新手。抱歉,问题很愚蠢。 问题答案: 代替 您需要调用merge方法,并将结果分配给数组,例如: 您的for循环也应该是:

  • 问题内容: 我有很多对象,我需要将它们分成两个组成一组,以供UI助手使用。 例: 通过这四个数组成为一个数组 有很多分割数组的方法。但是,如果阵列很大,什么是最有效的(成本最低)。 问题答案: 如果您正在寻找效率,则可以使用一种方法来懒散地生成每个包含2个元素的数组,因此您一次只能在内存中存储2个元素: 此方法适用于任何Array,而不仅限于Arrays。 对于Swift 1,没有协议扩展,您将拥

  • 问题内容: 我有2个1d数组,而我正在尝试将它们填充到JAVA中的单个2d数组中。 例如: 结果应为: 我该怎么办?我目前有这样的事情: 我有点被困在那里… 问题答案: 2D数组是数组的数组。那你为什么不试试这个呢? 为了确保它是如此简单并且可以正常工作,请进行以下测试:

  • 给定一个1-D数组,比如4个元素5 4 2 3,我知道改进的合并排序(分治)算法可以计算反转数(对,这样我 倒置的编号为4对(5,4) (5,2) (5,3)和(4,3) 我不熟悉堆栈溢出。请原谅格式问题。