496. 下一个更大元素 I
题目描述
给定两个没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。
找到 nums1 中每个元素在 nums2 中的下一个比其大的值。
nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个
比 x 大的元素。如果不存在,对应位置输出 -1 。
示例 1:
输入: nums1 = [4,1,2], nums2 = [1,3,4,2].
输出: [-1,3,-1]
解释:
对于num1中的数字4,你无法在第二个数组中找到下一个更大的数字,因此输出 -1。
对于num1中的数字1,第二个数组中数字1右边的下一个较大数字是 3。
对于num1中的数字2,第二个数组中没有下一个更大的数字,因此输出 -1。
示例 2:
输入: nums1 = [2,4], nums2 = [1,2,3,4].
输出: [3,-1]
解释:
对于 num1 中的数字 2 ,第二个数组中的下一个较大数字是 3 。
对于 num1 中的数字 4 ,第二个数组中没有下一个更大的数字,因此输出 -1 。
提示:
nums1和nums2中所有元素是唯一的。
nums1和nums2 的数组大小都不超过1000。
Related Topics 栈
暴力解法最容易想到,而且相对来说理解简单:
class Solution:
def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
# 暴力解法
res = []
for num1 in nums1:
for i in range(nums2.index(num1)+1, len(nums2)):
if nums2[i] > num1:
res.append(nums2[i])
break
else:
res.append(-1)
return res
其时间复杂度为 ,而优化方法便是单调栈。若把数组看成不同高度的人的排队结果,每个元素的下一个更大的元素便是他回头看到的第一个高个子。中间的矮个儿即可忽略(也即被挡住)。
解题中需要注意的是入栈顺序是倒叙。因此下一个元素入栈前比其小的元素均要出栈,因为这些元素均是在这个元素的后面,这个元素入栈后比其小的元素均被其挡住。
class Solution:
def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
hashmap = {}
stack = []
for i in range(len(nums2)-1, -1, -1):
while stack and stack[-1] < nums2[i]:
stack.pop()
hashmap[nums2[i]] = -1 if not stack else stack[-1]
stack.append(nums2[i])
# print(hashmap)
res = []
for num in nums1:
res.append(hashmap[num])
return res
单调栈解法时间复杂度为 ,因为对于每个元素来说,最多只有入栈和出栈两个操作。
503. 下一个更大元素 II
题目描述
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。
数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循
环地搜索它的下一个更大的数。如果不存在,则输出 -1。
示例 1:
输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
注意: 输入数组的长度不会超过 10000。
Related Topics 栈
对于循环数组元素的下一个元素就不仅仅是其右边的元素了,也可能是其左边的元素。为了实现能同时搜索其左右元素,我们可以将原数组复制一份加入到原数组的后面,然后按照 496. 下一个更大元素 I 的解法:
class Solution:
def nextGreaterElements(self, nums: List[int]) -> List[int]:
# 利用 496.下一个更大元素I 中的解法,将数组复制一份加入到原数组后面
stack = []
nums = nums + nums
n = len(nums)
res = [-1] * n
for i in range(n-1, -1, -1):
while stack and stack[-1] <= nums[i]:
stack.pop()
res[i] = -1 if not stack else stack[-1]
stack.append(nums[i])
# print(res)
return res[:n//2]
在实际中面对循环数组,一般是采用取余 (%) 来实现。所以本题中我们也可以不复制数组,而采用取余来实现:
class Solution:
def nextGreaterElements(self, nums: List[int]) -> List[int]:
stack = []
n = len(nums)
res = [-1] * n
for i in range(2*n-1, -1, -1):
while stack and stack[-1] <= nums[i % n]:
stack.pop()
res[i % n] = -1 if not stack else stack[-1]
stack.append(nums[i % n])
# print(res)
return res
402. 移掉K位数字
给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。
注意:
num 的长度小于 10002 且 ≥ k。
num 不会包含任何前导零。
示例 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。
Related Topics 栈 贪心算法
题目分析
首先我们需要确定什么样的数字应该被移除。当我们考察位置 的数字时,若其前面有数字,如果移除前面的数字能获得更小的结果,那前面的数字应该被移除。由于每次对比都是临近的数字,则考虑使用栈来解决问题。
class Solution:
def removeKdigits(self, num: str, k: int) -> str:
n = len(num)
if n == k:
return '0'
stack = []
for c in num:
while stack and stack[-1] > c and k > 0:
stack.pop()
k -= 1
if not stack and c == '0':
continue
stack.append(c)
# 还有要删除的元素,就从栈顶删除
for _ in range(k):
stack.pop()
return '0' if not stack else ''.join(stack)
1081. 不同字符的最小子序列
题目描述
返回字符串 text 中按字典序排列最小的子序列,该子序列包含 text 中所有不同字符一次。
示例 1:
输入:"cdadabcc"
输出:"adbc"
示例 2:
输入:"abcd"
输出:"abcd"
示例 3:
输入:"ecbacba"
输出:"eacb"
示例 4:
输入:"leetcode"
输出:"letcod"
提示:
1 <= text.length <= 1000
text 由小写英文字母组成
注意:本题目与 316 https://leetcode-cn.com/problems/remove-duplicate-letters/ 相同
Related Topics 栈 贪心算法 字符串
题目分析
本题需要考虑的重点是怎么确定该字符是否需要删除。如果后面还有该字符,则前面比当前大的字符应该被删除,以保留字典序最小的结果。鉴于此,我们考虑对所有字符进行计数,用于判断后面是否还有该字符。
class Solution:
def smallestSubsequence(self, s: str) -> str:
# 计数
hashmap = {}
for c in s:
hashmap.setdefault(c, 0)
hashmap[c] += 1
stack = []
inStack = {}
for c in s:
hashmap[c] -= 1
if inStack.get(c):
continue
while stack and stack[-1] > c:
if hashmap[stack[-1]] == 0:
break
inStack[stack.pop()] = False
stack.append(c)
inStack[c] = True
return ''.join(stack)
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]
Related Topics 贪心算法 动态规划
本题留着挑战吧。
参考
- 单调栈解决 Next Greater Number 一类问题