Skip to content

Commit

Permalink
修改
Browse files Browse the repository at this point in the history
  • Loading branch information
arkingc committed Jul 11, 2018
1 parent 52fc643 commit 106e88c
Show file tree
Hide file tree
Showing 2 changed files with 229 additions and 3 deletions.
Binary file added pic/leetcode-128-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
232 changes: 229 additions & 3 deletions 数据结构与算法/算法题总结.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@
- *删除*
+ Leetcode26:[删除排序数组中的重复项](#删除排序数组中的重复项)(`双指针` `easy`)
+ Leetcode27:[删除数组中值为val的元素](#删除数组中值为val的元素)(`双指针` `easy`)
- *连续子数组*
- *子数组与连续子数组*
+ 《剑指offer》面试题42:[连续子数组的最大和](#连续子数组的最大和)(`动态规划`)
+ Leetcode152:[连续子数组的最大积](#连续子数组的最大积)(`动态规划` `medium`)
+ Leetcode134:[加油站](#加油站)(`贪心` `medium`)
+ Leetcode128:[最长连续序列](#最长连续序列)(`哈希表` `hard`)
- *排列组合*
+ 《剑指offer》面试题38(相关题一):[正方体顶点上放数字](#正方体顶点上放数字)(`全排列`)
+ 《剑指offer》面试题38(相关题二):[八皇后](#八皇后)(`全排列`)
Expand Down Expand Up @@ -235,6 +237,7 @@
+ 《剑指offer》面试题13:[机器人的运动范围](#机器人的运动范围)(`DFS`)
+ Leetcode62:[左上角到右下角的路径数](#左上角到右下角的路径数)(`DFS` `动态规划` `medium`)
+ Leetcode130:[被包围的区域](#被包围的区域)(`DFS` `medium`)
+ Leetcode200:[岛屿的数量](#岛屿的数量)(`DFS` `easy`)
+ Leetcode695:[岛屿的最大面积](#岛屿的最大面积)(`DFS` `easy`)
+ Leetcode55:[跳步游戏](#跳步游戏)(`贪心` `medium`)
+ Leetcode45:[跳步游戏II](#跳步游戏ii)(`动态规划` `BFS` `hard`)
Expand Down Expand Up @@ -838,7 +841,7 @@ public:

## 数组中出现次数超过一半的数字

[OJ链接](https://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163?tpId=13&tqId=11181&tPage=2&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking)
OJ链接:[牛客](https://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163?tpId=13&tqId=11181&tPage=2&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking)、Leetcode([求众数](https://leetcode.com/problems/majority-element/description/))

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字

Expand Down Expand Up @@ -13199,4 +13202,227 @@ public:
```

<br>
<br>
<br>

## 最长连续序列

[OJ链接](https://leetcode.com/problems/longest-consecutive-sequence/description/)

给定一个未排序的整数数组,找出最长连续序列的长度

要求算法的时间复杂度为 O(n)

示例:

```
输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。
```

### 解答

#### 1)排序

先排序,排序完成后遍历一遍数组就能找出最长连续序列

```c++
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
sort(nums.begin(),nums.end());
int res = 0,sz = nums.size();
for(int i = 0;i < sz;i++){
int j = i,len = 1;
while(j + 1 < sz){
if(nums[j + 1] == nums[j] + 1) len++;
else if(nums[j + 1] != nums[j]) break;
j++;
}
if(len > res) res = len;
i = j; //j + 1已经不连续,所以i再++就到了第一个不连续的位置
}
return res;
}
};
```

* **时间复杂度**:O(nlogn)(accept,但不符合要求)
* **空间复杂度**:O(1)

#### 2)hash表

[参考](https://www.youtube.com/watch?v=rc2QdQ7U78I)

使用一个hash表,key表示数,value表示以key为边界的连续序列的长度,很显然,当插入一个数字num时:

* 如果num已经存在hash表中,那么以前已经处理过,那么忽略
* 否则,又分为几种情况:
- 如果num-1在hash表中,表明num刚好和num-1结尾的序列相连,因此组成一个新的最大连续序列,此时更新区间左边界和右边界(即num)hash表项的value,即最大连续序列的长度
- 如果num+1在hash表中,表明num刚好和num+1开头的序列相连,因此组成一个新的最大连续序列,此时更新区间左边界(即num)和右边界hash表项的value,即最大连续序列的长度
- 如果num-1和num+1都在hash表中,说明num将两个连续序列相连,因此更新左边区间左边界hash项的value,以及右区间右边界hash项的value

每次得到一个新的连续序列时,与结果判定,如果更大,那么更新结果。下图为[1,2,3,6,5,4]的示例:

<div align="center"> <img src="../pic/leetcode-128-1.png"/> </div>

* **时间复杂度**:O(n)
* **空间复杂度**:O(n)

<br>
<br>

## 加油站

[OJ链接](https://leetcode.com/problems/gas-station/description/)

在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。

你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。

如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1。

说明:

* 如果题目有解,该答案即为唯一答案。
* 输入数组均为非空数组,且长度相同。
* 输入数组中的元素均为非负数。

示例 1:

```
输入:
gas = [1,2,3,4,5]
cost = [3,4,5,1,2]

输出: 3

解释:
从 3 号加油站(索引为 3 处)出发,可获得 4 升汽油。此时油箱有 = 0 + 4 = 4 升汽油
开往 4 号加油站,此时油箱有 4 - 1 + 5 = 8 升汽油
开往 0 号加油站,此时油箱有 8 - 2 + 1 = 7 升汽油
开往 1 号加油站,此时油箱有 7 - 3 + 2 = 6 升汽油
开往 2 号加油站,此时油箱有 6 - 4 + 3 = 5 升汽油
开往 3 号加油站,你需要消耗 5 升汽油,正好足够你返回到 3 号加油站。
因此,3 可为起始索引。
```

示例 2:

```
输入:
gas = [2,3,4]
cost = [3,4,3]

输出: -1

解释:
你不能从 0 号或 1 号加油站出发,因为没有足够的汽油可以让你行驶到下一个加油站。
我们从 2 号加油站出发,可以获得 4 升汽油。 此时油箱有 = 0 + 4 = 4 升汽油
开往 0 号加油站,此时油箱有 4 - 3 + 2 = 3 升汽油
开往 1 号加油站,此时油箱有 3 - 3 + 3 = 3 升汽油
你无法返回 2 号加油站,因为返程需要消耗 4 升汽油,但是你的油箱只有 3 升汽油。
因此,无论怎样,你都不可能绕环路行驶一周。
```

### 解答

* 假如从位置`i`开始,`i+1,i+2...`,一路开过来一路油箱都没有空。说明什么?说明从`i`到`i+1,i+2,...`肯定是正积累。
* 现在突然发现开往位置`j`时油箱空了。这说明什么?说明从位置`i`开始没法走完全程(废话)。那么,我们要从位置`i+1`开始重新尝试吗?不需要!为什么?因为前面已经知道,位置`i`肯定是正积累,那么,如果从位置`i+1`开始走更加没法走完全程了,因为没有位置`i`的正积累了。同理,也不用从`i+2,i+3,...`开始尝试。所以我们可以放心地从位置`j+1`开始尝试

```c++
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int start = 0; //起始位置
int remain = 0; //当前剩余燃料
int debt = 0; //前面没能走完的路上欠的债

for(int i = 0;i < gas.size();i++){
remain += gas[i] - cost[i];
if(remain < 0){
start = i + 1;
debt += remain;
remain = 0;
}
}

return debt + remain >= 0 ? start : -1;
}
};
```

<br>
<br>

## 岛屿的数量

[OJ链接](https://leetcode.com/problems/number-of-islands/description/)

给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。

示例 1:

```
输入:
11110
11010
11000
00000

输出: 1
```

示例 2:

```
输入:
11000
11000
00100
00011

输出: 3
```

### 解答

如果遇到1,计数加1,使用DFS遍历,为了防止重复,在DFS遍历过程中将1改为非1的任意字符

```c++
class Solution {
public:
int numIslands(vector<vector<char>>& grid) {
int count = 0;
for(int row = 0;row < grid.size();row++){
for(int col = 0;col < grid[0].size();col++){
if(grid[row][col] == '1'){
count++;
dfs(grid,row,col);
}
}
}
/* 如果不想改动grid,可以将所有的'#'变回'1'
for(int row = 0;row < grid.size();row++){
for(int col = 0;col < grid[0].size();col++){
if(grid[row][col] == '#'){
grid[row][col] = '1';
}
}
}
*/
return count;
}

private:
void dfs(vector<vector<char>>& grid,int row,int col){
if(row < 0 || col < 0 || row >= grid.size() || col >= grid[0].size() || grid[row][col] != '1') return;
//没越界,并且为'1'
grid[row][col] = '#';
dfs(grid,row - 1,col);
dfs(grid,row + 1,col);
dfs(grid,row,col - 1);
dfs(grid,row,col + 1);
}
};
```

0 comments on commit 106e88c

Please sign in to comment.