🌙 栈 (opens new window)
🌙 1.有效的括号 (opens new window)
/**
* @param {string} s
* @return {boolean}
*/
var isValid = function (s) {
let map = {
"}": "{",
")": "(",
"]": "["
}
let stack = []
for (let i = 0; i < s.length; i++) {
let str = s[i]
// 遇到右括号
if (map[str]) {
// 左括号出栈判断匹配
if (map[str] !== stack.pop()) {
return false
}
} else {
// 左括号进栈
stack.push(str)
}
}
return stack.length === 0
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
🌙 2.下一个更大的元素 (opens new window)
nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。
给你两个 没有重复元素 的数组 nums1 和 nums2 ,下标从 0 开始计数,其中nums1 是 nums2 的子集。
对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j] 的 下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1 。
返回一个长度为 nums1.length 的数组 ans 作为答案,满足 ans[i] 是如上所述的 下一个更大元素 。
示例 1:
输入:nums1 = [4,1,2], nums2 = [1,3,4,2].
输出:[-1,3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:
- 4 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
- 1 ,用加粗斜体标识,nums2 = [1,3,4,2]。下一个更大元素是 3 。
- 2 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- 单调栈
var nextGreaterElement = function (nums1: number[], nums2: number[]): number[] {
let map = new Map()
let arr = []
arr.push(nums2[0])
// 从下一个开始
for (let i = 1; i < nums2.length; i++) {
let top = arr[arr.length - 1]
// 下一个小了,没找到记录一下
if (nums2[i] < top) {
arr.push(nums2[i])
}
// 下一个相等,没找到记录一下
if (nums2[i] === top) {
arr.push(nums2[i])
}
// 下一个大了,找到了
if (nums2[i] > top) {
// 记录一下
map.set(top, nums2[i])
arr.pop()
// 继续看arr中没找到的,有没有符合条件的
while (arr.length > 0 && arr[arr.length - 1] < nums2[i]) {
// 找到了,记录并且删除
map.set(arr[arr.length - 1], nums2[i])
arr.pop()
}
}
arr.push(nums2[i])
}
let res = []
// 从map中找到num1的每个元素对应的下一个更到的元素
for (let i = 0; i < nums1.length; i++) {
if (map.has(nums1[i])) {
res[i] = map.get(nums1[i])
} else {
res[i] = -1
}
}
return res
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
优化一下上述代码:
var nextGreaterElement = function(nums1: number[], nums2: number[]): number[] {
let map = new Map()
let arr =[]
arr.push(nums2[0])
// 从下一个开始
for(let i=1; i<nums2.length; i++) {
// let top = arr[arr.length - 1]
// // 下一个小了,没找到记录一下
// if(nums2[i] < top) {
// arr.push(nums2[i])
// }
// // 下一个相等,没找到记录一下
// if(nums2[i] === top) {
// arr.push(nums2[i])
// }
// 下一个大了,找到了
// if(nums2[i] > top) {
// 记录一下
// map.set(top, nums2[i])
// arr.pop()
// 继续看arr中没找到的,有没有符合条件的
while(arr.length > 0 && arr[arr.length - 1] < nums2[i]) {
// 找到了,记录并且删除
map.set(arr[arr.length - 1], nums2[i])
arr.pop()
}
// }
arr.push(nums2[i])
}
let res = []
// 从map中找到num1的每个元素对应的下一个更到的元素
for(let i=0; i<nums1.length; i++) {
if(map.has(nums1[i])) {
res[i] = map.get(nums1[i])
} else {
res[i] = -1
}
}
return res
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
即经典的单调栈代码模板:
var nextGreaterElement = function (nums1: number[], nums2: number[]): number[] {
let map = new Map()
let stack = []
for (let i = 0; i < nums2.length; i++) {
while (stack.length > 0 && stack[stack.length - 1] < nums2[i]) {
// 找到了,记录并且删除
map.set(stack[stack.length - 1], nums2[i])
stack.pop()
}
stack.push(nums2[i])
}
let res = []
// 从map中找到num1的每个元素对应的下一个更到的元素
for (let i = 0; i < nums1.length; i++) {
res[i] = map.has(nums1[i]) ? map.get(nums1[i]) : -1
}
return res
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
🌙 3.下一个更大元素 II (opens new window)
给定一个循环数组 nums ( nums[nums.length - 1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的 下一个更大元素 。
数字 x 的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1 。
示例 1:
输入: nums = [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
- 单调栈
function nextGreaterElements(nums: number[]): number[] {
let stack = []
let len = nums.length
let res = new Array(len).fill(-1)
// stack.push(nums[0])
// for(let i=1; i<len * 2; i++) {
for(let i=0; i<len * 2; i++) {
let n = nums[i % len]
while(stack.length > 0 && n > nums[stack[stack.length - 1]]) {
res[stack[stack.length - 1]] = n
stack.pop()
}
stack.push(i % len)
}
return res
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
🌙 4.下一个更大元素 III (opens new window)
给你一个正整数 n ,请你找出符合条件的最小整数,其由重新排列 n 中存在的每位数字组成,并且其值大于 n 。如果不存在这样的正整数,则返回 -1 。
注意 ,返回的整数应当是一个 32 位整数 ,如果存在满足题意的答案,但不是 32 位整数 ,同样返回 -1 。
示例 1:
输入:n = 12
输出:21
示例 2:
输入:n = 21
输出:-1
提示:
1 <= n <= 231 - 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function nextGreaterElement(n: number): number {
// 32位正数
if (n > 2 ** 31 - 1) return -1
// 数字转为字符串复杂度:log10n
let arr = n.toString().split('').map(Number)
nextPermutation(arr)
let res = +arr.join('')
return res > MAX ? -1 : res > n ? res : -1
};
// 下一个排列: https://leetcode.cn/problems/next-permutation/description/
function nextPermutation(nums: number[]): void {
let i = nums.length - 1
let flag = false
for (; i > 0; i--) {
if (nums[i] > nums[i - 1]) {
// 找到比前一个大的数了
// i 之后的肯定都符合 nums[i] >= nums[i+1]
// 逆序即可以达到升序排列
reverse(nums, i, nums.length - 1)
flag = true
break
}
}
if (flag) {
for (let j = i; j < nums.length; j++) {
if (nums[j] > nums[i - 1]) {
[nums[j], nums[i - 1]] = [nums[i - 1], nums[j]]
return
}
}
}
reverse(nums, 0, nums.length - 1)
return
};
function reverse(nums: number[], s: number, e: number) {
while (s < e) {
[nums[s], nums[e]] = [nums[e], nums[s]]
s++
e--
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
🌙 2.每日温度 (opens new window)
给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。
示例 1:
输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
示例 2:
输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]
示例 3:
输入: temperatures = [30,60,90]
输出: [1,1,0]
提示:
1 <= temperatures.length <= 105
30 <= temperatures[i] <= 100
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 单调栈
/**
* @param {number[]} temperatures
* @return {number[]}
*/
var dailyTemperatures = function(temperatures) {
if(!temperatures || temperatures.length < 1) return []
let len = temperatures.length
let res = new Array(len).fill(0)
// 单调栈
let stack = []
stack.push(0)
for(let i=1; i<len; i++) {
// 右边的小或等,直接入栈
if(temperatures[i] <= temperatures[stack[stack.length - 1]]) {
stack.push(i)
} else {
// 找到第一个更大的了,准备出栈
while(stack.length > 0) {
let top = stack[stack.length - 1]
if(temperatures[i] > temperatures[top]) {
res[top] = i - top
stack.pop()
} else {
break
}
}
stack.push(i)
}
}
return res
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
优化一下:
/**
* @param {number[]} temperatures
* @return {number[]}
*/
var dailyTemperatures = function(temperatures) {
if(!temperatures || temperatures.length < 1) return []
let len = temperatures.length
let res = new Array(len).fill(0)
// 单调栈
let stack = []
stack.push(0)
for(let i=1; i<len; i++) {
// 找到比栈顶元素更大的第一个元素,将栈顶元素出栈,以此类推直至栈里面没有更大的了
while(stack.length > 0 && temperatures[i] > temperatures[stack[stack.length - 1]]) {
const top = stack.pop()
res[top] = i - top
}
stack.push(i)
}
return res
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
🌙 3.逆波兰表达式求值 (opens new window)
给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
注意:
有效的算符为 '+'、'-'、'*' 和 '/' 。
每个操作数(运算对象)都可以是一个整数或者另一个表达式。
两个整数之间的除法总是 向零截断 。
表达式中不含除零运算。
输入是一个根据逆波兰表示法表示的算术表达式。
答案及所有中间计算结果可以用 32 位 整数表示。
示例 1:
输入:tokens = ["2","1","+","3","*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2:
输入:tokens = ["4","13","5","/","+"]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
示例 3:
输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
输出:22
解释:该算式转化为常见的中缀算术表达式为:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
提示:
1 <= tokens.length <= 104
tokens[i] 是一个算符("+"、"-"、"*" 或 "/"),或是在范围 [-200, 200] 内的一个整数
逆波兰表达式:
逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。
平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:
去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/**
* @param {string[]} tokens
* @return {number}
*/
var evalRPN = function (tokens) {
// 栈;
// 遇到数字则入栈;
// 遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中。
let stack = [];
let op = '+-*/';
for (let str of tokens) {
if (op.indexOf(str) > -1) {
// 出栈
let b = stack.pop();
let a = stack.pop();
// 入栈
if (str === '+') {
stack.push(a + b)
} else if (str === '-') {
stack.push(a - b)
} else if (str === '*') {
stack.push(a * b)
} else {
stack.push(~~(a / b))
}
} else {
stack.push(+str);
}
}
// 出栈
return stack.pop();
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
🌙 4.盛最多水的容器 (opens new window)
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- 双指针
/**
* @param {number[]} height
* @return {number}
*/
var maxArea = function(height) {
let n = height.length
let left = 0;
let right = n - 1
let res = 0
while(left < right) {
let cur = (right - left) * Math.min(height[left], height[right])
res = res > cur ? res : cur
if(height[left] < height[right]) left++
else right--
}
return res
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
🌙 5.接雨水 (opens new window)
- 单调栈:
var trap = function (height) {
const len = height.length;
if (len <= 2) return 0;
let res = 0;
const stack = [];
for (let i = 0; i < len; i++) {
// 找到第一个大的元素
while (stack.length > 0 && height[i] > height[stack[stack.length - 1]]) {
let top = stack.pop();
if (stack.length > 0) {
let h = Math.min(height[stack[stack.length - 1]], height[i]) - height[top];
let w = i - stack[stack.length - 1] - 1; // 注意减一,只求中间宽度
res += h * w;
}
}
stack.push(i);
}
return res;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- 双指针:
当前列雨水面积 = min(当前列左边柱子的最高高度,当前列右边柱子的最高高度) - 当前柱子高度。
/**
* @param {number[]} height
* @return {number}
*/
var trap = function (height) {
let ans = 0;
let left = 0, right = height.length - 1;
let leftMax = 0, rightMax = 0;
while (left < right) {
leftMax = Math.max(leftMax, height[left]);
rightMax = Math.max(rightMax, height[right]);
if (leftMax < rightMax) {
ans += leftMax - height[left];
left++;
} else {
ans += rightMax - height[right];
right--;
}
}
return ans;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
🌙 6.柱状图中最大的矩形 (opens new window)
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积
输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10
1
2
3
4
5
6
7
2
3
4
5
6
7
- 暴力求解
function largestRectangleArea(heights: number[]): number {
if (!heights || heights.length < 1) return 0
let res = 0
for (let i = 0; i < heights.length; i++) {
// 以heights[i]作为高度,计算可以左右扩散的最大宽度
let left = i;
// 向左边扩散
while (left > 0 && heights[left - 1] >= heights[i]) {
left--
}
// 向右扩散
let right = i
while (right < heights.length - 1 && heights[right + 1] >= heights[i]) {
right++
}
// 计算heights[i]左右扩散的宽度
let width = right - left + 1
res = Math.max(res, width * heights[i])
}
return res
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- 单调栈
function largestRectangleArea(heights: number[]): number {
if (!heights || heights.length < 1) return 0
let res = 0
// 单调递减栈: 找每个柱子左右两边第一个小于该柱子的柱子
let stack = []
let arr = [0, ...heights, 0]
for (let i = 0; i < arr.length; i++) {
// 找到第一个小的元素
while (stack.length > 0 && arr[i] < arr[stack[stack.length - 1]]) {
let top = stack.pop()
if(stack.length > 0) {
res = Math.max(res, heights[top] * (i - stack[stack.length - 1] - 1))
}
}
stack.push(i)
}
return res
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
🌙 7.去除重复字母 (opens new window)
给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的
字典序
最小(要求不能打乱其他字符的相对位置)。
示例 1:
输入:s = "bcabc"
输出:"abc"
示例 2:
输入:s = "cbacdcbc"
输出:"acdb"
提示:
1 <= s.length <= 104
s 由小写英文字母组成
注意:该题与 1081 https://leetcode-cn.com/problems/smallest-subsequence-of-distinct-characters 相同
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function smallestSubsequence(s: string): string {
let stack: string[] = []
let cache = new Map<string, boolean>()
let counter = new Map<string, number>()
for(let i=0; i<s.length; i++) {
counter.set(s[i], (counter.get(s[i]) || 0) + 1)
}
for(let i=0; i<s.length; i++) {
counter.set(s[i], counter.get(s[i]) - 1)
if(cache.get(s[i])) continue
while(stack.length > 0 && s[i] < stack[stack.length - 1]) {
let top = stack[stack.length - 1]
if(counter.get(top) === 0) break
stack.pop()
cache.set(top, false)
}
stack.push(s[i])
cache.set(s[i], true)
}
return stack.join('')
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
🌙 8.拼接最大数 (opens new window)
给定长度分别为 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]
提示:
m == nums1.length
n == nums2.length
1 <= m, n <= 500
0 <= nums1[i], nums2[i] <= 9
1 <= k <= m + n
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function maxNumber(nums1: number[], nums2: number[], k: number): number[] {
let res = new Array(k).fill(0)
let len1 = nums1.length
let len2 = nums2.length
// 假设t表示从nums1取几个数,则t取值范围:
// max(0, k-nums2.length) <= t <= min(k, nums1.length)
let start = Math.max(0, k - len2)
let end = Math.min(k, len1)
for (let i = start; i <= end; i++) {
// if (i > len1 || k - i > len2) continue
let sub1 = maxSubArray(nums1, i)
let sub2 = maxSubArray(nums2, k - i)
let cur = merge(sub1, sub2)
res = max(res, cur)
}
return res
};
// 求序列表示数最大的k位子序列: 单调栈
function maxSubArray(nums: number[], k: number): number[] {
// 需要删除rm个数
let rm = nums.length - t
let stack = []
for (let i = 0; i < nums.length; i++) {
while (rm > 0 && stack.length > 0 && nums[i] > stack[stack.length - 1]) {
stack.pop()
rm--
}
stack.push(nums[i])
}
while (rm > 0) {
stack.pop()
rm--
}
return stack
}
// 合并两个序列,保持元素在各个序列中的相对位置不变,返回最大的序列
function merge(nums1, nums2) {
let res = [];
let p1 = 0, p2 = 0;
while (p1 < nums1.length && p2 < nums2.length) {
if (compare(nums1, p1, nums2, p2) >= 0) {
res.push(nums1[p1++]);
} else {
res.push(nums2[p2++]);
}
}
while (p1 < nums1.length) {
res.push(nums1[p1++]);
}
while (p2 < nums2.length) {
res.push(nums2[p2++]);
}
return res;
}
function compare(nums1: number[], p1: number, nums2: number[], p2: number) {
while (p1 < nums1.length && p2 < nums2.length && nums1[p1] === nums2[p2]) {
p1++;
p2++;
}
if (p1 === nums1.length) return -1;
if (p2 === nums2.length) return 1;
return nums1[p1] - nums2[p2];
}
// 2个序列长度相同,返回表示数更大的序列
function max(nums1: number[], nums2: number[]): number[] {
let len1 = nums1.length
let len2 = nums2.length
if (len1 < len2) return nums2
if (len1 > len2) return nums1
for (let i = 0; i < len1; i++) {
if (nums1[i] > nums2[i]) return nums1
if (nums1[i] < nums2[i]) return nums2
}
return nums1
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
🌙 9.移掉 K 位数字 (opens new window)
给你一个以字符串表示的非负整数 num 和一个整数 k ,移除这个数中的 k 位数字,使得剩下的数字最小。请你以字符串形式返回这个最小的数字。
示例 1 :
输入:num = "1432219", k = 3
输出:"1219"
解释:移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219 。
示例 2 :
输入:num = "10200", k = 1
输出:"200"
解释:移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。
示例 3 :
输入:num = "10", k = 2
输出:"0"
解释:从原数字移除所有的数字,剩余为空就是 0 。
提示:
1 <= k <= num.length <= 105
num 仅由若干位数字(0 - 9)组成
除了 0 本身之外,num 不含任何前导零
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function removeKdigits(num: string, k: number): string {
let stack = []
for(let i = 0; i < num.length; i++) {
while(k > 0 && stack.length > 0 && stack[stack.length - 1] > num[i]) {
stack.pop()
k--
}
stack.push(num[i])
}
while(k > 0) {
stack.pop()
k--
}
while(stack[0] === '0') {
stack.shift()
}
return stack.length === 0 ? '0' : stack.join('')
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19