给出两个数组
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。请建议最快捷,最优雅的方式
答案 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所以它不在我的脑海里,我可能有不需要的东西。