Leetcode OJ: Merge Sorted Array

Merge Sorted Array

Given two sorted integer arrays A and B, merge B into A as one sorted array.

Note:
You may assume that A has enough space (size that is greater or equal to m + n) to hold additional elements from B. The number of elements initialized in A and B are m andn respectively.

最简单粗暴的思路:

1. 开辟数组空间C用以存放中间过程,然后对A、B数组各给一个指针。

2. 开始遍历比较,哪个小把对应的值push进C,然后对应指针也后移,直到两个数组都遍历完了。

3. 把C的值都拷贝到A。

时间复杂度为O(m+n),空间复杂度为O(m+n)。

代码如下:

 1 class Solution {
 2 public:
 3     void merge(int A[], int m, int B[], int n) {
 4         vector<int> C;
 5         int i = 0, j = 0;
 6         int count = 0;
 7         while (i < m && j < n) {
 8             if (A[i] < B[j]) {
 9                 C.push_back(A[i]);
10                 ++i;
11             } else {
12                 C.push_back(B[j]);
13                 ++j;
14             }
15             count++;
16         }
17         while (i < m) {
18             C.push_back(A[i++]);
19             count++;
20         }
21         while (j < n) {
22             C.push_back(B[j++]);
23             count++;
24         }
25         
26         for (int i = 0; i < count; ++i) {
27             A[i] = C[i];
28         }
29     }
30 };

减少比较次数的思路(利用二分查找):

1. 开辟数组空间C用以存放中间过程,然后对A、B数组各给一个指针i, j。

2. 在A[i]后查找B[j]应该在A中插入的位置i+ansA(一定要注意好下标

3. 若ansA没越界,判断A[i+ansA]是与B[j]是否相等,若相等重复3,否则跳下一步4。

4. 把A[i]~A[i+ansA](不包含)值都拷贝到C中。

5. 若ansA仍没越界,则在B[j]中查找这一值应插入的位置ansB,把B[j]~B[j+ansB](不包含)值都拷贝到C中,j:=j+ansB。

6. i := i+ansA。如果i,j均没越界,跳到2,否则跳到下一步7。

7. 把A、B中的剩余部分都拷贝到C

8. 最后把C的值都拷贝到A

代码如下:

 1 class Solution {
 2 public:
 3     // 二分查找
 4     int search(int A[], int n, int target) {
 5         int begin = 0, end = n, mid;
 6         while (begin < end) {
 7             mid = begin + ((end - begin) >> 1);
 8             if (A[mid] < target) {
 9                 begin = mid + 1;
10             } else if (A[mid] > target) {
11                 end = mid;
12             } else {
13                 break;
14             }
15         }
16         if (begin >= end)
17             return end;
18         return mid;
19     }
20 
21     void merge(int A[], int m, int B[], int n) {
22         vector<int> C;
23         int i = 0, j = 0;
24         while (i < m && j < n) {
25             int ansA = search(A + i, m - i, B[j]);
26             // 判断是否与B[j]相等
27             while (i + ansA < m && A[i + ansA] == B[j])
28                 ++ansA;
29             if (ansA > 0)
30                 C.insert(C.end(), A + i, A + i + ansA);
31             if (i + ansA < m) {
32                 int ansB = search(B + j, n - j, A[i + ansA]);
33                 if (ansB > 0) {
34                     C.insert(C.end(), B + j, B + j + ansB);
35                     j += ansB;
36                 }
37             } 
38             i += ansA;
39         }
40         if (i < m) {
41             C.insert(C.end(), A + i, A + m);
42         }
43         if (j < n) {
44             C.insert(C.end(), B + j, B + n);
45         }
46         
47         copy(C.begin(), C.end(), A);
48     }
49 };

比较次数是O(logm+logn),复制次数还是O(m+n),最终复杂度还是O(m+n),空间复杂度为O(m+n)。

在时间复杂度上我已经尽力了,于是就想有没有空间复杂度为O(1)的方法呢?

很自然就会想到利用数组移动,为了减小移动的数量,我们还可以结合以上说到的二分查找。

过程与以上类似,只是中间过程需要不断改变A的长度,而且要特别的注意下标问题。

 1 class Solution {
 2 public:
 3     int search(int* A, int n, int target) {
 4         int begin = 0, end = n;
 5         int mid;
 6         while (begin < end) {
 7             mid = begin + ((end - begin) >> 1);
 8             if (A[mid] < target) {
 9                 begin = mid + 1;
10             } else if (A[mid] > target) {
11                 end = mid;
12             } else {
13                 break;
14             }
15         }
16         
17         if (begin >= end) {
18             return end;
19         }
20         return mid;
21     }
22     
23     
24     void merge(int A[], int m, int B[], int n) {
25         vector<int> C;
26         int i = 0, j = 0;
27         while (i < m && j < n) {
28             int ansA = search(A + i, m - i, B[j]);
29             while (i + ansA < m && A[i + ansA] == B[j])
30                 ansA++;
31             if (ansA < m - i) {
32                 int ansB = search(B + j, n - j, A[i + ansA]);
33                 if (ansB > 0) { 
34                     for (int k = m - 1; k >= i + ansA; --k) {
35                         A[k + ansB] = A[k];
36                     }
37                     for (int k = 0; k < ansB; ++k) {
38                         A[i + ansA + k] = B[j + k];
39                     }
40                     j += ansB;
41                 }
42                 i += ansA + ansB;
43                 m += ansB;
44             } else {
45                 i += ansA;
46                 break;
47             }
48         }
49         
50         while (j < n) {
51             A[i++] = B[j++];
52         }
53     }
54 };

时间复杂度为O(m+n),空间复杂度为O(1)。

不过最终在LeetCode上跑的运行时间,对于这三段代码都是没有明显的区别,有时候简单粗暴的方法还更快一些。所以大家看着玩就好。

 
posted @ 2014-03-22 02:19  flowerkzj  阅读(178)  评论(0编辑  收藏  举报