【问题标题】:Check if two arrays are similar [duplicate]检查两个数组是否相似[重复]
【发布时间】:2013-11-06 06:00:47
【问题描述】:

给定两个数组,检查它们是否相似(即具有相同的整数并且每个整数出现的次数相同)。

例如:

int arr1[5] = { 3, 5, 2, 5, 2}
int arr2[5] = { 2, 3, 5, 5, 2}

我不被允许使用排序和哈希表。它应该是 O(n) 并且不应该使用任何额外的空间。

这是一道面试题。

尝试使用以下规则:

  1. 两个数组的整数之和应该相同
  2. 两个数组中整数的乘积应该相同。
  3. 所有整数的异或应为零

但是面试官还是不开心。也许我错过了一些极端案例。

【问题讨论】:

  • 这是您提出的问题的逐字副本吗?如果是这样,它就非常模棱两可,我不确定要问什么。
  • 我猜基本上如果一个数组是另一个数组的排列。大概这个问题是看你在解决问题的同时思考的过程。您可以尝试将一个数组中的每个元素与另一个数组中的另一个元素进行匹配。
  • 你“尝试过”什么?
  • 它应该是 O(n),其中 n 是整数个数。
  • 这个问题可能有助于告诉你面试官对你的期望:stackoverflow.com/questions/13298110/…

标签: arrays algorithm


【解决方案1】:

如果元素值是整数并且以n (1...n) 为界,我可以想到一种执行此任务的方法,其中n 是数组的大小(这适用于您的示例):

在每个数组中,对于每个元素x,我们执行arr[x%(n+1)-1] += n+1。我们使用 mod,因为元素可能会在整个过程中发生变化,通过使用 mod,我们可以得到原始数组中出现的元素。

我们所做的就是计算一个值varr[v]中出现的次数,加上n+1,然后我们可以通过arr[v]%(n+1)得到原始值,因为该值以n为界,以及通过arr[v]/(n+1) 出现的次数。

最后我们比较AB中每个值出现的次数,如果有不同的值,我们返回false。如果所有值的计数都相同,我们返回true

这是一个需要O(1) 内存的O(n) 时间解决方案。

算法如下:

bool checkIfArraysAreSimilar(int[] A, int[] B)
{
    n = A.length; // = B.length
    int i;

    for (i = 0; i < n; i++)
    {
        A[(A[i]%(n+1))-1] += n+1;
        B[(B[i]%(n+1))-1] += n+1;
    }

    for (i = 0; i < n; i++)
    {
        if (A[i] / n+1 != B[i] / n+1)
            return false;
    }

    return true;
}

【讨论】:

  • 非常好的解决方案,但我想知道如果数组中的数字大于 n+1,它是否可以正常工作,例如以下数组:[3,5,8,5,2][3,5,8,5,8]。我认为您的代码会发现这些数组是相似的,因此只有当数组的最大值小于 n+1 时,您的解决方案才能正常工作。但是,干得好!
  • @Bentoy13 你是对的,我已经提到这个解决方案只有在值以n 为界时才有效。
  • 啊,是的!对不起,我读得太快了。可逆桶计数的好版本!
  • 算法不一致 :( 1Console.WriteLine(checkIfArraysAreSimilar(new int[] {10, 2, 3, 4, 5}, new int[] {5, 4, 3, 2, 10 }));` 给出false
【解决方案2】:

在 JavaScript 中试试这个算法:

DEMO

var arr11 = [ 3, 5, 2, 5, 2]
var arr22 = [ 2, 3, 5, 5, 2]
console.log(arraySimilar(arr11,arr22));
function arraySimilar(arr1,arr2){ 
    var tempArr = arr2;
    // Checking Length if both the arrays are equal 
    if(arr1.length == arr2.length){
        //Running a For Loop for first array 
        for(i=0; i<arr1.length; i++){
            //If the Element is present removing from "tempArr"
            if(tempArr.indexOf(arr1[i])!= -1){
                tempArr.splice(tempArr.indexOf(arr1[i]),1);
            }
            else{ return false;}
        }
    }
    else{ return false; }
    // Check "tempArr" if it is empty
    if(tempArr.length==0){
        return true;
    }else{
        return false;
    }
}

【讨论】:

  • 这是 O(n^2) 由于indexOf
【解决方案3】:

可能他的意思是你应该比较 f(x[i]) 的 sum by i 和 f(y[i]) 的 sum by i,其中 x 和 y 是数组,f 是哈希函数。

【讨论】:

  • 请修正格式。你的意思是计算每个数组元素的哈希值并将它们相加吗?
  • 你甚至可以在 SO 上使用 LaTeX 吗?我知道你可以在数学上......
【解决方案4】:

第一个数组有两种可能的方式,无论它是否包含不重复的元素。假设为简单起见,第一个数组不包含重复的元素,那么这个想法很简单,就像我下面的代码一样跟踪总数

#include <iostream>

int  main()
{ 
    int arr1[5] = { 1, 2, 3, 4, 5};
    int arr2[5] = { 5, 1, 3, 4, 2};

    int total(0);

    for (unsigned int i(0); i < 5; ++i)
    {
        for (unsigned int j(0); j < 5; ++j)
        {
            if ( arr1[i] == arr2[j] )
            {
                total += 1;
            }
        }
    }
    if ( total == 5 ) 
        std::cout << "Same " << std::endl;
    else 
        std::cout << "not Same " << std::endl;

    std::cin.get();
    return 0;
}

如果总数小于或大于 5,则数组不相同。现在,在我看来,我们需要提出一个计算正确总数的算法,因此我们需要一个接受数组并检查总数的函数。例如,在您的情况下,总数应该是 9(1 代表 3,4 代表 2,4 代表 5)。这就是我想到的。我希望这个想法很清楚。这是我为一般情况所做的

#include <iostream>


int getTotal(int arr[], const int size)
{
    int *temp = new int[size]; 
    int total(0);
    for (int i(0); i < size; ++i)
        temp[i] = arr[i];


    for (int i(0); i < size; ++i)
    {
        for (int j(0); j < size; ++j)
        {
            if ( arr[i] == temp[j] )
                total += 1;
        }
    }

    std::cout << total << std::endl;
    return total;
}

int  main()
{ 
    int arr1[5] = { 3, 5, 2, 5, 2};
    int arr2[5] = { 2, 3, 5, 5, 2};

    int total = getTotal(arr1, 5);
    int track(0);

    for (unsigned int i(0); i < 5; ++i)
    {
        for (unsigned int j(0); j < 5; ++j)
        {
            if ( arr1[i] == arr2[j] )
            {
                track += 1;
            }
        }
    }
    if ( track == total ) 
        std::cout << "Same " << std::endl;
    else 
        std::cout << "not Same " << std::endl;

    std::cin.get();
    return 0;
}

使用一个循环的另一种方法。这个想法是获得一个数组的总数,然后将总数除以每个元素以获得新的总数。如果第一个数组的新总数等于第二个数组的新总数,那么它们是相同的。 (注意:我没有针对所有情况测试我的代码;但是,我的方法对我来说似乎是明智的。

#include <iostream>


double getTotal(double arr[], const int size)
{
    double total1(0), total2(0);

    for (int i(0); i < 5; ++i)
    {
        total1 += arr[i];
    }

    for (int i(0); i < 5; ++i)
    {
        total2 += total1/arr[i];
    }

    std::cout << total2 << std::endl;

    return total2;
}

int  main()
{ 
    double arr1[5] = { 3, 5, 2, 4, 2};
    double arr2[5] = { 2, 3, 5, 5, 2};

    double total1 = getTotal(arr1, 5);
    double total2 = getTotal(arr2, 5);

    if ( total1 == total2 ) 
        std::cout << "Same " << std::endl;
    else 
        std::cout << "not Same " << std::endl;

    std::cin.get();
    return 0;
}

【讨论】:

  • 我认为这也是 O(N^2),因为有 2 个 for 循环。
  • 我用另一种方法更新了我的代码。看看吧
  • 它在另一个for中仍然有for
  • 是的,你是对的。我很抱歉。我已经删除了第二种方法,因为它不适用于所有情况。
  • 看看我的回答。我只使用一个循环对其进行了更新。如你所愿。
猜你喜欢
  • 1970-01-01
  • 2020-10-05
  • 1970-01-01
  • 2021-11-15
  • 1970-01-01
  • 2020-02-12
  • 2017-09-09
  • 1970-01-01
相关资源
最近更新 更多