最近算法题倒是一天有写一道,不过总是无法抓住很好的review 和tip 来写,所以感觉写ARTS的时间总是耽搁又耽搁,比一起的间隔时间也长了好几天。
Algorithm
LeetCode Count and Say,简单。 这题算是比较印象深刻的一题,最开始这一题的题目都没有看清楚,不知道这是什么意思。后面才明白,是后一个数去say 前一个数,得到后一个数之后继续。这样其实就可以算是一种递归了。因为我们知道了递归因子,和边界点。
Description
The count-and-say sequence is the sequence of integers with the first five terms as following:
1. 1
2. 11
3. 21
4. 1211
5. 111221
1 is read off as "one 1" or 11.
11 is read off as "two 1s" or 21.
21 is read off as "one 2, then one 1" or 1211.
Given an integer n, generate the nth term of the count-and-say sequence.
Note: Each term of the sequence of integers will be represented as a string. Example 1:
Input: 1
Output: "1"
Example 2:
Input: 4
Output: "1211"
Input Constraints:
1 <= n <= 30
solution
我们知道,要计算$n$个数,就需要计算第$n-1$个数,最后从第1个数开始推导。
public String countAndSay(int n) {
if (n == 1) return "1";
String s = countAndSay(n-1);
//用来存这个可变字串
StringBuilder sb = new StringBuilder();
char say = s.charAt(0);
int cnt = 1;
for (int i = 1; i < s.length(); i++){
char c = s.charAt(i);
if (c == say){
//如果前一个数和当前要读的一样,计数加一
cnt ++;
}else {
//否则,字串就连接次数和前一个数
sb.append(cnt).append(say);
say = c;
cnt = 1;
}
}
//最后一个数就会跳出,所以得加上最后循环的say 和cnt
sb.append(cnt).append(say);
return sb.toString();
}
test
@Test
public void countAndSay() {
CountAndSay solution = new CountAndSay();
assertEquals("1",solution.countAndSay(1));
assertEquals("1211",solution.countAndSay(4));
}
Review
刚好本周学习了一些Kafka方面的知识,顺便看到这篇文章,所以这周就用这篇文章来作为Review好了。 Thorough Introduction to Apache Kafka™ 这篇文章彻底深入的分析了Kafka是什么,它的好处,和它各个基础部分(producer,broker,consumer,topic,stream processor)。 我们先来看看它总结出来的一句对Kafka的描述:
stripped down to its core, Kafka is a distributed, horizontally-scalable, fault-tolerant, commit log.
先介绍了它的这几个特点:distributed(分布式)、horizontally-scalable(水平可扩展性)、fault-tolerant(容错性)、commit log(提交日志)。
distributed
可以让Kafka在多台机器上部署集群,提供一个结节(Leader)给用户去使用。这其实也保障了他的后面一个特性,fault-tolerant。关于分布式,作者引用了它自己的另一篇专门写分布式的文章,我也把这篇文章放在我的分享部分。
horizontally-scalable
有水平的扩展性,自然相对就是垂直的扩展性。而垂直的扩展性就是硬件方面的,提高CPU,RAM,SSD等方面的资源。 但是这确确实实是有限的,局限于现有的科技、物理水平,垂直的扩展是有限制的。而且这种扩展是需要时间的,它可能需要你把当前的服务暂停然后去扩容,去更换更好的CPU等等,这对大公司是无法忍受的。
而水平的扩展,添加一台新的机器,把新机器加入你的集群之中。这就方便很多了。但是又不是所有的系统,项目都是支持这种水平扩容的,这就是Kafka的特性了。
读到这里感觉,这其实都可以说是分布式的优势了。
commit log
Kafka中的数据都是有顺序的,有序号记录的,它把数据记录在硬盘上,如果有序号的话,它的读写都是$O(1)$,读写也互相不影响,无论多少的数据,都是一样的。这就导致了在如今大量的数据流的互联网环境,Kafka的读写是多么的有利。
之后介绍了Kafka如何工作。比较重要的几点就是,
- consumer在消费的时候,有一个offset,可以记录你上次的读取记录,你可以自己决定从哪开始读取。
- kafka中的数据会复制保持在各个broker之中,保证如果一个Leader挂掉,其他的broker 可以马上选举,而且数据不会丢失。
- kafka的元数据(Leader,partition…)都是记录在zookeeper中的,zookeeper的读比写快更多(注:zookeeper不是很熟,争取下周熟悉一下zookeeper的核心思想和设计理念)
然后:它的Stream Processing 不是很清楚。这一块的业务没有接触到真实的实例,需要做做实验才能更加深入!
Tip
这周自己看了kafka的前面文档,自己在win 10 的Linux子系统里面安装了kafka.
- 首先去官网下载kafka,解压。
> tar -xzf kafka_2.11-2.0.0.tgz
> cd kafka_2.11-2.0.0
- 开启服务。kafka首先需要zookeeper,所以如果有zookeeper的要先开启zookeeper;不然也可以用kafka内置的,去开启zookeeper的服务。
> bin/zookeeper-server-start.sh config/zookeeper.properties
或者直接在后台启动,不让它输出到终端。
> bin/zookeeper-server-start.sh config/zookeeper.properties 1>/dev/null 2>&1 &
然后开启Kafka服务:
> bin/kafka-server-start.sh config/server.properties
- 创建一个topic,之后你就可以让生产者往这个topic里面放数据,消费者从这个topic 里面拿数据了。
> bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test
这里只创建了一个分区和一份复制。
- 现在用生产者往这个
test的topic里面放一些数据。
> bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test
This is a message
This is another message
- 用消费者拿一些数据出来看看。
> bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning
This is a message
This is another message
- 目前都只是在一个kafka服务上面,kafka是可以做集群的。先来建立三个节点。
> cp config/server.properties config/server-1.properties
> cp config/server.properties config/server-2.properties
负责两份配置文件,然后修改一下下面的关键参数即可:
config/server-1.properties:
broker.id=1
listeners=PLAINTEXT://:9093
log.dirs=/tmp/kafka-logs-1
config/server-2.properties:
broker.id=2
listeners=PLAINTEXT://:9094
log.dirs=/tmp/kafka-logs-2
broker.id是每个节点中独一无二的属性,端口和日志文件地址也是因为目前是建立在一台机器上,所以需要有所区分。
然后像之前那样启动这两个服务即可。
> bin/kafka-server-start.sh config/server-1.properties &
...
> bin/kafka-server-start.sh config/server-2.properties &
再创建一个拥有三份复制的topic
> bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 3 --partitions 1 --topic my-replicated-topic
然后让我们来观察一下这个topic的状态:
> bin/kafka-topics.sh --describe --zookeeper localhost:2181 --topic my-replicated-topic
Topic:my-replicated-topic PartitionCount:1 ReplicationFactor:3 Configs:
Topic: my-replicated-topic Partition: 0 Leader: 1 Replicas: 1,2,0 Isr: 1,2,0
Leader,是负责所给分区的读与写。每个节点都有机会成为leader,这是随机选择出来的。
Replicas,是复制分区日志、数据的一列节点,因为建立的broker.id分别是0,1,2,所以这刚好也是这三个。
Isr,是’In-Sync’,是目前活着的一些节点。
到目前为止,这大概就是一个简单的kafka的上手了。可以快速体验一下kafka 不同于过去传统消息系统的区别。通过主题和订阅的方式让消费者都能得到数据,同时又运用队列和topic,让不同的消费者可以读到各自不同的数据。
kafka才接触几天,浅薄之见,如有错误,请指出。
后续会继续读读Kafka官方的document,里面的design似乎讲的是它的设计,这个应该是它的精髓之所在。
Share
分享一篇关于分布式的文章:
A Thorough Introduction to Distributed Systems
还有一篇blog,更上周是一个博主写的:
Write code that’s easy to delete, and easy to debug too