Skip to content

Commit 4b09f64

Browse files
Merge pull request algorithm001#709 from yanlingli3799/master
第四周作业,李颜翎
2 parents 693be2d + 2471dc7 commit 4b09f64

8 files changed

Lines changed: 270 additions & 1 deletion

File tree

Week_03/id_118/NOTE.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,30 @@
1-
# 学习笔记
1+
# 学习笔记
2+
3+
这周的学习分两部分:
4+
- 专栏,集中在单模式字符串匹配算法。
5+
- 算法,集中做了几道“图”相关的题。
6+
7+
还是用 xmind 结合手绘图来做学习总结的,不过又有了些新的感受。
8+
9+
---
10+
11+
在看字符串匹配算法的时候,有一些点不太想的明白,以BM算法为例:
12+
- 为什么坏字符位移数可能为负?
13+
- 好后缀与模式串的多个子串匹配时,选哪一个?
14+
- 为什么必须是完整子串匹配,或模式串的前缀子串与好后缀的后缀子串匹配,其他子串不行吗?
15+
16+
遇到这些问题的时候,可以通过举例子的方式辅助思考。
17+
18+
附上我在学习过程中画的图例,和整理的总结:
19+
- 图例:https://github.com/yanlingli3799/algorithm/blob/master/Week_03/id_118/src/%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%8C%B9%E9%85%8D-%E5%9B%BE%E4%BE%8B.pdf
20+
- 小结:https://github.com/yanlingli3799/algorithm/blob/master/Week_03/id_118/src/%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%8C%B9%E9%85%8D-%E6%80%9D%E7%BB%B4%E5%AF%BC%E5%9B%BE.pdf
21+
22+
23+
----
24+
25+
做题的时候,挑的几个图做的,其他的难度都不大,稍微转化一下就好。
26+
928比较麻烦,费了好大力气才理解和 924 啥区别。
27+
整理思路的时候,还是画了一些图例,个人感觉还是比较有用的。目前使用bfs暴力搜索算出来的,时间复杂度比较高,提交有的时候甚至会报超时。
28+
29+
附928图例草稿:https://github.com/yanlingli3799/algorithm/blob/master/Week_03/id_118/src/928%E8%8D%89%E7%A8%BF.pdf
30+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/
2+
// 121.买卖股票的最佳时机
3+
// 思路:其实就是求某个时间点左边的最小值和右边的最大值之差的最大值。
4+
class Solution {
5+
public int maxProfit(int[] prices) {
6+
if(prices.length <=0){
7+
return 0;
8+
}
9+
10+
int minPrice = prices[0];
11+
int maxProfit = 0;
12+
13+
for(int i=1;i<prices.length;i++){
14+
// 若今天价格高于前面几天的最低价格,则可以卖出。
15+
// 此时,计算今天卖出利润多少,是否比已计算的利润更高
16+
if(prices[i]>minPrice && maxProfit<(prices[i]-minPrice)){
17+
maxProfit = prices[i]-minPrice;
18+
}
19+
20+
// 若今天价格低于前几天的最低价格,则更新最低价格
21+
if(prices[i]<minPrice){
22+
minPrice = prices[i];
23+
}
24+
}
25+
return maxProfit;
26+
}
27+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
2+
// 122.买卖股票的最佳时机2
3+
// 和 121 不一样的是,121 要求买买一次获得最大利润,122 要求多次买卖,获得最大利润,且不可以同时参与多笔交易
4+
// 这样问题可以拆解为多个区间找最大差值的问题
5+
// 由于可以多次买卖,所以我们只需要找到所有的独立的“单调递增区间”,然后计算其差值之和即可。
6+
class Solution {
7+
public int maxProfit(int[] prices) {
8+
9+
int totalProfit = 0;
10+
11+
// 1. 数组为空,或只有一个元素,则最大利润为0
12+
if(prices.length<=1){
13+
return 0;
14+
}
15+
16+
int partLeft = prices[0];
17+
int partRight = prices[0];
18+
19+
// 2. 从1开始,寻找并累加单调区间左右差值
20+
for(int i=1;i<prices.length;i++){
21+
if(prices[i]>partRight){
22+
partRight = prices[i];
23+
}
24+
if(prices[i]<partRight){
25+
totalProfit += (partRight-partLeft);
26+
partLeft = prices[i];
27+
partRight = prices[i];
28+
}
29+
}
30+
31+
// 3. 最后一个小区间
32+
if(partLeft!=partRight){
33+
totalProfit += (partRight-partLeft);
34+
}
35+
36+
return totalProfit;
37+
}
38+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/
2+
// 123.买卖股票的最佳时机3
3+
// 是在 122 的基础上,加了限制条件,不能对所有值做累加,只能取最大的两个求和
4+
class Solution {
5+
public int maxProfit(int[] prices) {
6+
7+
ArrayList<Integer> profit = new ArrayList();
8+
9+
// 1. 数组为空,或只有一个元素,则最大利润为0
10+
if(prices.length<=1){
11+
return 0;
12+
}
13+
14+
int totalMaxProfit = 0;
15+
16+
//
17+
for(int i=1;i<prices.length;i++){
18+
// 左侧闭区间:[0,i]
19+
// 右侧闭区间:[i+1,length-1]
20+
int leftMaxProfit = maxProfit(prices,0,i);
21+
int rightMaxProfit = maxProfit(prices,i+1,prices.length-1);
22+
if(leftMaxProfit+rightMaxProfit >totalProfit){
23+
totalProfit = leftMaxProfit+rightMaxProfit;
24+
}
25+
}
26+
27+
return totalProfit;
28+
}
29+
30+
31+
// 求闭区间 [from,to] 做一笔交易的最大值。
32+
int maxProfit(int[] prices,int from,int to){
33+
if(from>=to){
34+
return 0;
35+
}
36+
if(from+1==to){
37+
return prices[to]-prices[from]>0?prices[to]-prices[from]:0;
38+
}
39+
40+
int minPrice = prices[from];
41+
int maxProfit = 0;
42+
for(int i=from+1;i<prices.length && i<=to;i++){
43+
// 若今天价格高于前面几天的最低价格,则可以卖出。
44+
// 此时,计算今天卖出利润多少,是否比已计算的利润更高
45+
if(prices[i]>minPrice && maxProfit<(prices[i]-minPrice)){
46+
maxProfit = prices[i]-minPrice;
47+
}
48+
49+
// 若今天价格低于前几天的最低价格,则更新最低价格
50+
if(prices[i]<minPrice){
51+
minPrice = prices[i];
52+
}
53+
}
54+
55+
return maxProfit;
56+
}
57+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// https://leetcode-cn.com/problems/assign-cookies/
2+
// 455.分发饼干
3+
// 解法:每次选一个胃口最小的孩子,给尺寸最小的饼干
4+
class Solution {
5+
public int findContentChildren(int[] g, int[] s) {
6+
7+
// 分别排序
8+
Arrays.sort(g);
9+
Arrays.sort(s);
10+
11+
int i=0;
12+
int lastMatchIndex = -1;
13+
14+
// 对每一个孩子 i ,从 s 里找第一个比它大的 j,能满足 s[j]>=g[i](尺寸>=胃口)。
15+
// 若某个孩子 i 找不到比它大的 j,则终止,后面的孩子也一定得不到满足
16+
for(i=0;i<g.length;i++){
17+
boolean found = false;
18+
for(int j=lastMatchIndex+1;j<s.length;j++){
19+
if(s[j]>=g[i]){
20+
lastMatchIndex = j;
21+
found=true;
22+
break;
23+
}
24+
}
25+
if(found==false){
26+
break;
27+
}
28+
}
29+
30+
return i;
31+
}
32+
33+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// https://leetcode-cn.com/problems/longest-word-in-dictionary/
2+
// 720.词典中最长的单词
3+
// 解题思路:构建Trie树,对每个单词的末尾做标记;然后扫描Trie树,找出最长单词
4+
// - 为了快速计算单词,对Trie树做个小小的变形,每个节点存储的不是一个字符,而是到当前节点为止的字串
5+
// - 这样,可以使用层次遍历,找出最长单词
6+
// - 若出现多个最长单词,第一个遇到的就是字典序最前的
7+
8+
class Solution {
9+
10+
// 定义一个内部类
11+
class TrieNode{
12+
String data;// 以当前字符结尾的字符串
13+
boolean isEndingChar;// 用来标识当前节点是否为某个单词的终点。
14+
TrieNode[] children;
15+
TrieNode(String data){
16+
this.data = data;
17+
this.children = new TrieNode[26];
18+
}
19+
}
20+
21+
// 向Trie树中插入一个单词
22+
void insertToTrie(TrieNode root,String word){
23+
TrieNode tmp = root;
24+
25+
// 遍历单词的每一个字符
26+
for(int i=0;i<word.length();i++){
27+
// 取字符,并计算索引
28+
char c = word.charAt(i);
29+
int index = c-'a';
30+
String data = word.substring(0,i+1);
31+
// 查看当前根节点对应索引位置是否为null,若为null,则new 一个新节点,插入
32+
if(tmp.children[index] == null){
33+
TrieNode newNode = new TrieNode(data);
34+
tmp.children[index] = newNode;
35+
}
36+
tmp = tmp.children[index];
37+
}
38+
// 最后一个单词,标记
39+
tmp.isEndingChar = true;
40+
}
41+
42+
// 构建 Trie 树
43+
void buildTrie(TrieNode root,String[] words){
44+
for(int i=0;i<words.length;i++){
45+
insertToTrie(root,words[i]);
46+
}
47+
}
48+
49+
50+
51+
52+
public String longestWord(String[] words) {
53+
TrieNode root = new TrieNode("");
54+
buildTrie(root,words);
55+
56+
String longestWord = "";
57+
Queue<TrieNode> queue = new LinkedList<TrieNode>();
58+
59+
// 先遍历第一层子节点,初始化Queue。
60+
for(int i=0;i<26;i++){
61+
if(root.children[i]!=null && root.children[i].isEndingChar==true){
62+
queue.offer(root.children[i]);
63+
if(longestWord.length() < root.children[i].data.length()){
64+
longestWord = root.children[i].data;
65+
}
66+
}
67+
}
68+
69+
// 层次遍历,每次从队列中取出一个节点来,向下遍历
70+
while(queue.size()!=0){
71+
TrieNode node = queue.poll();
72+
for(int i=0;i<26;i++){
73+
if(node.children[i]!=null && node.children[i].isEndingChar==true){
74+
queue.offer(node.children[i]);
75+
if(longestWord.length() < node.children[i].data.length()){
76+
longestWord = node.children[i].data;
77+
}
78+
}
79+
}
80+
}
81+
82+
return longestWord;
83+
}
84+
85+
}
3.44 MB
Binary file not shown.
267 KB
Binary file not shown.

0 commit comments

Comments
 (0)