首先,我们将栈相关的,难度为简单的4道题,一起做了,然后汇总成博客的形式。一起练一波,过完简单的题目之后,然后我们再去过中等的题目。
232.用栈实现队列
使用栈实现队列的下列操作:
- push(x) -- 将一个元素放入队列的尾部。
- pop() -- 从队列首部移除元素。
- peek() -- 返回队列首部的元素。
- empty() -- 返回队列是否为空。
示例:
MyQueue queue = new MyQueue(); queue.push(1); queue.push(2); queue.peek(); // 返回 1 queue.pop(); // 返回 1 queue.empty(); // 返回 false
说明:
- 你只能使用标准的栈操作 -- 也就是只有
push to top
,peek/pop from top
,size
, 和is empty
操作是合法的。- 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
- 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。
class MyQueue(object):
def __init__(self):
"""
Initialize your data structure here.
"""
self.list = []
def push(self, x):
"""
Push element x to the back of queue.
:type x: int
:rtype: None
"""
self.list.append(x)
def pop(self):
"""
Removes the element from in front of queue and returns that element.
:rtype: int
"""
return self.list.pop(0)
def peek(self):
"""
Get the front element.
:rtype: int
"""
return self.list[0]
def empty(self):
"""
Returns whether the queue is empty.
:rtype: bool
"""
return not self.list
# Your MyQueue object will be instantiated and called as such:
# obj = MyQueue()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.peek()
# param_4 = obj.empty()
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。
这道题,读了一会题,感觉好绕。我理解的就是,数组1中的元素,在数组2中,然后其右边的这个数是否比它大。如果是,然后比它大的那个数,如果不是,返回-1.
class Solution(object):
def nextGreaterElement(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: List[int]
"""
re = []
for i in range(len(nums1)):
next_ = nums2.index(nums1[i])
if next_ < len(nums2)-1:
next_ +=1
if nums2[next_] > nums1[i] :
re.append(nums2[next_])
else:
re.append(-1)
return re
提交后,发现有一个用例没有通过。
解答错误
输入
[1,3,5,2,4]
[6,5,4,3,2,1,7]输出
[7,-1,-1,-1,-1]
预期结果
[7,7,7,7,7]
这个用例,说明,不是右边一个,是指只有nums2右边有比它大的数,那么就返回这个数,否则才返回-1.所以需要重新修改代码。
class Solution(object):
def nextGreaterElement(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: List[int]
[4,1,2]
[1,3,4,2]
"""
re = []
for i in range(len(nums1)):
next_ = nums2.index(nums1[i])
if next_ < len(nums2)-1:
for j in range(next_+1,len(nums2)):
if nums2[j]> nums1[i]:
re.append(nums2[j])
break
else:
re.append(-1)
else:
re.append(-1)
return re
成功
执行用时: 116 ms, 在Next Greater Element I的Python提交中击败了16.23% 的用户
内存消耗: 10.9 MB, 在Next Greater Element I的Python提交中击败了0.00% 的用户
进行下一个挑战:
感觉耗时太高了。然后看了别人的算法优化了一下:
class Solution(object):
def nextGreaterElement(self,nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: List[int]
"""
for i in range(len(nums1)):
position = nums2.index(nums1[i])
for j in range(position + 1, len(nums2)):
if nums2[j] > nums1[i]:
nums1[i] = nums2[j]
break
if nums1[i] == nums2[position]:
nums1[i] = -1
return nums1
成功
执行用时: 108 ms, 在Next Greater Element I的Python提交中击败了17.39% 的用户
内存消耗: 11.1 MB, 在Next Greater Element I的Python提交中击败了0.00% 的用户
感觉差不多呢,然后看了一种新方法,用单调栈
def nextGreaterElement(nums1, nums2):
stack = [] # 单调栈
dic = {} # 字典
# 利用单调栈,将num2中所有值的对应更大元素存入dic
for i in nums2:
while stack and i > stack[-1]: # 此处用while而不是if
dic[stack.pop()] = i
stack.append(i)
# 遍历num1,根据dic中的记录改写num1
for j in range(len(nums1)):
nums1[j] = dic.get(nums1[j], -1)
return nums1
成功
执行用时: 56 ms, 在Next Greater Element I的Python提交中击败了66.38% 的用户
内存消耗: 11 MB, 在Next Greater Element I的Python提交中击败了0.00% 的用户
进行下一个挑战:
682. 棒球比赛
你现在是棒球比赛记录员。
给定一个字符串列表,每个字符串可以是以下四种类型之一:
1.整数
(一轮的得分):直接表示您在本轮中获得的积分数。
2."+"
(一轮的得分):表示本轮获得的得分是前两轮有效
回合得分的总和。
3."D"
(一轮的得分):表示本轮获得的得分是前一轮有效
回合得分的两倍。
4."C"
(一个操作,这不是一个回合的分数):表示您获得的最后一个有效
回合的分数是无效的,应该被移除。
每一轮的操作都是永久性的,可能会对前一轮和后一轮产生影响。
你需要返回你在所有回合中得分的总和。示例 1:
输入: ["5","2","C","D","+"] 输出: 30 解释: 第1轮:你可以得到5分。总和是:5。 第2轮:你可以得到2分。总和是:7。 操作1:第2轮的数据无效。总和是:5。 第3轮:你可以得到10分(第2轮的数据已被删除)。总数是:15。 第4轮:你可以得到5 + 10 = 15分。总数是:30。
示例 2:
输入: ["5","-2","4","C","D","9","+","+"] 输出: 27 解释: 第1轮:你可以得到5分。总和是:5。 第2轮:你可以得到-2分。总数是:3。 第3轮:你可以得到4分。总和是:7。 操作1:第3轮的数据无效。总数是:3。 第4轮:你可以得到-4分(第三轮的数据已被删除)。总和是:-1。 第5轮:你可以得到9分。总数是:8。 第6轮:你可以得到-4 + 9 = 5分。总数是13。 第7轮:你可以得到9 + 5 = 14分。总数是27。
注意:
- 输入列表的大小将介于1和1000之间。
- 列表中的每个整数都将介于-30000和30000之间。
如果定义一个变量sum=0来求和的话,会非常麻烦,这道题栈的知识很简答, 用一个list去装数据,就很好求
class Solution(object):
def calPoints(self, ops):
"""
:type ops: List[str]
:rtype: int
"""
stack = []
for s in range(len(ops)):
if ops[s] == '+':
stack.append(stack[-1]+stack[-2])
elif ops[s] == 'D':
stack.append(2*stack[-1])
elif ops[s] == 'C':
stack.pop()
else:
stack.append(int(ops[s]))
return sum(stack)
503. 下一个更大元素 II
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
示例 1:
输入: [1,2,1] 输出: [2,-1,2] 解释: 第一个 1 的下一个更大的数是 2; 数字 2 找不到下一个更大的数; 第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
这道题我感觉和上面的那道题差不多。然后就用单调栈做了。
class Solution(object):
def nextGreaterElements(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
stack = []
dic = {}
for i in nums:
while stack and i > stack[-1]:
dic[stack.pop()] = i
stack.append(i)
for j in range(len(nums)):
nums[j] = dic.get(nums[j],-1)
return nums
但是有一个测试用例没有过:
解答错误
输入 [5,4,3,2,1]
输出 [-1,-1,-1,-1,-1]
预期结果 [-1,5,5,5,5]
这个测试用例能叫题目中所说的’循环数组‘吗? 最后一个元素的下一个元素是数组的第一个元素。 我以为是循环数组是他给的那样 【1,2,1】 再比如 【1,2,5,6,7,1】 .
后面查资料知道了原来循环数组,可以把它想象成一个圆环,所以需要循环比较。
思路:
首先想到用单调栈来解决,但是此时输入的是一个循环数组而且其中包含了重复元素,对于循环数组的问题一个常见的处理手段就是通过余数,然后将数组的长度扩大两倍即可。对于包含重复元素,其实并没有什么,它并不能决定我们是建立一个严格的栈还是非严格的栈。关键问题在于如果我们找不到下一个更大的元素的话要怎么办?对于例子中的
2
,由于是循环数组,所以我们循环一圈后必然会碰到同样的2
,此时我们要不要弹出栈顶元素呢?当然不要。基于此,我们可以确定我们的单调栈是一个非严格单调减的栈。剩下的部分就很简单了.
class Solution(object):
def nextGreaterElements(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
stack = []
res = [-1] * len(nums)
for i in range(len(nums)*2):
while stack and nums[stack[-1]]<nums[i%len(nums)]:
res[stack.pop()] = nums[i%len(nums)]
stack.append(i%len(nums))
return res
取余运算
('0%10=', 0)
('1%10=', 1)
('2%10=', 2)
('3%10=', 3)
('4%10=', 4)
('5%10=', 5)
('6%10=', 6)
('7%10=', 7)
('8%10=', 8)
('9%10=', 9)