题目链接
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push
、pop
、peek
、empty
):
实现 MyQueue
类:
void push(int x)
将元素 x 推到队列的末尾int pop()
从队列的开头移除并返回元素int peek()
返回队列开头的元素boolean empty()
如果队列为空,返回 true
;否则,返回 false
说明:
push to top
, peek/pop from top
, size
, 和 is empty
操作是合法的。示例 1:
输入:
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]
解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false
提示:
1 <= x <= 9
100
次 push
、pop
、peek
和 empty
pop
或者 peek
操作)Python:
#本人解法
class MyQueue:
def __init__(self):
self.size = 0
self.queue = []
def push(self, x: int) -> None:
self.size += 1
self.queue.append(x)
def pop(self) -> int:
self.size -= 1
out = self.queue[0]
self.queue = self.queue[1:]
return out
def peek(self) -> int:
return self.queue[0]
def empty(self) -> bool:
if self.size != 0:
return False
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()
#将一个栈当作输入栈,用于压入 push 传入的数据;另一个栈当作输出栈,用于 pop和 peek操作。每次 pop或peek时,若输出栈为空则将输入栈的全部数据依次弹出并压入输出栈,这样输出栈从栈顶往栈底的顺序就是队列从队首往队尾的顺序。
class MyQueue:
def __init__(self):
self.in_queue = []
self.out_queue = []
def push(self, x: int) -> None:
self.in_queue.append(x)
def in2out(self) -> None:
while len(self.in_queue):
self.out_queue.append(self.in_queue[-1])
self.in_queue = self.in_queue[:-1]
def pop(self) -> int:
if not len(self.out_queue):
self.in2out()
x = self.out_queue[-1]
self.out_queue = self.out_queue[:-1]
return x
def peek(self) -> int:
if not len(self.out_queue):
self.in2out()
return self.out_queue[-1]
def empty(self) -> bool:
if self.in_queue or self.out_queue:
return False
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()
Go:
//本人解法
type MyQueue struct {
size int
queue []int
}
func Constructor() MyQueue {
return MyQueue{0, []int{}}
}
func (q *MyQueue) Push(x int) {
q.size++
q.queue = append(q.queue, x)
}
func (q *MyQueue) Pop() (out int) {
q.size--
out = q.queue[0]
q.queue = q.queue[1:]
return
}
func (q *MyQueue) Peek() int {
return q.queue[0]
}
func (q *MyQueue) Empty() bool {
if q.size != 0 {
return false
}
return true
}
//双栈法
//将一个栈当作输入栈,用于压入 push 传入的数据;另一个栈当作输出栈,用于 pop和 peek操作。每次 pop或peek时,若输出栈为空则将输入栈的全部数据依次弹出并压入输出栈,这样输出栈从栈顶往栈底的顺序就是队列从队首往队尾的顺序。
type MyQueue struct {
inStack, outStack []int
}
func Constructor() MyQueue {
return MyQueue{}
}
func (q *MyQueue) Push(x int) {
q.inStack = append(q.inStack, x)
}
func (q *MyQueue) in2out() {
for len(q.inStack) > 0 {
q.outStack = append(q.outStack, q.inStack[len(q.inStack)-1])
q.inStack = q.inStack[:len(q.inStack)-1]
}
}
func (q *MyQueue) Pop() int {
if len(q.outStack) == 0 {
q.in2out()
}
x := q.outStack[len(q.outStack)-1]
q.outStack = q.outStack[:len(q.outStack)-1]
return x
}
func (q *MyQueue) Peek() int {
if len(q.outStack) == 0 {
q.in2out()
}
return q.outStack[len(q.outStack)-1]
}
func (q *MyQueue) Empty() bool {
return len(q.inStack) == 0 && len(q.outStack) == 0
}
题目链接
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push
、top
、pop
和 empty
)。
实现 MyStack
类:
void push(int x)
将元素 x 压入栈顶。int pop()
移除并返回栈顶元素。int top()
返回栈顶元素。boolean empty()
如果栈是空的,返回 true
;否则,返回 false
。注意:
push to back
、peek/pop from front
、size
和 is empty
这些操作。示例:
输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]
解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False
提示:
1 <= x <= 9
100
次 push
、pop
、top
和 empty
pop
和 top
都保证栈不为空Python:
class MyStack:
def __init__(self):
self.size = 0
self.stack = []
def push(self, x: int) -> None:
self.size += 1
self.stack.append(x)
def pop(self) -> int:
self.size -= 1
l = len(self.stack)
out = self.stack[l - 1]
self.stack = self.stack[: l - 1]
return out
def top(self) -> int:
return self.stack[len(self.stack) - 1]
def empty(self) -> bool:
if self.size:
return False
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()
class MyStack:
def __init__(self):
self.queue1 = []
self.queue2 = []
def push(self, x: int) -> None:
self.queue2.append(x)
while self.queue1:
self.queue2.append(self.queue1[0])
self.queue1 = self.queue1[1:]
self.queue1, self.queue2 = self.queue2, self.queue1
def pop(self) -> int:
v = self.queue1[0]
self.queue1 = self.queue1[1:]
return v
def top(self) -> int:
return self.queue1[0]
def empty(self) -> bool:
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 = collections.deque()
self.queue2 = collections.deque()
def push(self, x: int) -> None:
"""
Push element x onto stack.
"""
self.queue2.append(x)
while self.queue1:
self.queue2.append(self.queue1.popleft())
self.queue1, self.queue2 = self.queue2, self.queue1
def pop(self) -> int:
"""
Removes the element on top of the stack and returns that element.
"""
return self.queue1.popleft()
def top(self) -> int:
"""
Get the top element.
"""
return self.queue1[0]
def empty(self) -> bool:
"""
Returns whether the stack is empty.
"""
return not self.queue1
class MyStack:
def __init__(self):
"""
Initialize your data structure here.
"""
self.queue = collections.deque()
def push(self, x: int) -> None:
"""
Push element x onto stack.
"""
n = len(self.queue)
self.queue.append(x)
for _ in range(n):
self.queue.append(self.queue.popleft())
def pop(self) -> int:
"""
Removes the element on top of the stack and returns that element.
"""
return self.queue.popleft()
def top(self) -> int:
"""
Get the top element.
"""
return self.queue[0]
def empty(self) -> bool:
"""
Returns whether the stack is empty.
"""
return not self.queue
Go:
type MyStack struct {
size int
stack []int
}
func Constructor() MyStack {
return MyStack{0, []int{}}
}
func (s *MyStack) Push(x int) {
s.size++
s.stack = append(s.stack, x)
}
func (s *MyStack) Pop() int {
s.size--
l := len(s.stack)
out := s.stack[l-1]
s.stack = s.stack[:l-1]
return out
}
func (s *MyStack) Top() int {
return s.stack[len(s.stack)-1]
}
func (s *MyStack) Empty() bool {
if s.size != 0 {
return false
}
return true
}
type MyStack struct {
queue1, queue2 []int
}
/** Initialize your data structure here. */
func Constructor() (s MyStack) {
return
}
/** Push element x onto stack. */
func (s *MyStack) Push(x int) {
s.queue2 = append(s.queue2, x)
for len(s.queue1) > 0 {
s.queue2 = append(s.queue2, s.queue1[0])
s.queue1 = s.queue1[1:]
}
s.queue1, s.queue2 = s.queue2, s.queue1
}
/** Removes the element on top of the stack and returns that element. */
func (s *MyStack) Pop() int {
v := s.queue1[0]
s.queue1 = s.queue1[1:]
return v
}
/** Get the top element. */
func (s *MyStack) Top() int {
return s.queue1[0]
}
/** Returns whether the stack is empty. */
func (s *MyStack) Empty() bool {
return len(s.queue1) == 0
}
type MyStack struct {
queue []int
}
/** Initialize your data structure here. */
func Constructor() (s MyStack) {
return
}
/** Push element x onto stack. */
func (s *MyStack) Push(x int) {
n := len(s.queue)
s.queue = append(s.queue, x)
for ; n > 0; n-- {
s.queue = append(s.queue, s.queue[0])
s.queue = s.queue[1:]
}
}
/** Removes the element on top of the stack and returns that element. */
func (s *MyStack) Pop() int {
v := s.queue[0]
s.queue = s.queue[1:]
return v
}
/** Get the top element. */
func (s *MyStack) Top() int {
return s.queue[0]
}
/** Returns whether the stack is empty. */
func (s *MyStack) Empty() bool {
return len(s.queue) == 0
}
题目链接
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效。
有效字符串需满足:
示例 1:
输入:s = "()"
输出:true
示例 2:
输入:s = "()[]{}"
输出:true
示例 3:
输入:s = "(]"
输出:false
提示:
1 <= s.length <= 10^4
s
仅由括号 '()[]{}'
组成Python:
#本人解法
class Solution:
def isValid(self, s: str) -> bool:
if len(s)%2:
return False
stack = []
for v in s:
if v == ")":
if stack and stack[-1] == "(":
stack.pop()
else:
return False
elif v == "]":
if stack and stack[-1] == "[":
stack.pop()
else:
return False
elif v == "}":
if stack and stack[-1] == "{":
stack.pop()
else:
return False
else:
stack.append(v)
return not stack
class Solution:
def isValid(self, s: str) -> bool:
if len(s) % 2 == 1:
return False
pairs = {
")": "(",
"]": "[",
"}": "{",
}
stack = list()
for ch in s:
if ch in pairs:
if not stack or stack[-1] != pairs[ch]:
return False
stack.pop()
else:
stack.append(ch)
return not stack
Go:
//本人解法,注意到有效字符串的长度一定为偶数,因此如果字符串的长度为奇数,我们可以直接返回False,省去后续的遍历判断过程。
func isValid(s string) bool {
if len(s)%2 != 0 {
return false
}
stack := make([]rune, 0)
for _, v := range s {
switch v {
case ')':
l := len(stack)
if l != 0 && stack[l-1] == '(' {
stack = stack[:l-1]
} else {
return false
}
case ']':
l := len(stack)
if l != 0 && stack[l-1] == '[' {
stack = stack[:l-1]
} else {
return false
}
case '}':
l := len(stack)
if l != 0 && stack[l-1] == '{' {
stack = stack[:l-1]
} else {
return false
}
default:
stack = append(stack, v)
}
}
return len(stack) == 0
}
//简洁版
func isValid(s string) bool {
n := len(s)
if n % 2 == 1 {
return false
}
pairs := map[byte]byte{
')': '(',
']': '[',
'}': '{',
}
var stack []byte
for i := 0; i < n; i++ {
if pairs[s[i]] > 0 {
if len(stack) == 0 || stack[len(stack)-1] != pairs[s[i]] {
return false
}
stack = stack[:len(stack)-1]
} else {
stack = append(stack, s[i])
}
}
return len(stack) == 0
}
题目链接
给出由小写字母组成的字符串 S
,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
示例:
输入:"abbaca"
输出:"ca"
解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。
提示:
1 <= S.length <= 20000
S
仅由小写英文字母组成。Python:
#栈
class Solution:
def removeDuplicates(self, s: str) -> str:
stk = list()
for ch in s:
if stk and stk[-1] == ch:
stk.pop()
else:
stk.append(ch)
return "".join(stk)
#双指针
class Solution:
def removeDuplicates(self, s: str) -> str:
b = list(s)
slow = fast = 0
l = len(b)
while fast < l:
b[slow] = b[fast]
if slow and b[slow] == b[slow - 1]:
slow -= 1
else:
slow += 1
fast += 1
return "".join(b[:slow])
Go:
//双指针
func removeDuplicates(s string) string {
b := []byte(s)
slow, fast := 0, 0
l := len(s)
for fast < l {
b[slow] = b[fast]
if slow > 0 && b[slow] == b[slow-1] {
slow--
} else {
slow++
}
fast++
}
return string(b[0:slow])
}
//本人解法
func removeDuplicates(s string) string {
var stack []rune
outer:
for _, v := range s {
l := len(stack)
for l != 0 && stack[l-1] == v {
stack = stack[:l-1]
continue outer
}
stack = append(stack, v)
}
return string(stack)
}
func removeDuplicates(s string) string {
stack := []byte{}
for i := range s {
if len(stack) > 0 && stack[len(stack)-1] == s[i] {
stack = stack[:len(stack)-1]
} else {
stack = append(stack, s[i])
}
}
return string(stack)
}
//自己写的一种很傻的解法
func removeDuplicates(s string) string {
if len(s) >= 2 {
b := []byte(s)
for {
f := false
for i := 0; i < len(b)-1; i++ {
if b[i] == b[i+1] {
b = append(b[:i], b[i+2:]...)
f = true
}
}
if f == false {
break
}
}
return string(b)
}
return s
}
题目链接
给你一个字符串数组 tokens
,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
注意:
'+'
、'-'
、'*'
和 '/'
。示例 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 + *
也可以依据次序计算出正确结果。Python:
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
stack = []
for token in tokens:
if token in {"+", "-", "*", "/"}:
operand2 = stack.pop()
operand1 = stack.pop()
if token == "+":
result = operand1 + operand2
elif token == "-":
result = operand1 - operand2
elif token == "*":
result = operand1 * operand2
else:
result = int(operand1 / operand2)
stack.append(result)
else:
stack.append(int(token))
return stack[0]
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
stack = []
operators = {
"+": lambda x, y: x + y,
"-": lambda x, y: x - y,
"*": lambda x, y: x * y,
"/": lambda x, y: int(x / y),
}
for token in tokens:
if token in operators:
operand2 = stack.pop()
operand1 = stack.pop()
operation = operators[token]
result = operation(operand1, operand2)
stack.append(result)
else:
stack.append(int(token))
return stack[0]
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
stack = [0] * ((len(tokens) + 1) // 2)
index = -1
operators = {
"+": lambda x, y: x + y,
"-": lambda x, y: x - y,
"*": lambda x, y: x * y,
"/": lambda x, y: int(x / y),
}
for token in tokens:
try:
val = int(token)
index += 1
stack[index] = val
except ValueError:
index -= 1
stack[index] = operators[token](stack[index], stack[index + 1])
return stack[0]
Go:
func evalRPN(tokens []string) int {
var stack []int
for _, v := range tokens {
switch v {
case "+":
stack = append(stack[:len(stack)-2], stack[len(stack)-2]+stack[len(stack)-1])
case "-":
stack = append(stack[:len(stack)-2], stack[len(stack)-2]-stack[len(stack)-1])
case "*":
stack = append(stack[:len(stack)-2], stack[len(stack)-2]*stack[len(stack)-1])
case "/":
stack = append(stack[:len(stack)-2], stack[len(stack)-2]/stack[len(stack)-1])
default:
num, _ := strconv.Atoi(v)
stack = append(stack, num)
}
}
return stack[0]
}
func evalRPN(tokens []string) int {
var stack []int
operators := map[string]func(int, int) int{
"+": func(x, y int) int { return x + y },
"-": func(x, y int) int { return x - y },
"*": func(x, y int) int { return x * y },
"/": func(x, y int) int { return x / y },
}
for _, token := range tokens {
if operator, ok := operators[token]; ok {
operand2 := stack[len(stack)-1]
operand1 := stack[len(stack)-2]
stack = stack[:len(stack)-2]
result := operator(operand1, operand2)
stack = append(stack, result)
} else {
num, _ := strconv.Atoi(token)
stack = append(stack, num)
}
}
return stack[0]
}
func evalRPN(tokens []string) int {
stack := make([]int, (len(tokens)+1)/2)
index := -1
operators := map[string]func(int, int) int{
"+": func(x, y int) int { return x + y },
"-": func(x, y int) int { return x - y },
"*": func(x, y int) int { return x * y },
"/": func(x, y int) int { return x / y },
}
for _, token := range tokens {
if val, err := strconv.Atoi(token); err == nil {
index++
stack[index] = val
} else {
index--
stack[index] = operators[token](stack[index], stack[index+1])
}
}
return stack[0]
}
给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
示例 2:
输入:nums = [1], k = 1
输出:[1]
提示:
1 <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4
1 <= k <= nums.length
这道题难就难在使用暴力法会超出时间限制。
Python:
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
n = len(nums)
# 注意 Python 默认的优先队列是小根堆
q = [(-nums[i], i) for i in range(k)]
heapq.heapify(q)
ans = [-q[0][0]]
for i in range(k, n):
heapq.heappush(q, (-nums[i], i))
while q[0][1] <= i - k:
heapq.heappop(q)
ans.append(-q[0][0])
return ans
#单调队列,使用python的deque
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
n = len(nums) # 获取输入数组长度
q = collections.deque() # 双端队列存放数组索引
# 处理前k个元素,维护一个递减队列
for i in range(k):
while q and nums[i] >= nums[q[-1]]:
q.pop() # 如果新来的数比队尾元素要大,则队尾元素出队
q.append(i) # 默认新来的数入队
ans = [nums[q[0]]] # 把队首元素加入结果中,因为它是当前最大的元素
for i in range(k, n): # 对数组剩余元素执行上述操作
while q and nums[i] >= nums[q[-1]]:
q.pop()
q.append(i)
while q[0] <= i - k: # 如果队首元素不在滑动窗口范围内,要移除
q.popleft()
ans.append(nums[q[0]]) # 把队首元素加入结果
return ans # 返回结果
#单调队列
class Solution:
# 定义最大滑动窗口函数
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
# 初始化一个空队列
q = []
# 定义一个用于入队操作的函数,保证队列头部始终是当前窗口的最大值
def push(i: int) -> None:
# 使用nonlocal关键字指定q是外部函数的局部变量
nonlocal q
# 在当前数入队前,将队列中所有小于当前数的数弹出,确保队列头部元素始终为最大值
while q and nums[i] >= nums[q[-1]]:
q = q[:-1]
# 将当前索引压入队列
q.append(i)
# 首次形成窗口
for i in range(k):
push(i)
# 取首个窗口的最大值
ans = [nums[q[0]]]
# 滑动窗口并更新结果
for i in range(k, len(nums)):
push(i)
# 如果队列头部的值已经离开了窗口,那么将其从队列中移除
while q[0] <= i - k:
q = q[1:]
# 将当前窗口最大值放入结果数组
ans.append(nums[q[0]])
# 返回结果数组
return ans
class MyQueue:
def __init__(self):
self.queue = deque() # 使用deque实现单调队列
def pop(self, value):
"""
每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。
同时pop之前判断队列当前是否为空。
"""
if self.queue and value == self.queue[0]:
self.queue.popleft()
def push(self, value):
"""
如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。
这样就保持了队列里的数值是单调从大到小的了。
"""
while self.queue and value > self.queue[-1]:
self.queue.pop()
self.queue.append(value)
def front(self):
"""查询当前队列里的最大值,直接返回队列前端也就是front就可以了。"""
return self.queue[0]
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
que = MyQueue()
result = []
for i in range(k): # 先将前k的元素放进队列
que.push(nums[i])
result.append(que.front()) # result 记录前k的元素的最大值
for i in range(k, len(nums)):
que.pop(nums[i - k]) # 滑动窗口移除最前面元素
que.push(nums[i]) # 滑动窗口前加入最后面的元素
result.append(que.front()) # 记录对应的最大值
return result
Go:
//优先队列
// 定义全局可变的整数切片 a
var a []int
// 创建一个结构体 hp,该结构体包含 sort 接口的 IntSlice
type hp struct{ sort.IntSlice }
// 重写 Less 方法,使其实现堆的从大到小排列
// 如果 h.IntSlice[i] 的值小于 h.IntSlice[j] 的值,那么返回true
func (h hp) Less(i, j int) bool { return a[h.IntSlice[i]] > a[h.IntSlice[j]] }
// Push 方法用于添加元素到堆中
func (h *hp) Push(v interface{}) { h.IntSlice = append(h.IntSlice, v.(int)) }
// Pop 方法用于从堆中移除元素
func (h *hp) Pop() interface{} {
a := h.IntSlice
v := a[len(a)-1]
h.IntSlice = a[:len(a)-1]
return v
}
// maxSlidingWindow 是滑动窗口最大值的具体实现
func maxSlidingWindow(nums []int, k int) []int {
// 赋值 a
a = nums
// 创建 hp 结构体实例
q := &hp{make([]int, k)}
// 初始堆
for i := 0; i < k; i++ {
q.IntSlice[i] = i
}
// 初始整理堆
heap.Init(q)
n := len(nums)
// 开始滑动窗口操作
ans := make([]int, 1, n-k+1)
ans[0] = nums[q.IntSlice[0]]
for i := k; i < n; i++ {
heap.Push(q, i)
for q.IntSlice[0] <= i-k {
heap.Pop(q)
}
ans = append(ans, nums[q.IntSlice[0]])
}
return ans
}
//单调队列
func maxSlidingWindow(nums []int, k int) []int {
var q []int // 使用一个队列q来存储元素的索引
// 定义一个局部函数push,它的功能是向队列中添加元素
push := func(i int) {
// 如果队列不为空,且当前元素值大于等于队列尾部元素值
for len(q) > 0 && nums[i] >= nums[q[len(q)-1]] {
// 队列尾部元素出队
q = q[:len(q)-1]
}
// 将当前元素的索引入队
q = append(q, i)
}
// 先将前k个元素做处理
for i := 0; i < k; i++ {
push(i)
}
n := len(nums)
// 初始化并设置返回结果数组的第一个元素
ans := make([]int, 1, n-k+1)
ans[0] = nums[q[0]]
// 从k开始遍历,对于每个元素,都将其添加到队列中
// 并保证队列的头部元素总是当前窗口的最大值
for i := k; i < n; i++ {
push(i)
// 如果队列中的头部元素不在当前窗口中,就将其出队
for q[0] <= i-k {
q = q[1:]
}
// 把当前窗口的最大值(队列q的头部元素对应的值)添加到结果数组中
ans = append(ans, nums[q[0]])
}
return ans
}
// MyQueue 结构体定义了一个单调队列解决方案
type MyQueue struct {
queue []int // 队列中的元素
}
// MyQueue的构造函数
func NewMyQueue() *MyQueue {
return &MyQueue{
queue: make([]int, 0),
}
}
// Front 返回队列的第一个元素
func (m *MyQueue) Front() int {
return m.queue[0]
}
// Back 返回队列的最后一个元素
func (m *MyQueue) Back() int {
return m.queue[len(m.queue)-1]
}
// Empty 检查队列是否为空
func (m *MyQueue) Empty() bool {
return len(m.queue) == 0
}
// Push 在队列后面添加一个元素
// 如果新元素比队列末尾的元素大,则移除队列末尾的元素
func (m *MyQueue) Push(val int) {
for !m.Empty() && val > m.Back() {
m.queue = m.queue[:len(m.queue)-1]
}
m.queue = append(m.queue, val)
}
// Pop 从队列前面移除一个元素
func (m *MyQueue) Pop(val int) {
if !m.Empty() && val == m.Front() {
m.queue = m.queue[1:]
}
}
// maxSlidingWindow 返回每个子数组(大小为k)的最大值
func maxSlidingWindow(nums []int, k int) []int {
queue := NewMyQueue() // 初始化队列
length := len(nums)
res := make([]int, 0) // 存储结果
// 将前k个元素放入队列并记录最大值
for i := 0; i < k; i++ {
queue.Push(nums[i])
}
res = append(res, queue.Front())
// 使窗口滑过数组的其余部分
for i := k; i < length; i++ {
queue.Pop(nums[i-k]) // 移除窗口外的元素
queue.Push(nums[i]) // 添加进窗口的新元素
res = append(res, queue.Front()) // 记录最大值
}
return res
}
题目链接
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
提示:
1 <= nums.length <= 105
k
的取值范围是 [1, 数组中不相同的元素的个数]
k
个高频元素的集合是唯一的Python:
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
m = defaultdict(int)
for i in nums:
m[i] += 1
return sorted(m, key=lambda x: m[x], reverse=True)[:k]
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
m = defaultdict(int)
for i in nums:
m[i] += 1
top = sorted(m.values(), reverse=True)[:k]
return [k for k in m if m[k] in top]
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
# 统计每个数字出现的频次
occurrences = {}
for num in nums:
occurrences[num] = occurrences.get(num, 0) + 1
# 建立最小堆
min_heap = []
for key, value in occurrences.items():
heapq.heappush(min_heap, (value, key))
if len(min_heap) > k:
heapq.heappop(min_heap)
# 将堆中的元素取出,放入返回结果
result = [heapq.heappop(min_heap)[1] for _ in range(k)]
# 返回最频繁的k个元素
return result
Go:
//本人解法,简单暴力
func topKFrequent(nums []int, k int) []int {
m := make(map[int]int)
for _, v := range nums {
m[v]++
}
keys := make([]int, 0, len(m))
for key := range m {
keys = append(keys, key)
}
sort.Slice(keys, func(i, j int) bool {
return m[keys[i]] > m[keys[j]]
})
return keys[:k]
}
//优先级队列,小顶堆
func topKFrequent(nums []int, k int) []int {
// 统计每个数字出现的频次
occurrences := map[int]int{}
for _, num := range nums {
occurrences[num]++
}
// 建立堆
h := &IHeap{}
heap.Init(h)
// 遍历频次表,将数字和对应的频次压入堆。当堆的元素数量大于k时,弹出堆顶
for key, value := range occurrences {
heap.Push(h, [2]int{key, value})
if h.Len() > k {
heap.Pop(h)
}
}
// 将堆中的元素取出,放入返回结果
ret := make([]int, k)
for i := 0; i < k; i++ {
ret[k - i - 1] = heap.Pop(h).([2]int)[0]
}
// 返回最频繁的k个元素
return ret
}
// 定义堆
type IHeap [][2]int
// Len 方法返回堆的长度
func (h IHeap) Len() int { return len(h) }
// Less 方法实现堆中元素的比较规则
func (h IHeap) Less(i, j int) bool { return h[i][1] < h[j][1] }
// Swap 方法实现堆中元素的交换
func (h IHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
// Push 方法实现元素的入堆操作
func (h *IHeap) Push(x interface{}) {
*h = append(*h, x.([2]int))
}
// Pop 方法实现元素的出堆操作
func (h *IHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}