Skip to content

Commit 618a0f1

Browse files
authored
Merge pull request gzc426#15 from gzc426/master
12.25
2 parents 0259a3e + 3030584 commit 618a0f1

File tree

9 files changed

+435
-0
lines changed

9 files changed

+435
-0
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#### [452. Minimum Number of Arrows to Burst Balloons](https://leetcode.com/problems/minimum-number-of-arrows-to-burst-balloons/)
2+
**题目描述**
3+
> 在二维空间有许多球形气球。对每个气球,输入是**水平方向**上气球直径的**开始和结束坐标**(开始坐标总是小于结束坐标)。
4+
5+
> 记一个气球直径的开始和结束坐标为 xstart,xend。在坐标x处射出一支箭,若 xstart ≤ x ≤ xend,则该气球会被引爆。
6+
可以射出的弓箭的数量没有限制。 弓箭一旦被射出之后,可以无限地前进。
7+
求所需弓箭的最小数量,使所有气球都被引爆。
8+
9+
**例子**
10+
> Input: [[10,16], [2,8], [1,6], [7,12]]
11+
Output: 2
12+
**Explanation:**
13+
One way is to shoot one arrow for example at x = 6 (bursting the balloons [2,8] and [1,6]) and another arrow at x = 11 (bursting the other two balloons).
14+
15+
**思想**
16+
和重叠区间有关~
17+
首先区间按start排序;依次遍历区间,若两区间重叠,记录重叠区域;然后判断下一个区间是否和该重叠区域重合。若重合,继续记录重叠区域;否则弓箭数+1。
18+
(改进)
19+
按end排序
20+
21+
**解法**
22+
```python
23+
class Solution(object):
24+
def findMinArrowShots(self, points):
25+
"""
26+
:type points: List[List[int]]
27+
:rtype: int
28+
"""
29+
if not points:
30+
return 0
31+
32+
cnt = 1
33+
points = sorted(points, key = lambda x:x[0])
34+
end = points[0][1]
35+
for point in points[1:]:
36+
if end >= point[0]: # overlap
37+
end = min(end, point[1])
38+
else:
39+
end = point[1]
40+
cnt += 1
41+
return cnt
42+
```
43+
改进:按end排序
44+
```python
45+
class Solution(object):
46+
def findMinArrowShots(self, points):
47+
"""
48+
:type points: List[List[int]]
49+
:rtype: int
50+
"""
51+
points = sorted(points, key = lambda x:x[1])
52+
cnt = 0
53+
end = float('-inf')
54+
for point in points:
55+
if point[0] > end: # non-overlap
56+
cnt += 1
57+
end = point[1]
58+
return cnt
59+
```
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
## 406_(根据身高重建队列)Queue Reconstruction by Height
2+
## 1 问题描述、输入输出与样例
3+
### 1.1 问题描述
4+
假设有打乱顺序的一群人站成一个队列。 每个人由一个整数对(h, k)表示,其中h是这个人的身高,k是排在这个人前面且身高大于或等于h的人数。 编写一个算法来重建这个队列。
5+
6+
__注意__
7+
总人数少于1100人。
8+
### 1.2 输入与输出
9+
输入:
10+
* vector<pair<int, int>>& people: 长度可变的结构体数组的引用 people
11+
12+
输出:
13+
* vector<pair<int, int>>: 重建之后的长度可变结构体数组
14+
### 1.3 样例
15+
#### 1.3.1 样例1
16+
输入:[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]<br>
17+
输出:[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
18+
19+
## 2 思路描述与代码
20+
### 2.1 思路描述(排序重建法)
21+
1. 按身高 h 从大到小排列,身高相等按 k 从小到大排序
22+
2. 按照规则(当前(h, k)插入的位置为第 k 个元素)重建队列
23+
24+
25+
比如输入:people = [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
26+
1. 排序后people = [[7,0], [7,1], [6,1], [5,0], [5,2], [4,4]]
27+
2. 按照规则(当前(h, k)插入的位置为第 k 个元素)重建队列
28+
* [7,0]插入第 0 个位置,有 ans = [[7,0]];
29+
* [7,1]插入第 1 个位置,有 ans = [[7,0], [7,1]];
30+
* [6,1]插入第 1 个位置,有 ans = [[7,0], [6,1], [7,1]];
31+
* [5,0]插入第 0 个位置,有 ans = [[5,0], [7,0], [6,1], [7,1]];
32+
* [5,2]插入第 2 个位置,有 ans = [[5,0], [7,0], [5,2], [6,1], [7,1]];
33+
* [4,4]插入第 4 个位置,有 ans = [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]];
34+
35+
### 2.2 代码
36+
```cpp
37+
//函数中涉及到的c++知识
38+
//pair<int, int> 可以理解为包含两个元素的结构体
39+
//vector<pair<int, int>> 是个长度可变的结构体数组,c++里面称为容器
40+
//ret_func_type func(vector<pair<int, int>>& name) 中的name是vector<pair<int, int>>容器的引用,可以理解为传入一个指针
41+
//sort(g.begin(), g.end(), cmp) 对容器g的结构体按照cmp的排序规则排序,容器的起始数据的指针是 g.begin(),容器的末尾数据的指针是g.end()
42+
43+
//1. 按身高 h 从大到小排列,身高相等按 k 从小到大排序
44+
//2. 重建队列
45+
vector<pair<int, int>> reconstructQueue(vector<pair<int, int>>& people) {
46+
int len = people.size();
47+
vector<pair<int, int>> ans;
48+
//1. 按身高 h 从大到小排列,身高相等按 k 从小到大排序
49+
sort(people.begin(), people.end(), cmp);
50+
//2. 重建队列
51+
for( int i = 0; i < len; i++ ){
52+
ans.insert(ans.begin() + people[i].second, people[i]);
53+
}
54+
return ans;
55+
}
56+
//按身高 h 从大到小排列,身高相等按 k 从小到大排序
57+
static bool cmp(const pair<int, int>& data1, const pair<int, int>& data2){
58+
return data1.first != data2.first ? data1.first > data2.first : data1.second < data2.second;
59+
}
60+
```
61+
## 3 思考与拓展
62+
### 3.1 思考
63+
本题按照排序规则排序后,很容易找到重排后应插入的位置。
64+
#### 3.1.1 其他方法
65+
#### 3.1.1.1 排序+BIT(二分索引树)
66+
1. 按照以 h 从小到达, h 相同以 k 从小到达排序
67+
2. 遍历排序后的结构体数组,借助BIT(二分索引树)可以在O(logn)时间内找到未用的第 k 个位置。
68+
69+
比如输入:people = [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
70+
1. 排序后people = [[4,4], [5,0], [5,2], [6,1], [7,0], [7,1]]
71+
2. 按照规则(当前(h, k)插入的位置为第 k 个可用元素)重建队列
72+
* pos = [1,1,1,1,1,1], [4,4]插入第 4 + 1 个可用位置,有pos = [1,1,1,1,0,1], ans = [[-1,-1],[-1,-1],[-1,-1],[-1,-1],[4,4],[-1,-1]];
73+
* pos = [1,1,1,1,0,1], [5,0]插入第 0 + 1 个可用位置,有pos = [0,1,1,1,0,1], ans = [[5,0],[-1,-1],[-1,-1],[-1,-1],[4,4],[-1,-1]];
74+
* pos = [0,1,1,1,0,1], [5,2]插入第 2 - 1 + 1 个可用位置(相同元素需要减掉),有pos = [0,1,0,1,0,1], ans = [[5,0],[-1,-1],[5,2],[-1,-1],[4,4],[-1,-1]];
75+
* pos = [0,1,0,1,0,1], [6,1]插入第 1 + 1 个可用位置,有pos = [0,0,1,0,0,1], ans = [[5,0],[-1,-1],[5,2],[6,1],[4,4],[-1,-1]];
76+
* pos = [0,0,1,0,0,1], [7,0]插入第 0 + 1 个可用位置,有pos = [0,0,0,0,0,1], ans = [[5,0],[7,0],[5,2],[6,1],[4,4],[-1,-1]];
77+
* pos = [0,0,0,0,0,1], [7,1]插入第 0 + 1 个可用位置,有pos = [0,0,0,0,0,0], ans = [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
78+
79+
80+
#### 3.1.2 复杂度分析
81+
方法|空间复杂度|时间复杂度
82+
--- | --- | ---
83+
排序重建法|O(1)|平均O(nlogn),最差O(n^2)
84+
排序+BIT(二分索引树)|O(n)|O(nlogn)
85+
#### 3.1.3 难点分析
86+
1. 找到合理的排序规则;
87+
2. 根据合理的规则对排序后的结构体数组重建
88+
89+
### 3.2 拓展
90+
如果让你实现BIT(二分索引树)呢?
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#### [406. Queue Reconstruction by Height](https://leetcode.com/problems/queue-reconstruction-by-height/)
2+
**题目描述**
3+
> 假设有打乱顺序的一群人站成一个队列。
4+
每人用一个整数对(h, k)表示,其中h是这个人的身高,k是排在这个人前面即身高≥h的人数。
5+
编写一个算法来重建这个队列。
6+
7+
**例子**
8+
> Input: [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
9+
Output: [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
10+
11+
**思想**
12+
**要点**是排序方式。
13+
1)按照h降序,k升序的方式排列。例子为[[7,0], [7,1], [6,1], [5,0], [5,2], [4,4]]
14+
2)首先[7,0], [7,1]正确;对于[6,1]要求前面有一个比它高的,所以在idx=1插入[6,1];对于[5,0],要求前面有没有比它高的,所以在idx=0插入[5,0]...
15+
16+
**解法**
17+
```python
18+
class Solution(object):
19+
def reconstructQueue(self, people):
20+
"""
21+
:type people: List[List[int]]
22+
:rtype: List[List[int]]
23+
"""
24+
res = []
25+
people = sorted(people, key = lambda(h, k):(-h, k))
26+
for p in people:
27+
res.insert(p[1], p)
28+
return res
29+
```
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
## 392_(判断子序列)Is Subsequence
2+
## 1 问题描述、输入输出与样例
3+
### 1.1 问题描述
4+
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。<br>
5+
你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。<br>
6+
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。
7+
8+
__后续挑战__ :<br>
9+
如果有大量输入的 S,称作S1, S2, ... , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?
10+
11+
### 1.2 输入与输出
12+
输入:
13+
* string s:给定的字符串 s
14+
* string t:给定的字符串 t
15+
16+
输出:
17+
* bool:判断 s 是否为 t 的子序列
18+
### 1.3 样例
19+
#### 1.3.1 样例1
20+
输入: s = "abc", t = "ahbgdc"<br>
21+
输出: true
22+
#### 1.3.2 样例2
23+
输入: s = "axc", t = "ahbgdc"<br>
24+
输出: false
25+
## 2 思路描述与代码
26+
### 2.1 思路描述(双下标法)
27+
i为字符 s 的遍历下标, j 表示字符 t 的遍历下标
28+
```cpp
29+
for( j = 0; j < len_t; j++ ){
30+
if(s[i] == t[j]){
31+
if(i == len_s - 1) return true;
32+
else i++;
33+
}
34+
}
35+
```
36+
比如输入: s = "abc", t = "ahbgdc";<br>
37+
j = 0, i = 0, s[0] == t[0], i = 1; <br>
38+
j = 1, i = 1, s[1] != t[1]; <br>
39+
j = 2, i = 1, s[1] == t[2], i = 2; <br>
40+
j = 3, i = 2, s[1] != t[3]; <br>
41+
j = 4, i = 2, s[2] != t[4]; <br>
42+
j = 5, i = 2, s[2] == t[5], 返回true;
43+
### 2.2 代码
44+
```cpp
45+
bool isSubsequence(string s, string t) {
46+
int len_s = s.size();
47+
int len_t = t.size();
48+
//边界情况
49+
if(len_s > len_t) return false;
50+
else if(len_s == 0) return true;
51+
52+
//遍历t
53+
int i = 0, j = 0;
54+
for( j = 0; j < len_t; j++ ){
55+
//如果当前字符相等,查找 s 的下一个字符是否在 t 中
56+
if(s[i] == t[j]){
57+
if(i == len_s - 1) return true;
58+
else i++;
59+
}
60+
}
61+
return false;
62+
}
63+
```
64+
## 3 思考与拓展
65+
### 3.1 思考
66+
本题按照子序列的定义并利用双下标法可以很容易解决。
67+
#### 3.1.1 其他方法
68+
无。
69+
#### 3.1.2 复杂度分析
70+
方法|空间复杂度|时间复杂度
71+
--- | --- | ---
72+
双下标法|O(1)|O(s_len+t_len)
73+
#### 3.1.3 难点分析
74+
1. i下标的更新。
75+
76+
### 3.2 拓展
77+
如果给你的是数组数据呢?
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
```
2+
class Solution {
3+
public:
4+
bool isSubsequence(string s, string t) {
5+
int ls = s.length();
6+
int lt = t.length();
7+
int i =0; int j = 0;
8+
for(; i!=ls&&j!=lt;){
9+
if(s[i]==t[j]){
10+
i++;
11+
j++;
12+
}else{
13+
j++;
14+
}
15+
}
16+
if(i==ls) return true;
17+
else return false;
18+
}
19+
};
20+
```

2018.12.23-leetcode392/WYJ.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
```java
2+
class Solution {
3+
public boolean isSubsequence(String s, String t) {
4+
if(s.length() == 0){
5+
return true;
6+
}
7+
int indexS = 0, indexT = 0;
8+
while(indexT < t.length()){
9+
if(t.charAt(indexT) == s.charAt(indexS)){
10+
indexS++;
11+
}
12+
indexT++;
13+
if(indexS == s.length()){
14+
return true;
15+
}
16+
}
17+
return false;
18+
}
19+
}
20+
```
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
## 665_(非递减数列)Non-decreasing Array
2+
## 1 问题描述、输入输出与样例
3+
### 1.1 问题描述
4+
给定一个长度为 n 的整数数组,你的任务是判断在最多改变 1 个元素的情况下,该数组能否变成一个非递减数列。<br>
5+
我们是这样定义一个非递减数列的: 对于数组中所有的 i (1 <= i < n),满足 array[i] <= array[i + 1]。<br>
6+
__说明__: <br>
7+
n 的范围为 [1, 10,000]
8+
### 1.2 输入与输出
9+
输入:
10+
* vector<int>& nums:输入的整数数组
11+
12+
输出:
13+
* bool:在最多改变 1 个元素的情况下,该数组能否变成一个非递减数列
14+
### 1.3 样例
15+
#### 1.3.1 样例1
16+
输入: [4,2,3]<br>
17+
输出: True<br>
18+
解释: 你可以通过把第一个4变成1来使得它成为一个非递减数列。
19+
#### 1.3.2 样例2
20+
输入: [4,2,1]<br>
21+
输出: False<br>
22+
解释: 你不能在只改变一个元素的情况下将其变为非递减数列。
23+
## 2 思路描述与代码
24+
### 2.1 思路描述(比较计数法)
25+
cnt统计当前数比前一个数小的个数;
26+
遍历数组中所有的值
27+
* 如果当前值比前一个值小
28+
* 如果cnt == 1,则判断是否存在纠正的方式,无则返回false
29+
* 否则cnt >= 2,则不存在纠正方式,返回false
30+
### 2.2 代码
31+
```cpp
32+
bool checkPossibility(vector<int>& nums) {
33+
int n = nums.size();
34+
int cnt = 0;
35+
for (int i = 1; i < n; i++) {
36+
if (nums[i - 1] > nums[i]) {
37+
cnt++;
38+
//cnt = 1时,需要注意有两种情况可以补救:
39+
//1. 比如[-1 4 2 3], 4 < 2, 2 > -1, 通过修改 4 为 -1~2 间的数都可以补救
40+
//2. 比如[1 2 -1 3],-1 < 2, 2 < 3, 通过修改 -1 为 2~3 间的数都可以补救
41+
42+
//cnt >= 2则怎样都不行了,因为只能修改一次
43+
if((cnt == 1 && i >= 2 && i < n - 1 && nums[i] < nums[i - 2] && nums[i + 1] < nums[i - 1]) || cnt >= 2) return false;
44+
}
45+
}
46+
return true;
47+
}
48+
```
49+
## 3 思考与拓展
50+
### 3.1 思考
51+
本题中需要考虑多种情况的可能性,否则容易犯错。
52+
#### 3.1.1 其他方法
53+
无。
54+
#### 3.1.2 复杂度分析
55+
方法|空间复杂度|时间复杂度
56+
--- | --- | ---
57+
比较计数法|O(1)|O(n)
58+
#### 3.1.3 难点分析
59+
1. 当前值比前一个值小只出现一次时需要考虑[-1 4 2 3]、[1 2 -1 3]、[1,2,3,2]、[4,1,2,3]之类可纠正的情况
60+
61+
### 3.2 拓展
62+
如果给你的是链表数据呢?

0 commit comments

Comments
 (0)