两个阵列的联盟

时间:2011-12-06 20:44:27

标签: c# java algorithm

给出两个数组

int arr1[n]
int arr2[m]

其中n> m

需要将两个数组的并集编写为一个。

例如,如果输入数组是:

   int arr1[] = {1, 3, 4, 5, 7}
   int arr2[] = {2, 3, 5, 6}

然后程序应该创建新的数组Union {1, 2, 3, 4, 5, 6, 7}

实现可以是C#或Java。

为了解决它,首先需要使用Merge Sort对数组进行排序 然后做联盟

我在网上看了看但没找到优雅的方式。我看过的每一个代码 充满了IF。

请建议最快捷,最优雅的方式

5 个答案:

答案 0 :(得分:4)

你是正确的,将Merge Sort中的两个列表合并是最有效的。这假设已经对两个列表进行了排序,如您的示例所示。以下是如何实现合并的示例:

function merge(left,right)
    var list result
    while length(left) > 0 or length(right) > 0
        if length(left) > 0 and length(right) > 0
            if first(left) ≤ first(right)
                append first(left) to result
                left = rest(left)
            else
                append first(right) to result
                right = rest(right)
        else if length(left) > 0
            append first(left) to result
            left = rest(left)
        else if length(right) > 0
            append first(right) to result
            right = rest(right)
    end while
    return result

从这里开始,不要在最终输出中包含重复。

答案 1 :(得分:2)

如果它看起来是优雅的MergeSort,那么没有什么比递归函数更优雅了: - )

这是:

这是一种分而治之的策略。我们基本上将数组划分为更小的数组,对较小的数组进行排序并将它们合并。

public static void mergesort(int a[],int left, int right){
    /*
    *  Time : O(n log n)
    *  Space : O(n)
    */
    int b[] = new int[right -left+1];
    domergesort(a,left,right,b);
}

public static void domergesort(int a[],int left,int right, int b[]){

    if(left < right){
        int mid = (left+right)/2;
        domergesort(a,left,mid,b);
        domergesort(a,mid+1,right,b);
        merge(a,left,mid,a,mid+1,right,b);
        for(int k=left;k<=right;k++)
            a[k] = b[k-left];
    }
}

也不是很多..

来源:我的博客(http://cloudingitup.blogspot.com/p/reading-guide-arrays.html)

将它们合并为一个联盟:

public static void merge( int a[], int al, int ar, int b[], int bl, int br, int c[]){
    // al : a's left index ar : a's right index c: merged array
    int i= al;
    int j = bl;
    int k=0;
    int prev = c[0]; 

    while ( i<= ar && j <= br){
        if (a[i] <= b[j])
          if (prev != a[i]) // Too keep the union distinct
              c[k++] = a[i++];
          else
             i++;
        else
            if (prev != b[j]) // Too keep the union distinct
                c[k++] = b[j++];
            else
                j++;

        prev = c[k-1];

    }

    while (i <= ar)
     {
     if (prev != a[i])
        c[k++] = a[i++];
      else
         i++;

       prev = c[k-1];
      }


    while (j <= br)
     {
     if (prev != b[j])
        c[k++] = b[j++];
      else
         j++;
       prev = c[k-1];
      }

}

用于说明代码的驱动程序代码:

int arr1[] = {1,1, 3, 4,4,4,5, 7};
int arr2[] = {2, 3, 5, 6,6,8};
int c[] = new int[8];

merge(arr1,0,7,arr2,0,5,c);

for(int i=0;i<8;i++)
System.out.print(c[i]);

输出:12345678

答案 2 :(得分:1)

public static void printUnion(int ar1[],int ar2[]) {
        int m = ar1.length;
        int n = ar2.length;
        int i=0,j=0;

        while(i<m && j<n) {
            if( ar1[i] <ar2[j]) {
                System.out.println(ar1[i]);
                i++;
            }else if(ar1[i] > ar2[j]) {
                System.out.println(ar2[j]);
                j++;
            }else {
                System.out.println(ar1[i]);
                i++;
                j++;
            }
        }
        while(i < m)
               System.out.println(ar1[i++]);
        while(j < n)
               System.out.println(ar2[j++]);
}

相同的代码适用于最小变化的交叉....

答案 3 :(得分:0)

在采访中,他们通常希望看到你解决问题,而不是使用库调用(例如arr1.union(arr2)可能不会削减它。)

这是我的头脑,但这样的事情应该有效,我认为是O(n ^ 2)。它假设两个数组都已排序。

union.rb

arr1 = [0,2,4,9,11,12,13]
arr2 = [3,4,7,9,10,11]

def union(n, m)
  if n.last > m.last
    arr1 = n; arr2 = m
  else
    arr1 = m; arr2 = n
  end

  union_array = []
  j = 0
  arr1.each do |x|
    while j < arr2.length && arr2[j] < x
      if arr2[j] < x
        union_array << arr2[j] unless arr2[j] == union_array.last
        j += 1
      end
    end
    union_array << x
  end
  union_array
end

puts union(arr1, arr2)

答案 4 :(得分:0)

这个方法应该运行得相当好,它将决定哪个数组更大,所以不一定需要定义的顺序。

爪哇:

public static <T> T[] combine(T[] a1, T[] a2)
{
    return combine(a1, a2, a1.length + a2.length);
}
public static <T> T[] combine(T[] a1, T[] a2, int maxlength)
{
    T[] front = null;
    T[] back = null;
    if(a1.length >= a2.length)
    {
        front = a1;
        back = a2;
    }
    else
    {
        front = a2;
        back = a1;
    }
    int len = front.length + back.length;
    if(len > maxlength)
    {
        len = maxlength;
    }
    int n = 0;
    T[] result = Arrays.copyOf(front, len);
    int c = 0;
    for(int i = 0;i < front.length;i++)
    {
        if(i < front.length && c < result.length)
        {
            result[c] = front[i];
            c++;
        }
        if(i < back.length && c < result.length)
        {
            result[c] = back[i];
            c++;
        }
    }
    return result;
}

这显然不是最有效的方法,但它确实完全有效。它还包括一个封顶,如果你想合并它们,但只获得第一个,让我们的方式5个项目,那么你可以在方法中添加一个参数5。

你实际上可以摆脱很多浪费,这里有很多杂乱的东西,我离开我的IDE所以它不在我的脑海里,我可能有不需要的东西。