题目:
给定长度分别为 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]
提示:
0 <= nums.length <= 105 -109 <= nums[i] <= 109 nums 是一个非递减数组 -109 <= target <= 109
抛砖引玉
思路:
假设已知分类从 nums1 和 nums2 中取出 x,y 个元素(x+y=k) 那么问题就转换成了:
从数组中取出 x 个元素,使取出的元素组成的数字最大 合并两个数组,保持两数组相对位置不变,使合并后的元素组成的数字最大
解决上面两个问题:
单调栈:从栈底到栈顶的元素单调递减,栈长度 x 从两个栈顶开始取,每次取栈顶较大的元素
那么现在就只剩一个我们最开始设置的假设条件了,x,y (x<=k,y<=k)均是未知的,枚举从两个数组取出元素个数的所有组合,最后再第 2 步时只要保证 x+y=k,保留遇到的最大拼接结果
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @param {number} k
* @return {number[]}
*/
var maxNumber = function(nums1, nums2, k) {
let _result = [],
map1 = findMax(nums1, k),
map2 = findMax(nums2, k),
max = 0
// 枚举x、y的可能组合
for (let x = 0; x <= k; x++) {
const y = k - x
if (x <= nums1.length && y <= nums2.length) {
const merge = mergeMax(map1.get(x) || [], map2.get(y) || [], k)
const num = merge.join('')
if (num > max) {
max = num
_result = merge
}
}
}
// 1. 单调栈:从数组重取出 x 个元素,使取出的元素组成的数字最大
function findMax(nums, k) {
let len = nums.length,
map = new Map()
if (len === 0) return map
for (let i = 1; i <= k; i++) {
let stack = [nums[0]]
for (let j = 1; j < len; j++) {
// 新元素大于栈底元素,且后面剩余的元素大于填满本轮栈的所需个数
while (
nums[j] > stack[stack.length - 1] &&
len - j > i - stack.length
) {
stack.pop()
}
if (stack.length < i) {
stack.push(nums[j])
}
}
// 选择个数 -> 最大组合
map.set(i, stack)
}
return map
}
// 2. 从两个栈顶开始,每次取栈顶较大的元素
function mergeMax(stack1, stack2, k) {
if (!stack1 || !stack2) return stack1 || stack2
let result = []
while (stack1.length > 0 || stack2.length > 0) {
if (stack1.length === 0) return [...result, ...stack2]
if (stack2.length === 0) return [...result, ...stack1]
if (stack1.join('') >= stack2.join('')) {
result.push(stack1.shift())
} else {
result.push(stack2.shift())
}
}
return result
}
return _result
}
博客: 前端小书童
每天的每日一题,写的题解会同步更新到公众号一天一大 lee 栏目 欢迎关注留言
公众号:前端小书童
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!