设计一个支持 push
,pop
,top
操作,并能在常数时间内检索到最小元素的栈。
push(x) —— 将元素 x 推入栈中。 pop() —— 删除栈顶的元素。 top() —— 获取栈顶元素。 getMin() —— 检索栈中的最小元素。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 输入: ["MinStack","push","push","push","getMin","pop","top","getMin"] [[],[-2],[0],[-3],[],[],[],[]] 输出: [null,null,null,null,-3,null,0,-2] 解释: MinStack minStack = new MinStack(); minStack.push(-2); minStack.push(0); minStack.push(-3); minStack.getMin(); --> 返回 -3. minStack.pop(); minStack.top(); --> 返回 0. minStack.getMin(); --> 返回 -2.
提示:
pop、top 和 getMin 操作总是在 非空栈 上调用。
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 class MinStack { var head:ListNode ? init () { head = ListNode (min:Int .max) } func push (_ val : Int ) { head = ListNode (val: val, min: min (val, head! .min), next: head) } func pop () { head = head? .next } func top () -> Int { return head? .val ?? 0 } func getMin () -> Int { return head? .min ?? 0 } class ListNode { let val: Int let min:Int let next: ListNode ? init (val : Int = 0 ,min :Int = 0 ,next :ListNode ? = nil ) { self .val = val self .min = min self .next = next } } }
解题思路:
题目要求我们从栈元素中找到最小值,按照正常想,我们都会遍历一遍栈的元素,但是这样时间复杂度就是O(n),题目要求是O(1),一般遇到这种问题,就需要空间换时间了。 使用链表,在每个节点保存当前的最小值,每次push都记录当前元素对应的最小值,每个节点都一一对应一个最小值,这样子getMin时间复杂度就是O(1),同道理,这里用两个栈也可以做到一一对应也能解决。
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
示例
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
提示
1 <= nums.length <= 105
-104 <= nums[i] <= 104
1 <= k <= nums.length
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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 class Solution { struct Deque <T > { private var array = [T ]() var isEmpty: Bool { return array.isEmpty } var count: Int { return array.count } mutating func enqueue (_ element : T ) { array.append(element) } mutating func enqueueInsert (_ element : T ) { array.insert(element, at: 0 ) } mutating func removeFirst () -> T ? { if isEmpty { return nil } else { return array.removeFirst() } } mutating func removeLast () -> T ? { if isEmpty { return nil } else { return array.removeLast() } } func getFirst () -> T ? { return array.first } func getLast () -> T ? { return array.last } } func maxSlidingWindow (_ nums : [Int ], _ k : Int ) -> [Int ] { if nums.count == 0 || k < 1 { return [Int ]()} if k == 1 { return nums } var maxes = [Int ](repeating: 0 , count: nums.count - k + 1 ) var deque = Deque <Int >() for ri in 0 ..< nums.count { while ! deque.isEmpty && nums[deque.getLast() ?? 0 ] <= nums[ri] { _ = deque.removeLast() } deque.enqueue(ri) let li = ri - k + 1 if li < 0 { continue } let temp = deque.getFirst() ?? 0 if temp < li { _ = deque.removeFirst() } maxes[li] = nums[deque.getFirst() ?? 0 ] } return maxes } }
解题思路:
使用到双端队列的特性,队首队尾均可进出的特性,实现单调队列
单调队列从队首到队尾,nums[队列元素],是逐渐减小的
队列里存放的是对应值的索引
每次入队列都需要从队尾开始遍历只要nums[队尾] <= nums[ri],就删除队尾(比较是否大于队尾,大于就删除)
每次移动窗口都需要检查队首的合法性(失效,不在滑动窗口索引范围内)就需要删除队首元素
最后取出单调队列的队首设置最大值(也就是窗口的最大值)
给定一个不含重复元素的整数数组 nums 。一个以此数组直接递归构建的 最大二叉树 定义如下:
二叉树的根是数组 nums 中的最大元素。
左子树是通过数组中 最大值左边部分 递归构造出的最大二叉树。
右子树是通过数组中 最大值右边部分 递归构造出的最大二叉树。
返回有给定数组 nums 构建的 最大二叉树 。
示例
1 2 3 4 5 6 7 8 9 10 11 12 输入:nums = [3,2,1,6,0,5] 输出:[6,3,5,null,2,0,null,null,1] 解释:递归调用如下所示: - [3,2,1,6,0,5] 中的最大值是 6 ,左边部分是 [3,2,1] ,右边部分是 [0,5] 。 - [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1] 。 - 空数组,无子节点。 - [2,1] 中的最大值是 2 ,左边部分是 [] ,右边部分是 [1] 。 - 空数组,无子节点。 - 只有一个元素,所以子节点是一个值为 1 的节点。 - [0,5] 中的最大值是 5 ,左边部分是 [0] ,右边部分是 [] 。 - 只有一个元素,所以子节点是一个值为 0 的节点。 - 空数组,无子节点。
提示
1 <= nums.length <= 1000
0 <= nums[i] <= 1000
nums
中的所有整数 互不相同
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 class Solution { func constructMaximumBinaryTree (_ nums : [Int ]) -> TreeNode ? { guard nums.count != 0 else {return nil } return findRoot(nums,0 ,nums.count) } func findRoot (_ nums : [Int ],_ l :Int ,_ r :Int ) -> TreeNode ? { guard l != r else {return nil } var maxIdx = l for i in (l + 1 )..< r { if nums[i] > nums[maxIdx] { maxIdx = i } } let treeNode = TreeNode (nums[maxIdx]) treeNode.left = findRoot(nums,l,maxIdx) treeNode.right = findRoot(nums,maxIdx + 1 ,r) return treeNode } }
解题思路:
这里需要每次都从数组分出最大子树根节点,以最大数字左边和右边一直对半找出最大数也就是最大根节点,一直细分到左右索引相等,所以这里可以用到递归的思路,递归调用找出最大根节点,注意这里是[l, r),[
包括l )
不包括r。
请根据每日 气温
列表 temperatures
,请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0
来代替。
示例 1: 输入: temperatures = [73,74,75,71,69,72,76,73] 输出: [1,1,4,2,1,1,0,0]
示例 2: 输入: temperatures = [30,40,50,60] 输出: [1,1,1,0]
提示: 1 <= temperatures.length <= 105 30 <= temperatures[i] <= 100
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 func dailyTemperatures (_ temperatures : [Int ]) -> [Int ] { guard temperatures.count != 0 else {return []} var result = [Int ](repeating: 0 , count: temperatures.count) let stack = Stack <Int >() for i in 0 ..< temperatures.count { while ! stack.isEmpty && temperatures[i] > temperatures[stack.top()] { result[stack.top()] = i - stack.top() _ = stack.pop() } stack.push(i) } return result } class Stack <E > { var array = [E ]() var isEmpty: Bool { return array.isEmpty } func push (_ element : E ) { array.append(element) } func pop () -> E { array.removeLast() } func top () -> E { array.last! } func size () -> Int { array.count } }
解题思路:
利用栈结构,实现一个单调递减栈,栈底放最大数,栈顶放最小数
遍历数组,每次跟栈顶的元素比较,如果小于栈顶元素直接入栈
如果大于代表准备入栈的元素是出栈元素(不符合单调递减栈规则,元素需要出栈)靠近右边第一个比它大的数值
计算索引差值,求出更高温度隔了几天
给定一个只包括 ‘(‘,’)’,’{‘,’}’,’[‘,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。
示例 1:
输入:s = “()” 输出:true 示例 2:
输入:s = “()[]{}” 输出:true 示例 3:
输入:s = “(]” 输出:false 示例 4:
输入:s = “([)]” 输出:false 示例 5:
输入:s = “{[]}” 输出:true
提示:
1 <= s.length <= 104 s 仅由括号 ‘()[]{}’ 组成
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 class Solution { func isValid (_ s : String ) -> Bool { guard s.count% 2 == 0 else { return false } let map:[Character :Character ] = [ "(" :")" , "[" :"]" , "{" :"}" ] var stack = [Character ]() for char in s { if map.keys.contains(char) { stack.append(char) }else { if stack.isEmpty { return false }else if map[stack.last! ] != char{ return false }else { stack.popLast() } } } return stack.isEmpty } }
解题思路:
根据题目意思,我们能发现规律,先出现的左括号类型后匹配,所以我们能想到用栈的数据结构先进后出
新建一个map来存储左右括号的规则,遍历字符串,如果等于map的Key代表是左括号,直接入栈
如果不是代表是右括号类型,开始跟栈顶匹配,匹配就出栈继续遍历,不匹配直接返回false
栈为空代表括号匹配都成功了,不为空就为不匹配
字符串如果不是偶数是奇数直接返回,因为括号必须是成双成对的
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(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 操作是合法的。 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
进阶:
你能否实现每个操作均摊时间复杂度为 O(1) 的队列?换句话说,执行 n 个操作的总时间复杂度为 O(n) ,即使其中一个操作可能花费较长时间。
示例:
输入: [“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 操作)
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 class MyQueue { var s1 = [Int ]() var s2 = [Int ]() init () { } func push (_ x : Int ) { s1.append(x) } func pop () -> Int { handleData() return s2.popLast() ?? 0 } func peek () -> Int { handleData() return s2.last ?? 0 } func empty () -> Bool { return s1.isEmpty && s2.isEmpty } func handleData () { if s2.isEmpty { while ! s1.isEmpty { s2.append(s1.popLast() ?? 0 ) } } } }
解题思路:
这里使用双栈,s1负责入队元素的栈, s2负责出队元素的栈
s2栈顶时刻保持是第一个入队列的元素
pop()和peek()都需要判断s2是否为空,为空就需要遍历把s1元素依次添加进s2