Merge pull request #64 from xiaoshuai96/master

solved @xiaoshuai96
This commit is contained in:
程序员吴师兄 2020-04-24 21:32:41 +08:00 committed by GitHub
commit 32851b8bda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 195 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 MiB

Binary file not shown.

View File

@ -0,0 +1,85 @@
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步个人博客https://www.zhangxiaoshuai.fun
**本题选自leetcode的第11题medium级别目前通过率61.3%**
**题目描述**
```txt
给你n个非负整数a1a2...an每个数代表坐标中的一个点(i,ai)在坐标内画n条垂直线
垂直线i的两个端点分别为(i,ai)(i,0)找出其中的两条线使得它们与x轴共同构成的容器可以容纳最多的水
说明你不能倾斜容器且n的值至少为2
示例
输入[1,8,6,2,5,4,8,3,7]
输出49
```
我们都应该听说过**木桶原理**一个木桶可以装入多少水取决于最短的那块板而这道题也可以与木桶装水的问题对应上
很容易的可以得到---->**容器可以容纳水的容量=两条垂直线中最短的那条*两条线之间的距离**
现在的情况是有很多条线让你计算两两之间能装的最多的水其实暴力法之间就能解决这个问题但是它的时间复杂度也达到了**O(n^2)**
ok那我们先试试用**暴力法**来解 决问题
### 1.暴力法
直接上代码
```java
public int maxArea(int[] height) {
int res = 0;
for(int i = 0;i < height.length;i++){
for(int j = i+1;j < height.length;j++){
int temp = Math.min(height[i],height[j]) * (j-i);
res = Math.max(res,temp);
}
}
return res;
}
```
暴力法是可以通过测试的但是可以看到**程序执行用时**并不理想
```
执行用时 :440 ms, 在所有 Java 提交中击败了17.44% 的用户
内存消耗 :39.9 MB, 在所有 Java 提交中击败了37.86%的用户
```
### 2.双指针
思路使用两个指针**resource****last**分别指向数组的第一个元素和最后一个元素然后我们计算这两条线之间能容纳的水的容量并更新最大容量初始值为0接着我们需要将指向元素值小的那个指针前移一步然后重复上面的步骤直到**resource = last**循环截止
**GIF动画演示**
![](../Animation/maxArea.gif)
**来看看代码**
```java
public int maxArea(int[] height) {
int resource = 0;
int last = height.length - 1;
int res = 0;
while (resource < last) {
if (height[resource] >= height[last]) {
res = Math.max(res, (last - resource) * height[last]);
last--;
} else {
res = Math.max(res, (last - resource) * height[resource]);
resource++;
}
}
return res;
}
```
**可以很明显的看到虽然内存消耗两者是差不多的但是双指针的速度比暴力解法的速度可是高出好多倍**
时间复杂度**O(n)** 空间复杂度**O(1)**
```
执行用时 :3 ms, 在所有 Java 提交中击败了92.69% 的用户
内存消耗 :40.3 MB, 在所有 Java 提交中击败了7.86%的用户
```
[视频演示](../Animation/maxArea.mp4)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,110 @@
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步个人博客https://www.zhangxiaoshuai.fun
本题在leetcode中题目序号994属于medium级别目前通过率为50.7%
**题目描述**
```
在给定的网格中每个单元格可以有以下三个值之一
值0代表空单元格
值1代表新鲜橘子
值2代表腐烂的橘子
每分钟任何与腐烂的橘子在4个正方向上相邻的新鲜橘子都会腐烂返回直到单元格中没有新鲜橘子为止所必须经过的最小分钟数如果不可能返回-1
示例1
输入[[2,1,1],[1,1,0],[0,1,1]]
输出4
示例2
输入[[2,1,1],[0,1,1],[1,0,1]]
输出-1
解释左下角的橘子第2行第0列永远不会腐烂因为腐烂只会发生在4个正向上
示例3
输入[[0,2]]
输出0
解释因为0分钟时已经没有新鲜橘子了所以答案就是0
提示
1<=grid.length<=10
1<=grid[0].length<=10
grid[i][j]仅为01或2
```
**由题意只有腐烂的橘子才可以去污染它周围四个方向上存在的新鲜橘子且它每一分钟只能污染一次下一次被它腐蚀的橘子再去腐蚀自己周边的新鲜橘子每次只有被新腐蚀的橘子才能继续向外腐蚀因为旧的腐烂的橘子已经被包围**
这就很像一个人得了传染病只要他遇见人就会将病传染给那个人而被传染的又会去感染别的人不同的是这里的橘子的位置是固定的无法移动
思路是非常简单的我们通过动态图直观理解下
![腐烂的橘子gif演示](../Animation/腐烂的橘子01.gif)
既然理清了思路那么我们来试试代码
首先我们需要知道初始状态下的单元格中有多少腐烂的橘子并且要将它们的位置信息保存下来我们可以用一个队列**先入先出**xy保存下来;然后我们开始遍历整个队列每次弹出一个保存的位置信息将这个位置周围的新鲜橘子全部腐蚀并且将被腐蚀的橘子的位置信息存入队列中在下次循环中从它们的位置上再**向外延伸**注意为了模拟同步我们需要将每次存入队列中的所有位置都要在下一次全部取出来直到队列为空循环结束这个时候并不能说明整个单元格中已经不存在新鲜的橘子因为可能存在下面这种情况
![](../Animation/example01.png)
很明显标红的区域新鲜橘子永远不能被腐蚀因为它周围唯一的两个单元格是空的
那么针对这种情况我们在前面遍历统计腐烂橘子的时候可以顺便统计一下新鲜橘子的数量count后面我们每腐蚀一个橘子就从count中减去1最终循环结束的时候我们只需要判断count是否大于0若是返回-1否则返回轮数res
------
**代码**
```java
public static int orangesRotting02(int[][] grid){
int row = grid.length,col = grid[0].length;
Queue<int[]> queue = new ArrayDeque();
int count = 0;//统计新鲜橘子的数量
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if (grid[i][j] == 2) {
queue.add(new int[]{i,j});
}
if (grid[i][j] == 1) {
count++;
}
}
}
int res = 0;
while (count > 0 && !queue.isEmpty()) {
res++;
int size = queue.size();
for (int i = 0; i < size; i++) {
int[] temp = queue.poll();
int r = temp[0],c = temp[1];//(x,y)
//
if (r > 0 && grid[r-1][c] == 1) {
grid[r-1][c] = 2;
count--;
queue.add(new int[]{r-1,c});
}
//
if (r < grid.length-1 && grid[r+1][c] == 1) {
grid[r+1][c] = 2;
count--;
queue.add(new int[]{r+1,c});
}
//
if (c > 0 && grid[r][c-1] == 1) {
grid[r][c-1] = 2;
count--;
queue.add(new int[]{r,c-1});
}
//
if (c < grid[0].length-1 && grid[r][c+1] == 1) {
grid[r][c+1] = 2;
count--;
queue.add(new int[]{r,c+1});
}
}
}
if (count > 0) {
return -1;
}
return res;
}
```