leetcode笔记--Create Maximum Number

题目:难度(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/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值