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上跑的运行时间,对于这三段代码都是没有明显的区别,有时候简单粗暴的方法还更快一些。所以大家看着玩就好。