📌  相关文章
📜  合并两个具有O(1)额外空间的排序数组

📅  最后修改于: 2021-05-04 23:32:35             🧑  作者: Mango

我们给了两个排序数组。我们需要合并这两个数组,以使初始编号(完成排序后)在第一个数组中,而其余的数字在第二个数组中。 O(1)中允许有多余的空间。

例子:

Input: ar1[] = {10};
       ar2[] = {2, 3};
Output: ar1[] = {2}
        ar2[] = {3, 10}  

Input: ar1[] = {1, 5, 9, 10, 15, 20};
       ar2[] = {2, 3, 8, 13};
Output: ar1[] = {1, 2, 3, 5, 8, 9}
        ar2[] = {10, 13, 15, 20}

如果允许我们使用额外的空间,则此任务很简单,并且为O(m + n)。但是,如果不允许有多余的空间,并且在最坏的情况下不到O(m * n)看起来不可能,那么它将变得非常复杂。尽管可以进行进一步的优化
这个想法是从ar2 []的最后一个元素开始,然后在ar1 []中搜索它。如果ar1 []中有一个更大的元素,则将ar1 []的最后一个元素移到ar2 []。为了使ar1 []和ar2 []保持排序,我们需要将ar2 []的最后一个元素放置在ar1 []中的正确位置。我们可以为此使用插入排序类型。

1.方法1

算法:

1) Iterate through every element of ar2[] starting from last 
   element. Do following for every element ar2[i]
    a) Store last element of ar1[i]: last = ar1[i]
    b) Loop from last element of ar1[] while element ar1[j] is 
       greater than ar2[i].
          ar1[j+1] = ar1[j] // Move element one position ahead
          j--
    c) If any element of ar1[] was moved or (j != m-1)
          ar1[j+1] = ar2[i] 
          ar2[i] = last

在上面的循环中,ar1 []和ar2 []中的元素始终保持排序状态。

下面是上述算法的实现。

C++
// C++ program to merge two sorted
//  arrays with O(1) extra space.
#include 
using namespace std;
 
// Merge ar1[] and ar2[] with O(1) extra space
void merge(int ar1[], int ar2[], int m, int n)
{
    // Iterate through all elements
    // of ar2[] starting from the last element
    for (int i = n - 1; i >= 0; i--)
    {
        /* Find the smallest element greater than ar2[i].
        Move all elements one position ahead till the
        smallest greater element is not found */
        int j, last = ar1[m - 1];
        for (j = m - 2; j >= 0
             && ar1[j] > ar2[i]; j--)
            ar1[j + 1] = ar1[j];
 
        // If there was a greater element
        if (j != m - 2 || last > ar2[i])
        {
            ar1[j + 1] = ar2[i];
            ar2[i] = last;
        }
    }
}
 
// Driver program
int main()
{
    int ar1[] = { 1, 5, 9, 10, 15, 20 };
    int ar2[] = { 2, 3, 8, 13 };
    int m = sizeof(ar1) / sizeof(ar1[0]);
    int n = sizeof(ar2) / sizeof(ar2[0]);
    merge(ar1, ar2, m, n);
 
    cout << "After Merging nFirst Array: ";
    for (int i = 0; i < m; i++)
        cout << ar1[i] << " ";
    cout << "nSecond Array: ";
    for (int i = 0; i < n; i++)
        cout << ar2[i] << " ";
    return 0;
}


Java
// Java program program to merge two
// sorted arrays with O(1) extra space.
 
import java.util.Arrays;
 
class Test
{
    static int arr1[] = new int[]{1, 5, 9, 10, 15, 20};
    static int arr2[] = new int[]{2, 3, 8, 13};
     
    static void merge(int m, int n)
    {
        // Iterate through all elements of ar2[] starting from
        // the last element
        for (int i=n-1; i>=0; i--)
        {
            /* Find the smallest element greater than ar2[i]. Move all
               elements one position ahead till the smallest greater
               element is not found */
            int j, last = arr1[m-1];
            for (j=m-2; j >= 0 && arr1[j] > arr2[i]; j--)
                arr1[j+1] = arr1[j];
      
            // If there was a greater element
            if (j != m-2 || last > arr2[i])
            {
                arr1[j+1] = arr2[i];
                arr2[i] = last;
            }
        }
    }
     
    // Driver method to test the above function
    public static void main(String[] args)
    {
        merge(arr1.length,arr2.length);
        System.out.print("After Merging nFirst Array: ");
        System.out.println(Arrays.toString(arr1));
        System.out.print("Second Array:  ");
        System.out.println(Arrays.toString(arr2));
    }
}


Python3
# Python program to merge
# two sorted arrays
# with O(1) extra space.
 
# Merge ar1[] and ar2[]
# with O(1) extra space
def merge(ar1, ar2, m, n):
 
    # Iterate through all
    # elements of ar2[] starting from
    # the last element
    for i in range(n-1, -1, -1):
     
        # Find the smallest element
        # greater than ar2[i]. Move all
        # elements one position ahead
        # till the smallest greater
        # element is not found
        last = ar1[m-1]
        j=m-2
        while(j >= 0 and ar1[j] > ar2[i]):
            ar1[j+1] = ar1[j]
            j-=1
  
        # If there was a greater element
        if (j != m-2 or last > ar2[i]):
         
            ar1[j+1] = ar2[i]
            ar2[i] = last
  
# Driver program
 
ar1 = [1, 5, 9, 10, 15, 20]
ar2 = [2, 3, 8, 13]
m = len(ar1)
n = len(ar2)
 
merge(ar1, ar2, m, n)
  
print("After Merging \nFirst Array:", end="")
for i in range(m):
    print(ar1[i] , " ", end="")
 
print("\nSecond Array: ", end="")
for i in range(n):
    print(ar2[i] , " ", end="")
 
# This code is contributed
# by Anant Agarwal.


C#
// C# program program to merge two
// sorted arrays with O(1) extra space.
using System;
 
// Java program program to merge two
// sorted arrays with O(1) extra space.
 
 
public class Test
{
    static int []arr1 = new int[]{1, 5, 9, 10, 15, 20};
    static int []arr2 = new int[]{2, 3, 8, 13};
     
    static void merge(int m, int n)
    {
        // Iterate through all elements of ar2[] starting from
        // the last element
        for (int i=n-1; i>=0; i--)
        {
            /* Find the smallest element greater than ar2[i]. Move all
            elements one position ahead till the smallest greater
            element is not found */
            int j, last = arr1[m-1];
            for (j=m-2; j >= 0 && arr1[j] > arr2[i]; j--)
                arr1[j+1] = arr1[j];
     
            // If there was a greater element
            if (j != m-2 || last > arr2[i])
            {
                arr1[j+1] = arr2[i];
                arr2[i] = last;
            }
        }
    }
     
    // Driver method to test the above function
    public static void Main()
    {
        merge(arr1.Length,arr2.Length);
        Console.Write("After Merging \nFirst Array: ");
        for(int i =0; i< arr1.Length;i++){
            Console.Write(arr1[i]+" ");
        }
        Console.Write("\nSecond Array: ");
        for(int i =0; i< arr2.Length;i++){
            Console.Write(arr2[i]+" ");
        }
    }
}
 
/*This code is contributed by 29AjayKumar*/


PHP
= 0; $i--)
    {
        /* Find the smallest element greater than ar2[i]. Move all
           elements one position ahead till the smallest greater
           element is not found */
        $last = $ar1[$m-1];
        for ($j = $m-2; $j >= 0 && $ar1[$j] > $ar2[$i]; $j--)
            $ar1[$j+1] = $ar1[$j];
  
        // If there was a greater element
        if ($j != $m-2 || $last > $ar2[$i])
        {
            $ar1[$j+1] = $ar2[$i];
            $ar2[$i] = $last;
        }
    }
}
  
// Driver program
 
$ar1 = array(1, 5, 9, 10, 15, 20);
$ar2 = array(2, 3, 8, 13);
$m = sizeof($ar1)/sizeof($ar1[0]);
$n = sizeof($ar2)/sizeof($ar2[0]);
merge($ar1, $ar2, $m, $n);
 
echo "After Merging \nFirst Array: ";
for ($i=0; $i<$m; $i++)
    echo $ar1[$i] . " ";
echo "\nSecond Array: ";
for ($i=0; $i<$n; $i++)
    echo $ar2[$i] ." ";
return 0;
?>


Javascript


C++
// CPP program for the above approach
#include 
using namespace std;
 
// Function to merge two arrays
void merge(int arr1[], int arr2[], int n, int m)
{
    int i = 0, j = 0, k = n - 1;
   
    // Untill i less than equal to k
    // or j is less tha m
    while (i <= k and j < m) {
        if (arr1[i] < arr2[j])
            i++;
        else {
            swap(arr2[j++], arr1[k--]);
        }
    }
   
    // Sort first array
    sort(arr1, arr1 + n);
   
    // Sort second array
    sort(arr2, arr2 + m);
}
 
// Driver Code
int main()
{
 
    int ar1[] = { 1, 5, 9, 10, 15, 20 };
    int ar2[] = { 2, 3, 8, 13 };
    int m = sizeof(ar1) / sizeof(ar1[0]);
    int n = sizeof(ar2) / sizeof(ar2[0]);
    merge(ar1, ar2, m, n);
 
    cout << "After Merging \nFirst Array: ";
    for (int i = 0; i < m; i++)
        cout << ar1[i] << " ";
    cout << "\nSecond Array: ";
    for (int i = 0; i < n; i++)
        cout << ar2[i] << " ";
    return 0;
}


Java
// Java program for the above approach
import java.util.Arrays;
import java.util.Collections;
 
class GFG {
    static int arr1[] = new int[] { 1, 5, 9, 10, 15, 20 };
    static int arr2[] = new int[] { 2, 3, 8, 13 };
 
    // Function to merge two arrays
    static void merge(int m, int n)
    {
        int i = 0, j = 0, k = n - 1;
        while (i <= k and j < m) {
            if (arr1[i] < arr2[j])
                i++;
            else {
                int temp = arr2[j];
                arr2[j] = arr1[k];
                arr1[k] = temp;
                j++;
                k--;
            }
        }
        Arrays.sort(arr1);
        Arrays.sort(arr2);
    }
 
    public static void main(String[] args)
    {
        merge(arr1.length, arr2.length);
        System.out.print("After Merging \nFirst Array: ");
        System.out.println(Arrays.toString(arr1));
        System.out.print("Second Array:  ");
        System.out.println(Arrays.toString(arr2));
    }
}


输出:

After Merging 
First Array: 1 2 3 5 8 9 
Second Array: 10 13 15 20

时间复杂度:最坏的情况是代码/算法的时间复杂度为O(m * n)。当ar1 []的所有元素都大于ar2 []的所有元素时,会发生最坏的情况。

插图:

合并两个排序的数组

<!—初始数组:
ar1 [] = {1,5,9,10,15,20};
AR2 [] = {2,3,8,13};
第一次迭代后:
ar1 [] = {1,5,9,10,13,15};
AR2 [] = {2,3,8,20};
// 20从ar1 []移至ar2 []
//将ar2 []中的13插入ar1 []中
在第二次迭代之后:
ar1 [] = {1,5,8,9,10,13};
AR2 [] = {2,3,15,20};
// 15从ar1 []移至ar2 []
//将ar2 []中的8插入ar1 []中
第三次迭代后:
ar1 [] = {1、3、5、8、9、10};
AR2 [] = {2,13,15,20};
// 13从ar1 []移至ar2 []
//将ar2 []中的3插入ar1 []中
第四次迭代后:
ar1 [] = {1,2,3,5,8,9};
ar2 [] = {10,13,15,20};
// 10从ar1 []移至ar2 []
//将ar2 []中的2插入ar1 []中
-!>

方法2:

可以通过观察在并行遍历两个排序的数组时进一步优化该解决方案,如果遇到第j个第二数组元素小于第i个第一个数组元素,则将包含第j个元素并替换第一个数组中的第k个元素。该观察结果有助于我们采用以下算法

算法

1) Initialize i,j,k as 0,0,n-1 where n is size of arr1 
2) Iterate through every element of arr1 and arr2 using two pointers i and j respectively
    if arr1[i] is less than arr2[j]
        increment i
    else
        swap the arr2[j] and arr1[k]
        increment j and decrement k

3) Sort both arr1 and arr2 

下面是上述算法的实现

C++

// CPP program for the above approach
#include 
using namespace std;
 
// Function to merge two arrays
void merge(int arr1[], int arr2[], int n, int m)
{
    int i = 0, j = 0, k = n - 1;
   
    // Untill i less than equal to k
    // or j is less tha m
    while (i <= k and j < m) {
        if (arr1[i] < arr2[j])
            i++;
        else {
            swap(arr2[j++], arr1[k--]);
        }
    }
   
    // Sort first array
    sort(arr1, arr1 + n);
   
    // Sort second array
    sort(arr2, arr2 + m);
}
 
// Driver Code
int main()
{
 
    int ar1[] = { 1, 5, 9, 10, 15, 20 };
    int ar2[] = { 2, 3, 8, 13 };
    int m = sizeof(ar1) / sizeof(ar1[0]);
    int n = sizeof(ar2) / sizeof(ar2[0]);
    merge(ar1, ar2, m, n);
 
    cout << "After Merging \nFirst Array: ";
    for (int i = 0; i < m; i++)
        cout << ar1[i] << " ";
    cout << "\nSecond Array: ";
    for (int i = 0; i < n; i++)
        cout << ar2[i] << " ";
    return 0;
}

Java

// Java program for the above approach
import java.util.Arrays;
import java.util.Collections;
 
class GFG {
    static int arr1[] = new int[] { 1, 5, 9, 10, 15, 20 };
    static int arr2[] = new int[] { 2, 3, 8, 13 };
 
    // Function to merge two arrays
    static void merge(int m, int n)
    {
        int i = 0, j = 0, k = n - 1;
        while (i <= k and j < m) {
            if (arr1[i] < arr2[j])
                i++;
            else {
                int temp = arr2[j];
                arr2[j] = arr1[k];
                arr1[k] = temp;
                j++;
                k--;
            }
        }
        Arrays.sort(arr1);
        Arrays.sort(arr2);
    }
 
    public static void main(String[] args)
    {
        merge(arr1.length, arr2.length);
        System.out.print("After Merging \nFirst Array: ");
        System.out.println(Arrays.toString(arr1));
        System.out.print("Second Array:  ");
        System.out.println(Arrays.toString(arr2));
    }
}

输出

After Merging 
First Array: 1 2 3 5 8 9
Second Array: 10 13 15 20

复杂性:

时间复杂度:在最坏的情况下,在while循环中遍历数组时的时间复杂度为O(n + m),而排序为O(nlog(n)+ mlog(m))。因此,代码的总体时间复杂度变为O((n + m)log(n + m))。

空间复杂度:由于函数不对任何操作使用任何额外的数组,因此空间复杂度为O(1)。