一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第20天,点击查看活动详情。
说明:文章部分内容及图片出自网络,如有侵权请与我本人联系(主页有公众号:小攻城狮学前端)
作者:小只前端攻城狮、 主页:小只前端攻城狮的主页、 来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【LeetCode 321. 拼接最大数 】- JavaScript(分治+单调栈)
给定长度分别为 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]
思路分析
这道题目有下面是个核心问题,解了它们这题就不在话下了。
- 怎么求出其中一个数组的最优解
- 怎么进行合并已经求出的两个数组的结果
- 如何进行数组的比较
可以说让人崩溃,做完这道题,相当于写了三道题。如果面试遇到这种题目,你应该懂面试官什么意思了,他对你不满意。
分而治之
思路:复杂问题解不了,我就给你拆解成一个一个小问题,解完再合并,非常经典的分治思想。
具体步骤:两者同时移动,如果后续有不同的元素则从元素更大那个数组中选,如果后续一直相等直到有一个越界,则从长度更长的那个数组中选,如果同时越界显然从哪个数组中选都是可以的
var maxNumber = function (nums1, nums2, k) {
let m = nums1.length, n = nums2.length;
let res = new Array(k).fill(0);
for (let i = Math.max(0, k - n); i <= k && i <= m; i++) {
let arr = merge(maxArr(nums1, i), maxArr(nums2, k - i), k);
if (compare(arr, 0, res, 0)) res = arr;
}
return res;
};
function maxArr(nums, k) {
let n = nums.length;
let res = new Array(k).fill(0);
for (let i = 0, j = 0; i < n; i++) {
while (n - i + j > k && j > 0 && nums[i] > res[j - 1]) j--;
if (j < k) res[j++] = nums[i]
}
return res
}
function merge(nums1, nums2, k) {
let res = new Array(k).fill(0);
for (let i = 0, j = 0, r = 0; r < k; r++) {
res[r] = compare(nums1, i, nums2, j) ? nums1[i++] : nums2[j++];
}
return res;
}
function compare(nums1, i, nums2, j) {
while (i < nums1.length && j < nums2.length && nums1[i] == nums2[j]) { i++; j++; }
return j == nums2.length || (i < nums1.length && nums1[i] > nums2[j])
}
贪心+DP
分析
动规从第一个数组取i个数,从第二个数组取k-i个数。 要取i个数,要从第一个数组取到i个最大数。取剩下K-i个数,要从第二个数组中取k-i个数。对于取到的两个vector进行组合,拿到当前组合的最大排序值。判断当前拿到的序列是否是最大序列值。
**注意:**代码虽然写起来简单,但是整体的效率没有分治来得好。可以试试,观察一下dp里面索引是怎么转化的
var maxNumber = function(nums1, nums2, k) {
let getMaxNum = (nums, k) => {
if (k == 0) return []
let ans = []
let tmp = nums.length - k
for (let num of nums) {
while (ans.length > 0 && num > ans[ans.length - 1] && (tmp--) > 0) {
ans.pop()
}
ans.push(num)
}
ans = ans.slice(0, k)
return ans
}
let compare = (i, j, nums1, nums2) => {
while (i < nums1.length && j < nums2.length && nums1[i] == nums2[j]) {
i++;
j++;
}
return j == nums2.length || (i < nums1.length && nums1[i] > nums2[j]);
}
let formatNum = (nums1, nums2) => {
let t1 = 0
let t2 = 0
let l1 = nums1.length
let l2 = nums2.length
let ans = []
if (l1 == 0 || l2 == 0) return nums1.concat(nums2)
while (t1 < l1 && t2 < l2) {
if (compare(t1, t2, nums1, nums2)) {
ans.push(nums1[t1])
t1++
} else {
ans.push(nums2[t2])
t2++
}
}
ans = ans.concat(nums2.slice(t2)).concat(nums1.slice(t1))
return ans
}
let res = []
let n1 = nums1.length
let n2 = nums2.length
for (let i = 0; i <= k; i++) {
const k1 = k - i
if (i > n1 || k1 > n2) continue
let v1 = res.join('')
let v2 = formatNum(getMaxNum(nums1, i), getMaxNum(nums2, k1)).join('')
console.log(formatNum(getMaxNum(nums1, i), getMaxNum(nums2, k1)))
if (v1 < v2) {
res = formatNum(getMaxNum(nums1, i), getMaxNum(nums2, k1))
}
}
return res
}
感谢阅读,希望能对你有所帮助,文章若有错误或者侵权,可以在评论区留言或在我的主页添加公众号联系我。
写作不易,如果觉得不错,可以「点赞」+「评论」 谢谢支持❤