321. Create Maximum Number
題目描述
Given two arrays of length m
and n
with digits 0-9
representing two numbers. Create the maximum number of length k <= m + n
from digits of the two. The relative order of the digits from the same array must be preserved. Return an array of the k
digits. You should try to optimize your time and space complexity.
Example 1:
nums1 = [3, 4, 6, 5]
nums2 = [9, 1, 2, 5, 8, 3]
k = 5
return [9, 8, 6, 5, 3]
Example 2:
nums1 = [6, 7]
nums2 = [6, 0, 4]
k = 5
return [6, 7, 6, 0, 4]
Example 3:
nums1 = [3, 9]
nums2 = [8, 9]
k = 3
return [9, 8, 9]
這個問題是要將兩個數組合成一個數,我們先得解決一個簡單一點的問題————從一個數組里挑出k個數字組成最大的數。
第一步
這個問題可以借助棧和貪心算法來實現。算法步驟:
- 新建一個空棧stack
- 遍歷數組
nums
- 彈出棧頂元素如果棧頂元素比
nums[i]
小,直到
1、棧空
2、剩余的數組不足以填滿棧至 k - 如果棧的大小小於 k ,則壓入
nums[i]
- 彈出棧頂元素如果棧頂元素比
- 返回棧stack
因為棧的長度知道是k,所以可以用數組來實現這個棧。時間復雜度為O(n),因為每個元素最多被push和pop一次。
實現代碼如下:
vector<int> maxArray(vector<int>& nums, int k){
int n = nums.size();
vector<int> result(k);
for (int i = 0, j = 0; i < n; i++){
while (n - i + j>k && j > 0 && result[j-1] < nums[i]) j--;
if (j < k) result[j++] = nums[i];
}
return result;
}
第二步
給定兩個數組,長度分別為m 和n,要得到 k = m+n的最大數。
顯然這個問題是原問題的特殊情況,顯然這種情況下,我們首先想到的是貪心算法。
我們要做k次選擇,每次我們就選兩個數組中較大的那個數即可。這是顯然的,但是如果兩個數相等,我們應該選擇哪個呢?
這就不是很顯然的了,舉個栗子,
nums1 = [6,7]
nums2 = [6,0,4]
k = 5
ans = [6,7,6,0,4]
所以相等的情況,我們就需要一直往后比,直到它們不相等分出大小為止。這就有點像歸並排序中的merge函數了。因為每次都得一直往后比,所以時間復雜度是O(mn)。
這部分代碼如下:
bool greater(vector<int>& nums1, int i, vector<int>& nums2, int j){
while (i < nums1.size() && j < nums2.size() && nums1[i] == nums2[j]){
i++;
j++;
}
return j == nums2.size() || (i<nums1.size() && nums1[i] > nums2[j]);
}
vector<int> merge(vector<int>& nums1, vector<int>& nums2, int k) {
std::vector<int> ans(k);
int i = 0, j = 0;
for (int r = 0; r<k; r++){
if( greater(nums1, i, nums2, j) ) ans[r] = nums1[i++] ;
else ans[r] = nums2[j++];
}
return ans;
}
第三步
讓我們回到原問題,我們首先把k個數分成兩部分,i 和 k-i,我們可以用第一步中的函數求出兩個數組中的長度為 i 和 k-i 的最大值。然后用第二步的方法將它們融合。最后我們從所有的結果中找出最大值。所以代碼如下:
vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) {
int m = nums1.size();
int n = nums2.size();
vector<int> result(k);
for (int i = std::max(0 , k - n); i <= k && i <= m; i++){
auto v1 = maxArray(nums1, i);
auto v2 = maxArray(nums2, k - i);
vector<int> candidate = merge(v1, v2, k);
if (greater(candidate, 0, result, 0)) result = candidate;
}
return result;
}