用栈实现队列

题目链接

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

  • 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

示例 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
输入:
["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
  • 最多调用 100pushpoppeekempty
  • 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)

Python:

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
#本人解法
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()
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
#将一个栈当作输入栈,用于压入 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:

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
//本人解法
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
}
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
//双栈法
//将一个栈当作输入栈,用于压入 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)的栈,并支持普通栈的全部四种操作(pushtoppopempty)。

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。
  • int pop() 移除并返回栈顶元素。
  • int top() 返回栈顶元素。
  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false

注意:

  • 你只能使用队列的基本操作 —— 也就是 push to backpeek/pop from frontsizeis empty 这些操作。
  • 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
输入:
["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
  • 最多调用100pushpoptopempty
  • 每次调用 poptop 都保证栈不为空

Python:

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
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()
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
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()
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
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
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
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:

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
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
}
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
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
}
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
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. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

示例 1:

1
2
输入:s = "()"
输出:true

示例 2:

1
2
输入:s = "()[]{}"
输出:true

示例 3:

1
2
输入:s = "(]"
输出:false

提示:

  • 1 <= s.length <= 10^4
  • s 仅由括号 '()[]{}' 组成

Python:

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
#本人解法
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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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:

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
//本人解法,注意到有效字符串的长度一定为偶数,因此如果字符串的长度为奇数,我们可以直接返回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
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//简洁版
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 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

示例:

1
2
3
4
输入:"abbaca"
输出:"ca"
解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。

提示:

  1. 1 <= S.length <= 20000
  2. S 仅由小写英文字母组成。

Python:

1
2
3
4
5
6
7
8
9
10
#栈
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#双指针
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//双指针
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])
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//本人解法
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)
}
1
2
3
4
5
6
7
8
9
10
11
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)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//自己写的一种很傻的解法
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 ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 '+''-''*''/'
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。

示例 1:

1
2
3
输入:tokens = ["2","1","+","3","*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

示例 2:

1
2
3
输入:tokens = ["4","13","5","/","+"]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6

示例 3:

1
2
3
4
5
6
7
8
9
10
输入: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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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:

1
2
3
4
5
6
7
8
9
10
11
输入: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:

1
2
输入:nums = [1], k = 1
输出:[1]

提示:

  • 1 <= nums.length <= 10^5
  • -10^4 <= nums[i] <= 10^4
  • 1 <= k <= nums.length

这道题难就难在使用暴力法会超出时间限制。

Python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#单调队列,使用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 # 返回结果
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
#单调队列
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
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
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:

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
//优先队列
// 定义全局可变的整数切片 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
}
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
//单调队列
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
}
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
// 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
}

前 K 个高频元素

题目链接

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

示例 1:

1
2
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例 2:

1
2
输入: nums = [1], k = 1
输出: [1]

提示:

  • 1 <= nums.length <= 105
  • k 的取值范围是 [1, 数组中不相同的元素的个数]
  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

Python:

1
2
3
4
5
6
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]
1
2
3
4
5
6
7
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]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//本人解法,简单暴力
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]
}
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
//优先级队列,小顶堆
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
}