题目:难度(Hard)
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]
Tags:Dynamic Programming, Greedy
分析:
1)分别从nums1(长度为m)和nums2(长度为n)中挑选出i(max(0, k - n) <= i <= min(m, k) 和k-i个数,使得在各个数组中挑选出的元素保持相对顺序不变的情况下,使选出的子数组最大化取;(参考Remove Duplicate Letters的思路,利用栈保存最大值子数组)
2)在保持元素相对位置不变的前提下,将2个子数组合并,使合并的数组最大化,类似于归并排序。两个最大子数组“归并后”一定是最大的,可用反证法证明。再在所有归并的数组中选出“最大值”返回即可
总时间复杂度是O(n*k)
代码实现:
class Solution(object):
def maxNumber(self, nums1, nums2, k):
"""
:type nums1: List[int]
:type nums2: List[int]
:type k: int
:rtype: List[int]
"""
#在数组nums中返回最大子数组,参考Remove Duplicate Letters的思路,利用栈保存最大值子数组,
#时间复杂度为O(n),其中n为数组的长度。
#返回的子数组中元素的相对位置与原数组保持一致,同时它应“最大”
def getMaxSubArray(nums, k1):
stack = []
for i in range(len(nums)):
while stack and nums[i] > stack[-1] and len(nums)-(i+1) >= k1-len(stack):
stack.pop()
#此时nums[i]是以nums[i]为首的“后缀数串”中最大的数
if len(stack) < k1:
stack.append(nums[i])
return stack
#注意:Python list可以直接比较大小,例如:[1,2]>[]返回True, [1,2]>None返回True,在此利用list的比较的便利
#由于这是一个特殊的归并,尤其是当真正比较的2个元素相等时,还要参考他们后面的元素的大小,此时就更凸显list比较的优势了
def merge2array(sub1, sub2):
result = []
while sub1 or sub2:
if sub1 >= sub2:
result.append(sub1[0])
sub1 = sub1[1:]
else:
result.append(sub2[0])
sub2 = sub2[1:]
return result
"""
分析:k<=m+n,在nums1数组中选取元素的个数不需要从0->k,仔细分析一下可知,
在nums1中应选取的最少元素个数:即当k>=len(nums2)时为k-len(nums2),当k<len(nums2)时为0
在nums1中应选取的最多元素个数:即当k>=len(nums1)时为len(nums1),当k<len(nums1)时为k
所以在nums1数组中选取元素的个数的范围时max(k-len(nums2), 0)-->min(len(nums1), k)
"""
len1, len2 = len(nums1), len(nums2)
k1_min = max(k-len2, 0)
k1_max = min(len1, k)
result = []
for k1 in range(k1_min, k1_max+1):
tmp = merge2array(getMaxSubArray(nums1, k1), getMaxSubArray(nums2, k-k1))
result = max(result, tmp)
return result
参考:
http://bookshadow.com/weblog/2015/12/24/leetcode-create-maximum-number/