321. 拼接最大数 #
leetcode 链接: https://leetcode-cn.com/problems/create-maximum-number/
给定长度分别为 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]
方法一:单调栈
为了求得长度为 k 的最大子序列,需要从两个数组中分别选出最大的子序列,然后将这两个子序列合并得到最大数。两个子序列的长度最小为 0,最大不能超过 k 且不能超过对应的数组长度。所以整个算法就分成三步:
- 分别计算 num1 和 nums2 的最大子序列
- 按照字典序降序合并子序列
- 保存对应的整数较大的子序列
func maxNumber(nums1 []int, nums2 []int, k int) []int {
initialSize := 0
if len(nums2) < k {
initialSize = k - len(nums2)
}
var ans []int
for size := initialSize; size <= k && size <= len(nums1); size++ {
sub1 := maxSubSequence(nums1, size)
sub2 := maxSubSequence(nums2, k-size)
merged := merge(sub1, sub2)
if lexicographicalLess(ans, merged) {
ans = merged
}
}
return ans
}
// 按照字典序降序合并
func merge(sub1, sub2 []int) []int {
var merged = make([]int, len(sub1)+len(sub2))
for i := range merged {
if lexicographicalLess(sub1, sub2) {
merged[i], sub2 = sub2[0], sub2[1:]
} else {
merged[i], sub1 = sub1[0], sub1[1:]
}
}
return merged
}
// 判断字典序大小
func lexicographicalLess(sub1, sub2 []int) bool {
for i := 0; i < len(sub1) && i < len(sub2); i++ {
if sub1[i] != sub2[i] {
return sub1[i] < sub2[i]
}
}
return len(sub1) < len(sub2)
}
// 单调栈求指定长度的最大子序列
func maxSubSequence(nums []int, k int) []int {
var sub []int
for i := range nums {
for len(sub) > 0 && nums[i] > sub[len(sub)-1] && len(sub)+len(nums)-i-1 >= k {
sub = sub[:len(sub)-1]
}
if len(sub) < k {
sub = append(sub, nums[i])
}
}
return sub
}