ARTS计划2020/44

为了能够让自己保持一个比较积极的状态,我向《左耳听风》学习,决定制定一个计划,会在耗子叔的计划做一些适合我的修订。

Algorithm 编程训练和算法学习。
Review 可以选择一些英文文档或者实用的技术文档。
Tip 不限定技巧,某些场景的方法设计也是可以的。
Share 一篇日志,不限定类型。

时间分配也大概和他说的一样:

1
2
3
4
完成一个 ARTS 的时间不要超过 5 个小时,尽题控制在 2-3 个小时以内,少了你投入不够,多了难以坚持。
这 2-3 个小时的时间分配是,算法题 30-60 分钟,英文文章 30 分钟,Tip 回想一下本周工作中学到的一个小技巧(10 分钟),
Share 思考一个技术观点、社会热点、一个产品或是一个困惑(这个时间应该放在日常),然后花 30-60 分钟写下来。

除了Share部分,时间不限定之外,对于Tips,我也打算放在日常,不限定一个。

这是我进行的第一周

Algorithm-保龄球计分

本周参与了阿里的一个代码重构比赛,叫做83行代码,不是很难,我做到第2关,获得了一个鼠标垫。
第一关是用观察者模式来完成一个增加(或者减少、或者修改)分支逻辑对主体业务不影响的程序,观察者模式主要还是套公式,我提炼的公式如下:

抽象出被观察者接口,被观察者实现被观察对象的变化。
抽象出观察者接口,观察者实现观察到被观察者对象变化之后的相关处理逻辑。
被观察者实现添加观察者对象作为属性成员。并实现添加观察者、移除观察者这些基本功能。

根据上面三步走,很快就能够完成观察者模式。其实设计模式就是使用抽象、接口、实现、继承这些东西来编码,只是有人总结了这样编码的经验供大家学习参考而已。

第二关主要是一个保龄球计分的问题,这个理解透规则就可以写出来。(并不难,我只是收获了如何如何打保龄球计分这个规则

1
2
3
4
5
6
7
8
保龄球的计分规则:
1. 每一局总共有十轮。
2. 每一轮共有十支球瓶,最多可以投两球,要尽量在两球之内把球瓶全部击倒。
3. 如果第一球就把全部的球瓶都击倒了,也就是“STRIKE”,本轮完成。 STRIKE的得分是10分再加奖励分,奖励分为后面两球的倒瓶数。
4. 如果第一球没有全倒时,就要再打一球,如果剩下的球瓶全都击倒,也就是“SPARE”。 SPARE所得分数为10分再加奖励分,奖励分为后面一球的倒瓶数。
5. 如果第二球也没有把球瓶全部击倒,分数就是第一球加第二球倒的瓶数。
6. 如果到第10轮,如果第10轮为STRIKE或SPARE时,可以分别继续击球2次或1次, 该额外的击球仅用于奖励分的计数。
7. 全部十轮的得分相加就等于这一局的总得分。

实现如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package bowling;

/**
* 保龄球积分规则
* @author HaiziGe
*/
public class Bowling {
/**
* 用来存放投掷击倒的数目 最多才21个
*/
private final int[] rolls = new int[21];
/**
* 数组下标
*/
private int rollsIndex = 0;
/**
* 记录当前是第几轮
*/
private int round = 0;
/**
* 判断是不是本轮第一次
*/
private boolean firstThrow = true;

/**
* 打出STRIKE 或者 SPARE
*/
private final int ALL_PINS = 10;

/**
* firstThrow 默认为真由规则可以知道第一球如果全中就进入下一轮了,
* 因此首先判断添加的是不是为10,round,
* 不是就把firstThrow改为false,第二次调用add的时候firstThrow为false,
* 然后本轮结束,round,将firstThrow改为true
* @param n 倒的瓶数
*/
public void roll(int n) {
//添加分数 将分数添加到数组中
rolls[rollsIndex++] = n;
if (!firstThrow) {
firstThrow = true;
round++;
} else if (n == ALL_PINS) {
round++;
} else{
firstThrow = false;
}
round = round > ALL_PINS ? ALL_PINS : round;
}

/**
* 当前轮的计算方法循环当前轮的次数
* a[0]赋值第一次击球firstThrow 然后下标自增一;判断第一次都不是击倒了10个
* 规则 保龄球一轮两个球 第一个全中就是之前的分数+10+后面两次投掷的分数
* 补中 两次一共击倒10个 之前的分数加两次击倒的10分加后面一次的的分数
*
* @return 总分
*/
public int getScore() {
int score = 0;
int ball = 0;
for(int i = 0; i < round; i++) {
int firstThrow = rolls[ball++];
if(firstThrow == ALL_PINS) {
score = score + ALL_PINS + rolls[ball] + rolls[ball+1];
} else {
int secondThrow = rolls[ball++];
score = score + (firstThrow + secondThrow == ALL_PINS ? ALL_PINS + rolls[ball] : firstThrow + secondThrow);
}
}
return score;
}

}

第三关是德州扑克,规则复杂,也是要求重构,我连规则都看不太懂,这种牌类的博弈游戏我永远都搞不清楚,要做这个题目估计要很长时间我才能理解规则,然后完成重构编码,最后我放弃了。/(ㄒoㄒ)/~~

Review-redis的过期通知

本周阅读 Redis官方文档 Redis Keyspace Notifications

公司不知道是谁引入了这种使用方式,我也没用过,看起来好像使用的范围还挺广的,不知道性能和效率如何。

Tip-list+stream

本周学了list+stream的一些操作,主要是list进行groupby的操作。

简单分组

1
Map<String, List<EntryDeliveryDetailywk>> detailsMap = dtos1.stream().collect(Collectors.groupingBy(EntryDeliveryDetailywk::getskuId));

复杂分组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Person {
private Integer category;

public Integer groupByCategoryInEntity()
if (category == 0) {
return 0;
} else if (category == 3 || category == 4) {
return 1;
} else {
return 2;
}
}
}

private Integer groupByCategoryInService(Person p) {
if (p.getCategory() == 0) {
return 0;
} else if (p.getCategory() == 3 || p.getCategory() == 4) {
return 1;
} else {
return 2;
}
}

// 这样用复杂分类,只要改造groupByCategory即可
Map<Integer, List<Person>> map1 = people.collect(Collectors.groupingBy(Person::groupByCategoryInEntity));
// 或者这样写也行 (其实更推荐,因为分组逻辑通常是服务层干的事和数据模型关系不大)
Map<Integer, List<Person>> map2 = people.collect(Collectors.groupingBy(p -> groupByCategoryInService(p)));

// 分组结构的相关业务逻辑
teacherList = map1.get(0);
studentList = map1.get(1);
otherList = map1.get(2);

Share-程序员数学

本周日常是在看《程序员数学课》这门课程,近期都会看这个,会更新大概几篇博客出来,作为我的读书笔记来分享。

PS. 我希望我能最少坚持一季度这个,一季度应该是能坚持的。