【题号】20
【题目描述】
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
输入: “()”
输出: true
示例 2:
输入: “()[]{}”
输出: true
示例 3:
输入: “(]”
输出: false
示例 4:
输入: “([)]”
输出: false
示例 5:
输入: “{[]}”
输出: true
【常规解法】
1.初始化栈 S。
2.一次处理表达式的每个括号。
3.如果遇到开括号,我们只需将其推到栈上即可。这意味着我们将稍后处理它,让我们简单地转到前面的 子表达式。
4.如果我们遇到一个闭括号,那么我们检查栈顶的元素。如果栈顶的元素是一个 相同类型的 左括号,那么我们将它从栈中弹出并继续处理。否则,这意味着表达式无效。
5.如果到最后我们剩下的栈中仍然有元素,那么这意味着表达式无效。
【我的代码】
class Stack(object):
def __init__(self, limit=10):
self.stack = [] #存放元素
self.limit = limit #栈容量极限
def push(self, data): #判断栈是否溢出
if len(self.stack) >= self.limit:
print('StackOverflowError')
pass
self.stack.append(data)
def pop(self):
if self.stack:
return self.stack.pop()
else:
#raise IndexError('pop from an empty stack') #空栈不能被弹出
return False
def peek(self): #查看堆栈的最上面的元素
if self.stack:
return self.stack[-1]
def is_empty(self): #判断栈是否为空
return not bool(self.stack)
def size(self): #返回栈的大小
return len(self.stack)
class Solution(object):
def isValid(self, s):
"""
:type s: str
:rtype: bool
"""
stack = Stack(len(s))
for c in s:
if (c == '(') or (c=='{') or (c=='['):
stack.push(c)
elif c==')':
if(stack.pop()!='('):
return False
elif c=='}':
if(stack.pop()!='{'):
return False
elif c==']':
if(stack.pop()!='['):
return False
else:
return False
if stack.is_empty():
return True
else:
return False
【执行情况】
执行用时36ms rank 23.13%
消耗内存11.7MB rank 99.23%
【范例代码】
class Solution(object):
def isValid(self, s):
"""
:type s: str
:rtype: bool
"""
# The stack to keep track of opening brackets.
stack = []
# Hash map for keeping track of mappings. This keeps the code very clean.
# Also makes adding more types of parenthesis easier
mapping = {")": "(", "}": "{", "]": "["}
# For every bracket in the expression.
for char in s:
# If the character is an closing bracket
if char in mapping:
# Pop the topmost element from the stack, if it is non empty
# Otherwise assign a dummy value of '#' to the top_element variable
top_element = stack.pop() if stack else '#'
# The mapping for the opening bracket in our hash and the top
# element of the stack don't match, return False
if mapping[char] != top_element:
return False
else:
# We have an opening bracket, simply push it onto the stack.
stack.append(char)
# In the end, if the stack is empty, then we have a valid expression.
# The stack won't be empty for cases like ((()
return not stack
【分析】
1.我做这道题的时候专门定义了一个栈类,其实直接定义一个stack数组即可。直接使用stack.pop()以及stack.append()进行出栈和入栈操作,使用stack和not stack进行栈是否为空的判断。
2.我穷举了所有左右闭合的情况进行判断,判断语句很笨重。由于每一个右括号,都对应了一个专属的左括号,所以更好的方法是使用哈希表。使用if char in mapping判断哈希表中是否有索引char,此处对应的是判断char是否为某右括号,如果有,则mapping[char]即为对应的左括号。
【拓展】
1.时间复杂度
定义了三个数组。数组1为常规的栈,数组2为左括号数组,数组3为括号对数组。
通过与数组2比对,判断新输入字符是否是左括号,直接进栈。若不是左括号且栈不为空,则将栈顶字符与新输入的字符拼接,通过与数组3比对,判断是否能组成正确的括号对,若是,则将栈顶出栈。以上都不满足时即为输入错误。字符串穷尽后,通过判断栈中是否还有元素决定输出结果。
(这里的栈不为空保证了后半句的数组不越界。即避免栈空时,错误输入一个右括号的情况)
范例:时间消耗4ms
class Solution(object):
def isValid(self, s):
stack, s1, s2 = [], ['(','[','{'], ['()','[]','{}']
for n in s:
if n in s1: stack.append(n)
elif stack and stack[-1]+n in s2: stack.pop()
else: return False
return stack == []
【题号】115
【题目描述】
设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) – 将元素 x 推入栈中。
pop() – 删除栈顶的元素。
top() – 获取栈顶元素。
getMin() – 检索栈中的最小元素。
示例:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
【常规解法】
构建辅助栈,“以空间换时间”
辅助栈栈顶为当前最小值。
(一)同步辅助栈
辅助栈元素个数和数据栈元素个数相同。
辅助栈中的元素完全对应了数据栈中每一个元素入栈时的最小值。并将判断放在入栈阶段。
每当数据栈中入栈新元素时,判断新入栈的元素是否比目前最小值要小,若小则替换当前最小值,并在辅助栈中同步入栈最小值。
每当数据栈中出栈元素时,辅助栈同步出栈。
(二)非同步辅助栈
辅助栈元素个数和数据栈元素个数不相同。
入栈时,为最小值才同步入栈;出栈时,为最小值才同步出栈。
每当数据栈中入栈新元素时,若新元素小于或等于当前最小值,则替换最小值,并将该元素入辅助栈。
每当数据栈中出栈元素时,若出栈元素等于当前最小值时,辅助栈同步出栈。
(此处的或等于容易漏)
【我的代码】
class MinStack(object):
def __init__(self):
"""
initialize your data structure here.
"""
self.stack=[]
def push(self, x):
"""
:type x: int
:rtype: None
"""
self.stack.append(x)
def pop(self):
"""
:rtype: None
"""
if self.stack:
return self.stack.pop()
else:
return False
def top(self):
"""
:rtype: int
"""
if self.stack:
return self.stack[-1]
else:
return False
def getMin(self):
"""
:rtype: int
"""
if self.stack:
minEle=self.stack[0]
else:
return False
for temp in self.stack:
if temp<minEle:
minEle=temp
return minEle
class MinStack:
# 辅助栈和数据栈同步
# 思路简单不容易出错
def __init__(self):
# 数据栈
self.data = []
# 辅助栈
self.helper = []
def push(self, x):
self.data.append(x)
if len(self.helper) == 0 or x <= self.helper[-1]:
self.helper.append(x)
else:
self.helper.append(self.helper[-1])
def pop(self):
if self.data:
self.helper.pop()
return self.data.pop()
def top(self):
if self.data:
return self.data[-1]
def getMin(self):
if self.helper:
return self.helper[-1]
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/min-stack/solution/shi-yong-fu-zhu-zhan-tong-bu-he-bu-tong-bu-python-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class MinStack:
# 辅助栈和数据栈不同步
# 关键 1:辅助栈的元素空的时候,必须放入新进来的数
# 关键 2:新来的数小于或者等于辅助栈栈顶元素的时候,才放入(特别注意这里等于要考虑进去)
# 关键 3:出栈的时候,辅助栈的栈顶元素等于数据栈的栈顶元素,才出栈,即"出栈保持同步"就可以了
def __init__(self):
# 数据栈
self.data = []
# 辅助栈
self.helper = []
def push(self, x):
self.data.append(x)
# 关键 1 和关键 2
if len(self.helper) == 0 or x <= self.helper[-1]:
self.helper.append(x)
def pop(self):
# 关键 3:【注意】不论怎么样,数据栈都要 pop 出元素
top = self.data.pop()
if self.helper and top == self.helper[-1]:
self.helper.pop()
return top
def top(self):
if self.data:
return self.data[-1]
def getMin(self):
if self.helper:
return self.helper[-1]
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/min-stack/solution/shi-yong-fu-zhu-zhan-tong-bu-he-bu-tong-bu-python-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【分析】
我做这道题的时候,有想过应该不是在输出最小值时才遍历栈,但没想到怎么样在入栈或出栈阶段做判断。本质上来说,没想到引入了一个新的辅助栈来参与判断。
本道题辅助栈分为同步栈和非同步栈两种解法,同步栈判断简单但空间消耗略高,非同步栈省了部分的空间消耗但其增加的判断也提高了时间开销。
对于同步辅助栈,辅助栈中的元素完全对应了数据栈中每一个元素入栈时的最小值。并将判断放在入栈阶段。
对于非同步辅助栈,入栈时,为最小值才同步入栈;出栈时,为最小值才同步出栈。
更推荐使用同步栈。
【拓展】
若不使用辅助栈,还可以使用一个单独的变量存储最小值。而当最小值发生变化时有如下两种操作方式:最小值入栈和存储差值。
(一)最小值入栈
当入栈时,新的元素值小于当前最小值,则替换最小值,并将原先的最小值也压入数据栈。
当出栈时,出栈的元素等于当前最小值,则再出栈一个元素,并将新出栈的元素作为新的最小值。
演示:
范例:
class MinStack {
int min = Integer.MAX_VALUE;
Stack<Integer> stack = new Stack<Integer>();
public void push(int x) {
//当前值更小
if(x <= min){
//将之前的最小值保存
stack.push(min);
//更新最小值
min=x;
}
stack.push(x);
}
public void pop() {
//如果弹出的值是最小值,那么将下一个元素更新为最小值
if(stack.pop() == min) {
min=stack.pop();
}
}
public int top() {
return stack.peek();
}
public int getMin() {
return min;
}
}
作者:windliang
链接:https://leetcode-cn.com/problems/min-stack/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-38/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
(二)存储差值
栈中存储的值为原先元素值与当时最小值之间的差值。
演示:
范例:
public class MinStack {
long min;
Stack<Long> stack;
public MinStack(){
stack=new Stack<>();
}
public void push(int x) {
if (stack.isEmpty()) {
min = x;
stack.push(x - min);
} else {
stack.push(x - min);
if (x < min){
min = x; // 更新最小值
}
}
}
public void pop() {
if (stack.isEmpty())
return;
long pop = stack.pop();
//弹出的是负值,要更新 min
if (pop < 0) {
min = min - pop;
}
}
public int top() {
long top = stack.peek();
//负数的话,出栈的值保存在 min 中
if (top < 0) {
return (int) (min);
//出栈元素加上最小值即可
} else {
return (int) (top + min);
}
}
public int getMin() {
return (int) min;
}
}
作者:windliang
链接:https://leetcode-cn.com/problems/min-stack/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-38/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【题号】225
【题目描述】
使用队列实现栈的下列操作:
push(x) – 元素 x 入栈
pop() – 移除栈顶元素
top() – 获取栈顶元素
empty() – 返回栈是否为空
注意:
你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的。
你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。
【常规解法】
双队列解法一:出栈时调整
定义两个辅助队列 queue1 与 queue2,使用一个变量 top_element 记录栈顶元素。
push():将元素入队 queue1
pop():
将 queue1 内所有元素全部出队,除最后一个元素外,其余入队 queue2,而后删除最后一个元素并返回
更新 top_element
调换 queue1 与 queue2
top():返回 top_elenemt
empty():判断 queue1 的长度
双队列解法二:入栈时调整
定义两个辅助队列 queue1 与 queue2,使用一个变量 top_element 记录栈顶元素。
push():
将元素入队 queue2,且将该元素定义为栈顶元素
更新 top_element
此时若 queue1 不为空,则让 queue1 中的元素逐个出队并加入 queue2 中
交换queue1和queue2
pop(): queue1 首个元素出队,更新 top_element
top(): 返回 top_element
empty(): 判断 queue1 长度
单队列解法:入栈反序操作
定义辅助队列 queue。
push():
将元素入队
除新入队元素,将其他元素从队首取出,再从队尾入队(完成反序)。此时队首元素即为新入队元素
pop():queue 首个元素出队
top():获取 queue 首个元素
empty():判断 queue 长度
【我的代码】
class MyStack(object):
def __init__(self):
"""
Initialize your data structure here.
"""
self.queen=[] #用list存放队列
self.topEle=0 #存放栈顶元素
def push(self, x):
"""
Push element x onto stack.
:type x: int
:rtype: None
"""
self.queen.append(x)
self.topEle=x #在入栈时 新入列的元素设为栈顶元素
def pop(self):
"""
Removes the element on top of the stack and returns that element.
:rtype: int
"""
if self.queen: # 在出栈时
for num in range(0,len(self.queen)-2): #1)对队列中前N-2个元素进行翻转
self.queen.append(self.queen[0])
del self.queen[0]
if len(self.queen)!=1: #2)对第N-1个元素设为新的栈顶元素
self.topEle=self.queen[0]
del self.queen[0]
self.queen.append(self.topEle)
output=self.queen[0] #3)出列第N个元素
del self.queen[0]
return output
def top(self):
"""
Get the top element.
:rtype: int
"""
if self.queen:
return self.topEle
else:
return False
def empty(self):
"""
Returns whether the stack is empty.
:rtype: bool
"""
if self.queen:
return False
else:
return True
# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()
【执行情况】
执行用时12ms rank 96.15%
消耗内存11.7MB rank 90.07%
【范例代码】
"""
双队列解法一:出栈时调整
"""
class MyStack:
def __init__(self):
"""
Initialize your data structure here.
"""
self.queue1 = []
self.queue2 = []
self.top_element = 0
def push(self, x: int) -> None:
"""
Push element x onto stack.
"""
self.queue1.append(x)
self.top_element = x
def pop(self) -> int:
"""
Removes the element on top of the stack and returns that element.
"""
# 把 queue1 里的元素取出,留下一个,其余塞入 queue2 中
length1 = len(self.queue1)
for i in range(length1 - 1):
item = self.queue1[0]
del self.queue1[0]
self.queue2.append(item)
self.top = item
target = self.queue1[0]
del self.queue1[0]
# 交换 queue1 与 queue2
self.queue1 = self.queue2
self.queue2 = []
return target
def top(self) -> int:
"""
Get the top element.
"""
# length1 = len(self.queue1)
# for i in range(length1):
# item = self.queue1[0]
# del self.queue1[0]
# self.queue2.append(item)
# self.queue1 = self.queue2
# self.queue2 = []
# return item
return self.top_element
def empty(self) -> bool:
"""
Returns whether the stack is empty.
"""
return len(self.queue1) == 0
# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()
"""
双队列解法二:入栈时调整
"""
class MyStack:
def __init__(self):
"""
Initialize your data structure here.
"""
self.queue1 = []
self.queue2 = []
self.top_element = 0
def push(self, x: int) -> None:
"""
Push element x onto stack.
"""
# 更新栈顶元素
self.top_element = x
# 加入 queue2 中
self.queue2.append(x)
if not self.empty():
# 如果 queue1 不为空,取出元素并加入 queue2
length1 = len(self.queue1)
for i in range(length1):
self.queue2.append(self.queue1[0])
del self.queue1[0]
# 交换
self.queue1 = self.queue2
self.queue2 = []
def pop(self) -> int:
"""
Removes the element on top of the stack and returns that element.
"""
target = self.queue1[0]
del self.queue1[0]
# 更新 top_element
if not self.empty():
self.top_element = self.queue1[0]
return target
def top(self) -> int:
"""
Get the top element.
"""
return self.top_element
def empty(self) -> bool:
"""
Returns whether the stack is empty.
"""
return len(self.queue1) == 0
# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()
"""
单队列解法:入栈反序操作
"""
class MyStack:
def __init__(self):
"""
Initialize your data structure here.
"""
self.queue = []
def push(self, x: int) -> None:
"""
Push element x onto stack.
"""
self.queue.append(x)
# 队列反序
length = len(self.queue)
for i in range(length - 1):
first = self.queue[0]
del self.queue[0]
self.queue.append(first)
def pop(self) -> int:
"""
Removes the element on top of the stack and returns that element.
"""
target = self.queue[0]
del self.queue[0]
return target
def top(self) -> int:
"""
Get the top element.
"""
return self.queue[0]
def empty(self) -> bool:
"""
Returns whether the stack is empty.
"""
return len(self.queue) == 0
# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()
作者:jalan
链接:https://leetcode-cn.com/problems/implement-stack-using-queues/solution/yong-dui-lie-shi-xian-zhan-de-san-chong-jie-fa-pyt/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【分析】
这道题有两种工具和操作方式。可以构建辅助栈并交换,或者直接对栈本身进行一个反序,我感觉本质上都差不多,时间开销也差不多,而且直接做反序更节省空间。操作方式分为在入栈时判断和出栈时判断,本质上也差不多。我选用了直接对栈做反序,并且在出栈时判断。
【题号】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.stack=[] #存储队列元素的栈
self.stackAss=[] #辅助栈
self.peekEle=0 #队首元素
def push(self, x):
"""
Push element x to the back of queue.
:type x: int
:rtype: None
"""
if not self.stack: #如果队中无元素 则新入队的元素设为队首元素
self.peekEle=x
self.stack.append(x)
def pop(self):
"""
Removes the element from in front of queue and returns that element.
:rtype: int
"""
if self.stack:
for i in range(0,len(self.stack)-2): #栈中前n-2个元素放入辅助栈
self.stackAss.append(self.stack.pop())
self.peekEle=self.stack.pop() #栈中第n-1个元素设为新的队首元素并放入辅助栈
if self.stack: #出栈第n个元素 并出队
self.stackAss.append(self.peekEle)
self.output=self.stack.pop()
else:
self.output=self.peekEle
if self.stackAss: #将辅助栈中的元素再放回队列栈重
for i in range(0,len(self.stackAss)):
self.stack.append(self.stackAss.pop())
return self.output
else:
return False
def peek(self):
"""
Get the front element.
:rtype: int
"""
if self.stack:
return self.peekEle
else:
return False
def empty(self):
"""
Returns whether the queue is empty.
:rtype: bool
"""
if self.stack:
return False
else:
return True
# 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()
private Stack<Integer> s1 = new Stack<>();
private Stack<Integer> s2 = new Stack<>();
// Push element x to the back of queue.
public void push(int x) {
if (s1.empty())
front = x;
s1.push(x);
}
// Removes the element from in front of queue.
public void pop() {
if (s2.isEmpty()) {
while (!s1.isEmpty())
s2.push(s1.pop());
}
s2.pop();
}
// Return whether the queue is empty.
public boolean empty() {
return s1.isEmpty() && s2.isEmpty();
}
// Get the front element.
public int peek() {
if (!s2.isEmpty()) {
return s2.peek();
}
return front;
}
【分析】
用栈实现队列,至少需要两个栈。
我的做法是,将一个栈作为队列栈,存储着队列元素,另一个栈只是在出栈时候起一个辅助作用。入队时正常入栈,出队时,将所有元素都倒序到辅助栈中,提取完第一个元素,再把辅助栈的元素正序回队列栈。这样效率很低,时间复杂度较大。而且我没有把判断放在倒序到辅助栈后再做,而是一边倒序一边做,判断变得繁琐了。
更好的做法是,一个栈专门用来入队,一个栈专门用来出队。入队栈中所有元素都是倒序的,可以正常入队;出队栈中所有元素都是正序的,可以正常出队。二者在出入队时不需要每次都做栈之间的传递,各司其责即可。直到出队栈为空,才再把入队栈的元素倒腾过来。
我对于本题的解法时仿照上一题(用队列来实现栈)的,可以用确实是可以用,但时间复杂度较高。而本题提出的新解法,其均摊复杂度只有O(1)。
【题号】496
【题目描述】
给定两个没有重复元素的数组 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。
【常规解法】
先建立一个哈希表,key为nums2中的每一个元素,value为该元素对应的下一个更大数字。之后再遍历num1去寻找哈希表中对应的value。
对于哈希表的建立,用的是单调栈的方法。
对nums2遍历入栈。
若栈中无元素,则直接入栈。
若栈中有元素,且即将入栈的元素比栈顶元素大,则出栈栈顶元素,存入哈希表。*其中key为栈顶元素,value为即将入站元素。*原栈顶元素出栈后,再次比较待入栈元素与新的栈顶元素,直到待入栈元素也大于栈顶元素时,入栈。
若num2遍历完后,栈中仍然存在元素,则将栈中元素全部出栈,key为栈中元素,value为-1。
由于整个操作过程中,新入栈元素都小于原栈顶元素,所以这是一个由小到大的单调栈。
【我的代码】
class Solution(object):
def nextGreaterElement(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: List[int]
"""
"""
nums3=[] #待输出的list
for num in nums1: #遍历nums1
isExist=False
for i in range(0,len(nums2)):
if num==nums2[i]: #遍历寻找nums2中对应的num1元素
i=i+1
while(inum):
isExist=True
nums3.append(nums2[i])
break
i=i+1
break
if not isExist:
nums3.append(-1)
return nums3
"""
nums3=[] #待输出的list
stack=[] #单调栈
mapping={} #哈希表
for num in nums2: #将num2元素依次尝试入栈
while(stack and stack[-1]<num): #若待入栈元素大于栈顶元素
mapping.update({stack.pop():num}) #则表栈顶元素出栈且入哈希表
stack.append(num)
while stack: #nums2全部入栈后 单调栈中的剩余元素全部入表
mapping.update({stack.pop():-1})
for num in nums1:
nums3.append(mapping[num])
return nums3
class Solution:
def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
stack, hashmap = list(), dict()
for i in nums2:
while len(stack) != 0 and stack[-1] < i:hashmap[stack.pop()] = i
stack.append(i)
return [hashmap.get(i,-1) for i in nums1]
作者:qsctech-sange
链接:https://leetcode-cn.com/problems/next-greater-element-i/solution/python3-wu-xing-dai-ma-di-jian-zhan-ha-xi-biao-by-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【分析】
这道题,我先用了纯粹遍历得笨方法,也能运行得通,不过消耗时间较大。
我参考了利用单调栈建立哈希表的方法,写了第二种解法,运行效率大大提高。
范例代码中一个地方值得注意,就是其return的写法:return [hashmap.get(i,-1) for i in nums1]。比我再去将遍历完nums2的单调栈重新入表,建立完哈希表再遍历num1去生成新的输出list,要简洁且省事。
【题号】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。
【常规解法】
让我们在处理数据时保持栈上每个有效回合的值。栈是理想的,因为我们只处理涉及最后或倒数第二轮的操作。
【我的代码】
class Solution(object):
def calPoints(self, ops):
"""
:type ops: List[str]
:rtype: int
"""
stack=[]
for string in ops:
if string.isdigit():
stack.append(int(string))
elif string[0]=='-' and string[1:].isdigit():
stack.append(int(string[1:])*-1)
elif string=="+" and len(stack)>1:
num1=stack.pop()
num2=stack.pop()
stack.append(num2)
stack.append(num1)
stack.append(num1+num2)
elif string=="D" and stack:
num=stack.pop()
stack.append(num)
stack.append(2*num)
elif string=="C" and stack:
stack.pop()
else:
return False
output=0
for score in stack:
output=output+score
return output
class Solution(object):
def calPoints(self, ops):
stack = []
for op in ops:
if op == '+':
stack.append(stack[-1] + stack[-2])
elif op == 'C':
stack.pop()
elif op == 'D':
stack.append(2 * stack[-1])
else:
stack.append(int(op))
return sum(stack)
作者:LeetCode
链接:https://leetcode-cn.com/problems/baseball-game/solution/bang-qiu-bi-sai-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【分析】
这道题本身的做法比较简单。只是涉及到栈顶和次栈顶元素的调用处理而已。
不过范例代码有我需要注意的地方,调用栈顶和次栈顶元素可以直接使用stack[-1]和stack[-2],计算栈和可以直接用sum(stack)
【题号884】
【题目描述】
给定 S 和 T 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果。 # 代表退格字符。
示例 1:
输入:S = “ab#c”, T = “ad#c”
输出:true
解释:S 和 T 都会变成 “ac”。
示例 2:
输入:S = “ab##”, T = “c#d#”
输出:true
解释:S 和 T 都会变成 “”。
示例 3:
输入:S = “a##c”, T = “#a#c”
输出:true
解释:S 和 T 都会变成 “c”。
示例 4:
输入:S = “a#c”, T = “b”
输出:false
解释:S 会变成 “c”,但 T 仍然是 “b”。
【常规解法】
使用 build(S) 和 build(T) 构造去除了退格符和被删除字符后的字符串,然后比较它们是否相等。
在 build(S) 中,使用栈存储每次输入的字符。
【我的代码】
class Solution(object):
def backspaceCompare(self, S, T):
"""
:type S: str
:type T: str
:rtype: bool
"""
stackS,stackT=[],[]
for char in S:
if char == '#' :
if stackS:
stackS.pop()
else:
stackS.append(char)
for char in T:
if char == '#':
if stackT:
stackT.pop()
else:
stackT.append(char)
return stackS==stackT
class Solution(object):
def backspaceCompare(self, S, T):
def build(S):
ans = []
for c in S:
if c != '#':
ans.append(c)
elif ans:
ans.pop()
return "".join(ans)
return build(S) == build(T)
作者:LeetCode
链接:https://leetcode-cn.com/problems/backspace-string-compare/solution/bi-jiao-han-tui-ge-de-zi-fu-chuan-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【分析】
我的思路和范例基本是一样的。主要是代码方面可以做一点改进。
我的判断逻辑是,(如果是# (如果非空 (出栈) ))(否则 入栈)
范例的判断逻辑是,(如果不是# 入栈)(又如果非空 出栈)。
其实本质上没有增加多少判断的时间,但我是有嵌套判断,看着有点累赘。
【拓展】
反向遍历字符串,如果遍历到一个退格符,那么再往左第一个非退格字符将会被删除,剩余未被删除的字符就是最终的字符串。
这里使用到了迭代器。空间复杂度较小。
class Solution(object):
def backspaceCompare(self, S, T):
def F(S):
skip = 0
for x in reversed(S):
if x == '#':
skip += 1
elif skip:
skip -= 1
else:
yield x
return all(x == y for x, y in itertools.izip_longest(F(S), F(T)))
作者:LeetCode
链接:https://leetcode-cn.com/problems/backspace-string-compare/solution/bi-jiao-han-tui-ge-de-zi-fu-chuan-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【题号】1021
【题目描述】
有效括号字符串为空 ("")、"(" + A + “)” 或 A + B,其中 A 和 B 都是有效的括号字符串,+ 代表字符串的连接。例如,"","()","(())()" 和 “(()(()))” 都是有效的括号字符串。
如果有效字符串 S 非空,且不存在将其拆分为 S = A+B 的方法,我们称其为原语(primitive),其中 A 和 B 都是非空有效括号字符串。
给出一个非空有效字符串 S,考虑将其进行原语化分解,使得:S = P_1 + P_2 + … + P_k,其中 P_i 是有效括号字符串原语。
对 S 进行原语化分解,删除分解中每个原语字符串的最外层括号,返回 S 。
示例 1:
输入:"(()())(())"
输出:"()()()"
解释:
输入字符串为 “(()())(())”,原语化分解得到 “(()())” + “(())”,
删除每个部分中的最外层括号后得到 “()()” + “()” = “()()()”。
示例 2:
输入:"(()())(())(()(()))"
输出:"()()()()(())"
解释:
输入字符串为 “(()())(())(()(()))”,原语化分解得到 “(()())” + “(())” + “(()(()))”,
删除每隔部分中的最外层括号后得到 “()()” + “()” + “()(())” = “()()()()(())”。
示例 3:
输入:"()()"
输出:""
解释:
输入字符串为 “()()”,原语化分解得到 “()” + “()”,
删除每个部分中的最外层括号后得到 “” + “” = “”。
【常规解法】
利用栈或标志符统计左右括号,当栈空/左右括号数量相等时,则表明最外层的括号已出现。
【我的代码】
class Solution(object):
def removeOuterParentheses(self, S):
"""
:type S: str
:rtype: str
"""
leftNum=0
output=""
for char in S:
if char=='(':
leftNum=leftNum+1
if leftNum>1:
output=output+char
else:
leftNum=leftNum-1
if leftNum:
output=output+char
return output
class Solution {
public String removeOuterParentheses(String S) {
StringBuilder sb = new StringBuilder();
int level = 0;
for (char c : S.toCharArray()) {
if (c == ')') --level;
if (level >= 1) sb.append(c);
if (c == '(') ++level;
}
return sb.toString();
}
}
作者:huaouo
链接:https://leetcode-cn.com/problems/remove-outermost-parentheses/solution/jian-ji-de-java-shi-xian-by-huaouo/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution(object):
def removeOuterParentheses(self, S):
"""
:type S: str
:rtype: str
"""
i=0
lnum=0
rnum=0
m=''
while i<len(S):
if S[i] == '(':
lnum+=1
if S[i] == ')':
rnum+=1
if lnum == rnum:
k=S[i-lnum-rnum+2:i]
m=m+k
lnum=0
rnum=0
i+=1
return m
作者:qin-ken-de-xiao-ma-nong-2
链接:https://leetcode-cn.com/problems/remove-outermost-parentheses/solution/python-whilexun-huan-qiu-jie-by-qin-ken-de-xiao-ma/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【分析】
这道题的思路并不复杂。不过在代码方面还是有可以借鉴的地方。
1)第一个范例代码中用了三个单层判断,代替了我的两个双层判断。我的双层判断是:若左括号则自增,后又如果大于一执行;若右括号则自减,后大于零执行。可以直接用若右括号则自减;若大于零则执行;若左括号则自增。 主要是刚好我的第二层判断只差一个1。
2)第二个范例中,是已经出现了最外层的括号时,直接把中间的放进去,而我是非最外层括号的每一个括号都放进去,执行次数比较多。k=S[i-lnum-rnum+2:i] ;m=m+k。
【题号】1047
【题目描述】
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
示例:
输入:“abbaca”
输出:“ca”
解释:
例如,在 “abbaca” 中,我们可以删除 “bb” 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 “aaca”,其中又只有 “aa” 可以执行重复项删除操作,所以最后的字符串为 “ca”。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
【常规解法】
方法一:替换函数
我们可以用字符串自带的替换函数,由于字符串仅包含小写字母,因此只有 26 种不同的重复项。
将 aa 到 zz 的 26 种重复项放入集合中;
遍历这 26 种重复项,并用字符串的替换函数把重复项替换成空串。
注意,在进行过一次替换之后,可能会出现新的重复项。例如对于字符串 abbaca,如果替换了重复项 bb,字符串会变为 aaca,出现了新的重复项 aa。因此,上面的过程需要背重复若干次,直到字符串在一整轮替换过程后保持不变(即长度不变)为止
方法二:栈
我们可以用栈来维护没有重复项的字母序列:
若当前的字母和栈顶的字母相同,则弹出栈顶的字母;
若当前的字母和栈顶的字母不同,则放入当前的字母。
【我的代码】
class Solution(object):
def removeDuplicates(self, S):
"""
:type S: str
:rtype: str
"""
stack=[]
for char in S:
if stack and stack[-1]==char:
stack.pop()
else:
stack.append(char)
else:
stack.append(char)
return "".join(stack)
#替换函数
from string import ascii_lowercase
class Solution:
def removeDuplicates(self, S: str) -> str:
# generate 26 possible duplicates
duplicates = {2 * ch for ch in ascii_lowercase}
prev_length = -1
while prev_length != len(S):
prev_length = len(S)
for d in duplicates:
S = S.replace(d, '')
return S
#栈
class Solution:
def removeDuplicates(self, S: str) -> str:
output = []
for ch in S:
if output and ch == output[-1]:
output.pop()
else:
output.append(ch)
return ''.join(output)
作者:LeetCode
链接:https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string/solution/shan-chu-zi-fu-chuan-zhong-de-suo-you-xiang-lin-zh/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【分析】
我的代码使用的是方法二,用栈的方法进行重复元素的出栈。这个方法的思路和代码都相对简单高效。
范例中提到了使用字符串替代函数的方法,虽然时间复杂度更高了,不过这个思路还是可以参考一下。利用字符表生成重复字符表duplicates = {2 * ch for ch in ascii_lowercase};遍历重复字符表,若一次完整遍历后,原字符串长度发生改变,则再次遍历重复字符表S = S.replace(d, ‘’)。