commit 5bf978cff70b96028b61d095b71e73d6b1776ae0 Author: JingmingZhang Date: Sun Apr 19 09:09:30 2020 +0800 Solved @zjming diff --git a/0155-min-stack/Animation/1.mp4 b/0155-min-stack/Animation/1.mp4 new file mode 100644 index 0000000..a932bb5 Binary files /dev/null and b/0155-min-stack/Animation/1.mp4 differ diff --git a/0155-min-stack/Animation/Animation.gif b/0155-min-stack/Animation/Animation.gif new file mode 100644 index 0000000..91358be Binary files /dev/null and b/0155-min-stack/Animation/Animation.gif differ diff --git a/0155-min-stack/Article/0155-min-stack b/0155-min-stack/Article/0155-min-stack new file mode 100644 index 0000000..4bd9ac3 --- /dev/null +++ b/0155-min-stack/Article/0155-min-stack @@ -0,0 +1,77 @@ +#### 题目描述 + +> 设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。 +> +> + push(x) —— 将元素 x 推入栈中。 +> + pop() —— 删除栈顶的元素。 +> + top() —— 获取栈顶元素。 +> + getMin() —— 检索栈中的最小元素。 + +```java +示例: + MinStack minStack = new MinStack(); + minStack.push(-2); + minStack.push(0); + minStack.push(-5); + minStack.push(1) + minStack.getMin(); --> 返回 -5. + minStack.pop(); + minStack.top(); --> 返回 -5. + minStack.getMin(); --> 返回 -5. +``` + +#### 题目解析 + +为了能在常数时间内检测到栈中的最小元素,我们可以通过"空间换时间"的方式进行实现,为栈本身(数据栈\_data)增加一个辅助栈(最小值栈\_min)。每一次元素入 \_data 栈,则在 \_min 栈中增加对应的最小值;当 \_data 栈中的元素出栈,则 \_min 栈也进行出栈操作 + +#### 动画理解 + +![](../Animation/Animation.gif) + +#### 代码实现 + +```java +class MinStack { + + private Stack _data; + private Stack _min; + + /** initialize your data structure here. */ + public MinStack() { + _data = new Stack<>(); + _min = new Stack<>(); + } + + public void push(int x) { + _data.add(x); + if (_min.isEmpty()){ + _min.push(x); + } + else{ + if (x > _min.peek()){ + x = _min.peek(); + } + _min.push(x); + } + } + + public void pop() { + _data.pop(); + _min.pop(); + } + + public int top() { + return _data.peek(); + } + + public int getMin() { + return _min.peek(); + } +} +``` + +#### 复杂度分析 + ++ 时间复杂度:O(1)。 ++ 空间复杂度:O(n)。 + diff --git a/0155-min-stack/Code/1.java b/0155-min-stack/Code/1.java new file mode 100644 index 0000000..0917dba --- /dev/null +++ b/0155-min-stack/Code/1.java @@ -0,0 +1,37 @@ +class MinStack { + + private Stack _data; + private Stack _min; + + /** initialize your data structure here. */ + public MinStack() { + _data = new Stack<>(); + _min = new Stack<>(); + } + + public void push(int x) { + _data.add(x); + if (_min.isEmpty()){ + _min.push(x); + } + else{ + if (x > _min.peek()){ + x = _min.peek(); + } + _min.push(x); + } + } + + public void pop() { + _data.pop(); + _min.pop(); + } + + public int top() { + return _data.peek(); + } + + public int getMin() { + return _min.peek(); + } +} \ No newline at end of file diff --git a/0215-Kth-Largest-Element-in-an-Array/Animation/1.mp4 b/0215-Kth-Largest-Element-in-an-Array/Animation/1.mp4 new file mode 100644 index 0000000..67a1b0e Binary files /dev/null and b/0215-Kth-Largest-Element-in-an-Array/Animation/1.mp4 differ diff --git a/0215-Kth-Largest-Element-in-an-Array/Animation/Animation.gif b/0215-Kth-Largest-Element-in-an-Array/Animation/Animation.gif new file mode 100644 index 0000000..790141c Binary files /dev/null and b/0215-Kth-Largest-Element-in-an-Array/Animation/Animation.gif differ diff --git a/0215-Kth-Largest-Element-in-an-Array/Article/0215-Kth-Largest-Element-in-an-Array b/0215-Kth-Largest-Element-in-an-Array/Article/0215-Kth-Largest-Element-in-an-Array new file mode 100644 index 0000000..c7ea5bd --- /dev/null +++ b/0215-Kth-Largest-Element-in-an-Array/Article/0215-Kth-Largest-Element-in-an-Array @@ -0,0 +1,88 @@ +# LeetCode 第 215 号问题:数组中的第K个最大元素 + +> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ]() 系列文章之一。 +> +> 同步博客:https://www.algomooc.com + +题目来源于 LeetCode 上第 215 号问题:数组中的第K个最大元素。题目难度为 Medium,目前通过率为 62.0% 。 + +#### 题目描述 + +> 在未排序的数组中找到第 **k** 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 +> + +```java +示例1: +输入: [3,2,1,5,6,4] 和 k = 2 +输出: 5 +示例2: +输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 +输出: 4 +``` + +#### 题目解析 + +维护一个K大小的最小堆,堆中元素个数小于K时,新元素直接进入堆中;否则,当堆顶小于新元素时,弹出堆顶,将新元素加入堆。 + +由于堆是最小堆,堆顶是堆中的最小元素,新元素都会保证比堆顶小(否则新元素替换堆顶),故堆中K个元素是已扫描元素里最大的K个;堆顶元素即为第K大数。 + +#### 动画理解 + +![](../Animation/Animation.gif) + +#### 代码实现 + +Java语言 + +```java +class Solution { + public int findKthLargest(int[] nums, int k) { + // // 创建一个小顶堆(优先队列模拟) + PriorityQueue heap = + new PriorityQueue(); + + // 在堆中维护当前最大k个元素 + for (int i = 0; i < nums.length; i++){ + if(heap.size() < k){ + heap.add(nums[i]); + }else if (heap.element() < nums[i]){ + heap.poll(); + heap.add(nums[i]); + } + } + return heap.poll(); + } +} +``` + +C++语言实现 + +```c++ +#include + +class Solution { +public: + int findKthLargest(vector& nums, int k) { + priority_queue, greater > Q; + for(int i = 0; i < nums.size(); i++){ + if(Q.size() < k){ + Q.push(nums[i]); + } + else if(Q.top() < nums[i]){ + Q.pop(); + Q.push(nums[i]); + } + } + + return Q.top(); + } +}; +``` + +#### 复杂度分析 + ++ 时间复杂度:向大小为 k 的堆中添加元素的时间复杂度为O(logK),重复该操作 N 次,故总时间复杂度为 O(NlogK) ++ 空间复杂度:O(K) + + + diff --git a/0215-Kth-Largest-Element-in-an-Array/Code/1.cpp b/0215-Kth-Largest-Element-in-an-Array/Code/1.cpp new file mode 100644 index 0000000..716dae0 --- /dev/null +++ b/0215-Kth-Largest-Element-in-an-Array/Code/1.cpp @@ -0,0 +1,19 @@ +#include + +class Solution { +public: + int findKthLargest(vector& nums, int k) { + priority_queue, greater > Q; + for(int i = 0; i < nums.size(); i++){ + if(Q.size() < k){ + Q.push(nums[i]); + } + else if(Q.top() < nums[i]){ + Q.pop(); + Q.push(nums[i]); + } + } + + return Q.top(); + } +}; \ No newline at end of file diff --git a/0215-Kth-Largest-Element-in-an-Array/Code/1.java b/0215-Kth-Largest-Element-in-an-Array/Code/1.java new file mode 100644 index 0000000..0d44773 --- /dev/null +++ b/0215-Kth-Largest-Element-in-an-Array/Code/1.java @@ -0,0 +1,18 @@ +class Solution { + public int findKthLargest(int[] nums, int k) { + // // һСѣȶģ⣩ + PriorityQueue heap = + new PriorityQueue(); + + // ڶάǰkԪ + for (int i = 0; i < nums.length; i++){ + if(heap.size() < k){ + heap.add(nums[i]); + }else if (heap.element() < nums[i]){ + heap.poll(); + heap.add(nums[i]); + } + } + return heap.poll(); + } +} \ No newline at end of file diff --git a/0290-Word-Pattern/Animation/1.mp4 b/0290-Word-Pattern/Animation/1.mp4 new file mode 100644 index 0000000..fb1f281 Binary files /dev/null and b/0290-Word-Pattern/Animation/1.mp4 differ diff --git a/0290-Word-Pattern/Animation/Animation.gif b/0290-Word-Pattern/Animation/Animation.gif new file mode 100644 index 0000000..ec08b4e Binary files /dev/null and b/0290-Word-Pattern/Animation/Animation.gif differ diff --git a/0290-Word-Pattern/Article/0290-Word-Pattern b/0290-Word-Pattern/Article/0290-Word-Pattern new file mode 100644 index 0000000..c2ec694 --- /dev/null +++ b/0290-Word-Pattern/Article/0290-Word-Pattern @@ -0,0 +1,87 @@ +# LeetCode 第 290 号问题:单词规律 + +> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ]() 系列文章之一。 +> +> 同步博客:https://www.algomooc.com + +题目来源于 LeetCode 上第 290 号问题:单词规律。题目难度为 Easy,目前通过率为 42.4% 。 + +#### 题目描述 + +> 给定一种规律 `pattern` 和一个字符串 `str` ,判断 `str` 是否遵循相同的规律。 +> +> 这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 str 中的每个非空单词之间存在着双向连接的对应规律。 +> +> 说明:你可以假设 `pattern` 只包含小写字母, `str` 包含了由单个空格分隔的小写字母。 + +```java +示例1: +输入: pattern = "abba", str = "dog cat cat dog" +输出: true +示例2: +输入:pattern = "abba", str = "dog cat cat fish" +输出: false +示例3: +输入: pattern = "aaaa", str = "dog cat cat dog" +输出: false +示例4: +输入: pattern = "abba", str = "dog dog dog dog" +输出: false +``` + +#### 题目解析 + +这道题目主要考察哈希表和字符串的内容。可以将题目拆解为下面三步: + +1. 设置`pattern`字符到单词(字符串 `str`)的**映射(哈希)**,使用`HashMap()`存储;使用`HashSet()` 记录被使用过的单词 。 +2. 若单词个数和`pattern`字符个数不匹配,返回false; +3. 遍历`pattern`,同时**对应的**向前移动 `str` 中单词的指针,每次拆分出`pattern`中的一个字符, **判断:** + + 如果该字符**从未出现**在哈希表中: + + 如果该字符对应的单词已被使用过 ,即`HashSet()`中包含该字符对应的单词,则返回false; + + 将该字符与其对应的单词**做映射**,加入哈希表中;**标记**该字符指向的单词**为已使用**,并加入`HashSet()`; + + 如果该字符在哈希表的**映射单词**与当前指向的单词不同,则返回false; + +#### 动画理解 + +![](../Animation/Animation.gif) + +#### 代码实现 + +Java语言 + +```java +class Solution { + public boolean wordPattern(String pattern, String str) { + HashMap map = new HashMap<>(); + HashSet set = new HashSet<>(); + String[] array = str.split(" "); + + if (pattern.length() != array.length) { + return false; + } + for (int i = 0; i < pattern.length(); i++) { + char key = pattern.charAt(i); + if (!map.containsKey(key)) { + if (set.contains(array[i])) { + return false; + } + map.put(key, array[i]); + set.add(array[i]); + } else { + if (!map.get(key).equals(array[i])) { + return false; + } + } + } + return true; + } +} +``` + +#### 复杂度分析 + ++ 时间复杂度:遍历`pattren` 一遍,时间复杂度O(n) ++ 空间复杂度:需要申请`HashMap()` 与 `HashSet()` ,还需要将字符串 `str` 分割后存储起来,空间复杂度O(n) + + + diff --git a/0290-Word-Pattern/Code/1.java b/0290-Word-Pattern/Code/1.java new file mode 100644 index 0000000..ee4780f --- /dev/null +++ b/0290-Word-Pattern/Code/1.java @@ -0,0 +1,26 @@ +class Solution { + public boolean wordPattern(String pattern, String str) { + HashMap map = new HashMap<>(); + HashSet set = new HashSet<>(); + String[] array = str.split(" "); + + if (pattern.length() != array.length) { + return false; + } + for (int i = 0; i < pattern.length(); i++) { + char key = pattern.charAt(i); + if (!map.containsKey(key)) { + if (set.contains(array[i])) { + return false; + } + map.put(key, array[i]); + set.add(array[i]); + } else { + if (!map.get(key).equals(array[i])) { + return false; + } + } + } + return true; + } +} \ No newline at end of file diff --git a/0394-Decode-String/Animation/1.mp4 b/0394-Decode-String/Animation/1.mp4 new file mode 100644 index 0000000..d0d8022 Binary files /dev/null and b/0394-Decode-String/Animation/1.mp4 differ diff --git a/0394-Decode-String/Animation/Animation.gif b/0394-Decode-String/Animation/Animation.gif new file mode 100644 index 0000000..0437424 Binary files /dev/null and b/0394-Decode-String/Animation/Animation.gif differ diff --git a/0394-Decode-String/Article/0394-Decode-String b/0394-Decode-String/Article/0394-Decode-String new file mode 100644 index 0000000..b4b0be0 --- /dev/null +++ b/0394-Decode-String/Article/0394-Decode-String @@ -0,0 +1,80 @@ +# LeetCode 第 394 号问题:字符串解码 + +> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ]() 系列文章之一。 +> +> 同步博客:https://www.algomooc.com + +题目来源于 LeetCode 上第 394 号问题:字符串解码。题目难度为 Medium,目前通过率为 49.7% 。 + +#### 题目描述 + +> 给定一个经过编码的字符串,返回它解码后的字符串。 +> +> 编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。 +> +> 你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。 +> +> 此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。 +> + +```java +示例: + s = "3[a]2[bc]", 返回 "aaabcbc". + s = "3[a2[c]]", 返回 "accaccacc". + s = "2[abc]3[cd]ef", 返回 "abcabccdcdcdef". +``` + +#### 题目解析 + +由于中括号[]存在嵌套,因此需要**从内向外**生成并拼接字符串,这与栈的**先进后出**的特性相一致。我们可以增加一个辅助栈 **stack\_multi** 用于存储紧挨着左方括号[ 的倍数,每当遇到左方括号时,**res** 与 **multi** 的值进行入栈操作;当遇到右方括号时,进行出栈操作;当遇到数字时,更新 **multi** 的值;当遇到除方括号和数字以外的其他字符时,更新 **res** 的值。需要注意更新 **multi** 的值要考虑连续多位数字的情况。 + +#### 动画理解 + +![](../Animation/Animation.gif) + +#### 代码实现 + +```java +class Solution { + public String decodeString(String s) { + StringBuilder res = new StringBuilder(); + int multi = 0; + + Stack stack_multi = new Stack(); + Stack stack_res = new Stack(); + + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if ('[' == c){ + stack_multi.push(multi); + stack_res.push(res.toString()); + multi = 0; + res = new StringBuilder(); + } + else if (']' == c) { + StringBuilder tmp = new StringBuilder(); + int cur_multi = stack_multi.pop(); + for (int j = 0; j < cur_multi; j++){ + tmp.append(res); + } + res = new StringBuilder(stack_res.pop() + tmp); + } + else if(c >= '0' && c <= '9'){ + multi = multi * 10 + (c - '0'); + } + else{ + res.append(c); + } + } + return res.toString(); + } +} +``` + +#### 复杂度分析 + ++ 时间复杂度 *O*(*N*),一次遍历字符串`s`; ++ 空间复杂度 *O(N)*,辅助栈在极端情况下需要线性空间,例如 `4[3[2[LeetCodeAnimation]]]`。 + + + diff --git a/0394-Decode-String/Code/1.java b/0394-Decode-String/Code/1.java new file mode 100644 index 0000000..c5b26e1 --- /dev/null +++ b/0394-Decode-String/Code/1.java @@ -0,0 +1,34 @@ +class Solution { + public String decodeString(String s) { + StringBuilder res = new StringBuilder(); + int multi = 0; + + Stack stack_multi = new Stack(); + Stack stack_res = new Stack(); + + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if ('[' == c){ + stack_multi.push(multi); + stack_res.push(res.toString()); + multi = 0; + res = new StringBuilder(); + } + else if (']' == c) { + StringBuilder tmp = new StringBuilder(); + int cur_multi = stack_multi.pop(); + for (int j = 0; j < cur_multi; j++){ + tmp.append(res); + } + res = new StringBuilder(stack_res.pop() + tmp); + } + else if(c >= '0' && c <= '9'){ + multi = multi * 10 + (c - '0'); + } + else{ + res.append(c); + } + } + return res.toString(); + } +} \ No newline at end of file diff --git a/0946--validate-stack-sequences/Animation/1.mp4 b/0946--validate-stack-sequences/Animation/1.mp4 new file mode 100644 index 0000000..e2ea0e2 Binary files /dev/null and b/0946--validate-stack-sequences/Animation/1.mp4 differ diff --git a/0946--validate-stack-sequences/Animation/Animation.gif b/0946--validate-stack-sequences/Animation/Animation.gif new file mode 100644 index 0000000..5600844 Binary files /dev/null and b/0946--validate-stack-sequences/Animation/Animation.gif differ diff --git a/0946--validate-stack-sequences/Article/0946-validate-stack-sequences b/0946--validate-stack-sequences/Article/0946-validate-stack-sequences new file mode 100644 index 0000000..ec29889 --- /dev/null +++ b/0946--validate-stack-sequences/Article/0946-validate-stack-sequences @@ -0,0 +1,61 @@ +# LeetCode 第 946 号问题:验证栈序列 + +> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ]() 系列文章之一。 +> +> 同步博客:https://www.algomooc.com + +题目来源于 LeetCode 上第 946 号问题:验证栈序列。题目难度为 Medium,目前通过率为 56.5% 。 + +#### 题目描述 + +> 给定 pushed 和 popped 两个序列,每个序列中的 值都不重复,只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时,返回 true;否则,返回 false +> + +```java +示例: +输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1] +输出:true +解释:我们可以按以下顺序执行: +push(1), push(2), push(3), push(4), pop() -> 4, +push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1 +``` + +#### 题目解析 + +出栈结果存储在队列中,按元素顺序push进入栈,每push一个元素,即检查是否与队列首部元素相同,若相同则弹出队列首元素,弹出栈顶元素,直到两个元素不同结束,若最终栈为空,说明序列合法,否则不合法。 + +#### 动画理解 + +![](../Animation/Animation.gif) + +#### 代码实现 + +```java +class Solution { + public boolean validateStackSequences(int[] pushed, int[] popped) { + + int N = pushed.length; + Stack stack = new Stack(); + + int j = 0; + for (int x: pushed) { + stack.push(x); + while (!stack.isEmpty() && j < N && stack.peek() == popped[j]) { + //队头元素出队,栈顶元素出栈 + stack.pop(); + j++; + } + } + if (!stack.isEmpty()){ + return false; + } + return true; + } +} +``` + +#### 复杂度分析 + ++ 时间复杂度:O(n)。 ++ 空间复杂度:O(n)。 + diff --git a/0946--validate-stack-sequences/Code/1.java b/0946--validate-stack-sequences/Code/1.java new file mode 100644 index 0000000..9d2026c --- /dev/null +++ b/0946--validate-stack-sequences/Code/1.java @@ -0,0 +1,21 @@ +class Solution { + public boolean validateStackSequences(int[] pushed, int[] popped) { + + int N = pushed.length; + Stack stack = new Stack(); + + int j = 0; + for (int x: pushed) { + stack.push(x); + while (!stack.isEmpty() && j < N && stack.peek() == popped[j]) { + //ͷԪسӣջԪسջ + stack.pop(); + j++; + } + } + if (!stack.isEmpty()){ + return false; + } + return true; + } +} \ No newline at end of file