LeetCode每日一题(Python实现):321.拼接最大数

题目描述:

给定长度分别为 m 和 n 的两个数组,其元素由 0-9 构成,表示两个自然数各位上的数字。现在从这两个数组中选出 k (k <= m + n) 个数字拼接成一个新的数,要求从同一个数组中取出的数字保持其在原数组中的相对顺序。

求满足该条件的最大数。结果返回一个表示该最大数的长度为 k 的数组。

说明: 请尽可能地优化你算法的时间和空间复杂度。

示例 1:

输入:
nums1 = [3, 4, 6, 5]
nums2 = [9, 1, 2, 5, 8, 3]
k = 5
输出:
[9, 8, 6, 5, 3]
示例 2:

输入:
nums1 = [6, 7]
nums2 = [6, 0, 4]
k = 5
输出:
[6, 7, 6, 0, 4]
示例 3:

输入:
nums1 = [3, 9]
nums2 = [8, 9]
k = 3
输出:
[9, 8, 9]

思路:

令数组nums1的长度为m,数组nums2的长度为n,则需要从数组nums1中选出长度为x的子序列,以及从数组nums2中
选出长度为y的子序列。
其中,x + y = k 且 0<=x<=m , 0<=y<=n
需遍历所有可能的x、y的值
对于每一组x、y得到最大数
第一步是分别从两个数组中得到指定长度的最大子序列
第二步是将两个最大子序列合并

第一步:通过单调栈实现:单调栈从栈底到栈顶递减,从左到右遍历数组,遍历过程中维护单调栈内的元素。见getMaxSubsequence函数
第二步:自定义比较:首先比较两个子序列的当前元素,如果两个当前元素不同,则选其中较大的元素作为下一个合并的元素。
否则需要比较后面所有元素才能决定哪个元素作为下一个合并的元素。
见compare、merge函数

代码实现:

from typing import List
class Solution:
    def maxNumber(self,nums1: List[int], nums2: List[int], k: int) -> List[int]:
          m = len(nums1)
          n = len(nums2)
          MaxSubsequence = [0]*k
          #遍历所有x、y可能的值
          start,end = max(0,k-n), min(k,m)

          for i in range(start,end+1):
              #从nums1中获得长度为i的子序列
              subsequence1 = self.getMaxSubsequence(nums1,i)
              #从nums2中获得长度为k-i的子序列
              subsequence2 = self.getMaxSubsequence(nums2,k-i)
              #将两个序列合并
              curMaxSubsequence = self.merge(subsequence1,subsequence2)
              #更新当前最大序列
              if self.compare(curMaxSubsequence, 0, MaxSubsequence, 0) > 0:
                  MaxSubsequence = curMaxSubsequence

          return MaxSubsequence

    def getMaxSubsequence(self,nums: List[int], n: int):
        stack = [0]*n
        top = -1 #表示stack栈顶下标
        remain = len(nums) - n
        # 弹出最少的元素使得栈从底到顶单调递增
        for i,num in enumerate(nums):
            #栈顶小于当前元素
            while top >= 0 and stack[top] < num and remain > 0:
                   top -= 1
                   remain -= 1
            if top < n - 1:
                top += 1
                stack[top] = num
            else:
                 remain -=1

        return stack
    def merge(self,subsequence1: List[int], subsequence2: List[int]):
        merged = list()
        x,y = len(subsequence1),len(subsequence2)
        if(x == 0):
            return subsequence2
        if(y == 0):
            return subsequence1
        mergedlen = x+y
        p = q = 0
        for _ in range(mergedlen):
              if self.compare(subsequence1,p,subsequence2,q) > 0:
                  # subsequence1[p] > subsequence2[q]
                  merged.append(subsequence1[p])
                  p += 1
              else:
                  merged.append(subsequence2[q])
                  q+=1

        return merged

    def compare(self, subsequence1: List[int], index1: int, subsequence2: List[int], index2: int) -> int:
        x, y = len(subsequence1), len(subsequence2)
        while index1 < x and index2 < y:
            difference = subsequence1[index1] - subsequence2[index2]
            if difference != 0:
                return difference
            index1 += 1
            index2 += 1
        #x 或 y 有一个遍历到结尾时 看哪个先遍历结尾,先遍历到结尾的小
        return (x - index1) - (y - index2)

ans = Solution()
arr = input(" ")
list1 = [int(n) for n in arr.split()]
arr = input(" ")
list2 = [int(n) for n in arr.split()]
k = int(input())
print(list1)
print(list2)
print(ans.maxNumber(list1,list2,k))

感悟:

1、python对于数组的处理不太友好,学到了输入时要使用 list = [int (n) for  n in arr.split()]来实现
2、 学到了单调栈的使用,单调栈及栈底到栈顶单调递增(减)。在本题中,需要通过数组模拟单调栈,其实现过程需进一步理解。
3、 在合并过程中,其排序思想为:两个当前元素相减,如果>0 则前者加入,如果相等则继续向后比较。数组x 或 y 有一个遍历到结尾时 看哪个先遍历结尾,先遍历到结尾的小。

猜你喜欢

转载自blog.csdn.net/weixin_44795952/article/details/110492810