Solved @zjming

This commit is contained in:
JingmingZhang 2020-04-19 09:09:30 +08:00
commit 5bf978cff7
21 changed files with 548 additions and 0 deletions

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 MiB

View File

@ -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<Integer> _data;
private Stack<Integer> _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)。

View File

@ -0,0 +1,37 @@
class MinStack {
private Stack<Integer> _data;
private Stack<Integer> _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();
}
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 MiB

View File

@ -0,0 +1,88 @@
# LeetCode 第 215 号问题数组中的第K个最大元素
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
>
> 同步博客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<Integer> heap =
new PriorityQueue<Integer>();
// 在堆中维护当前最大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 <queue>
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int, vector<int>, greater<int> > 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)

View File

@ -0,0 +1,19 @@
#include <queue>
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int, vector<int>, greater<int> > 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();
}
};

View File

@ -0,0 +1,18 @@
class Solution {
public int findKthLargest(int[] nums, int k) {
// // 创建一个小顶堆优先队列模拟
PriorityQueue<Integer> heap =
new PriorityQueue<Integer>();
// 在堆中维护当前最大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();
}
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 KiB

View File

@ -0,0 +1,87 @@
# LeetCode 第 290 号问题:单词规律
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
>
> 同步博客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<Character, String> map = new HashMap<>();
HashSet<String> 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)

View File

@ -0,0 +1,26 @@
class Solution {
public boolean wordPattern(String pattern, String str) {
HashMap<Character, String> map = new HashMap<>();
HashSet<String> 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;
}
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 MiB

View File

@ -0,0 +1,80 @@
# LeetCode 第 394 号问题:字符串解码
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
>
> 同步博客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<Integer> stack_multi = new Stack();
Stack<String> 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]]]`。

View File

@ -0,0 +1,34 @@
class Solution {
public String decodeString(String s) {
StringBuilder res = new StringBuilder();
int multi = 0;
Stack<Integer> stack_multi = new Stack();
Stack<String> 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();
}
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 MiB

View File

@ -0,0 +1,61 @@
# LeetCode 第 946 号问题:验证栈序列
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
>
> 同步博客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<Integer> 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)。

View File

@ -0,0 +1,21 @@
class Solution {
public boolean validateStackSequences(int[] pushed, int[] popped) {
int N = pushed.length;
Stack<Integer> 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;
}
}