读《七堂极简的物理课》有感
读这本书是为了了解自牛顿后的物理学巨变
牛顿之后,发现了电磁场,但力学定律与麦克斯韦方程组有冲突,爱因斯坦发现了时空关系,时间和空间不再是独立的。
后面发现了量子,世界不再是连续的,是一份份的。微观世界趋向于概率性的,不确定的。不再是牛顿时代的,一切都是根据确定的公式确定的。
爱因斯坦统一时间与空间,引力与电磁场,质量与能量。引发了核物理,量子力学。
读了一遍还是一知半解。
读这本书是为了了解自牛顿后的物理学巨变
牛顿之后,发现了电磁场,但力学定律与麦克斯韦方程组有冲突,爱因斯坦发现了时空关系,时间和空间不再是独立的。
后面发现了量子,世界不再是连续的,是一份份的。微观世界趋向于概率性的,不确定的。不再是牛顿时代的,一切都是根据确定的公式确定的。
爱因斯坦统一时间与空间,引力与电磁场,质量与能量。引发了核物理,量子力学。
读了一遍还是一知半解。
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-linked-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
迭代和递归方式
迭代1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class Solution {
public ListNode reverseList(ListNode head) {
ListNode node = head;
ListNode pre = null;
if(node == null)return head;
ListNode next = node.next;
while(node != null && next!=null){
node.next = pre;
pre = node;
node = next;
next = node.next;
}
node.next = pre;
return node;
}
}
递归1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Solution {
public ListNode reverseList(ListNode head) {
if(head==null)return head;
return reverse(head,null);
}
public ListNode reverse(ListNode node,ListNode exist){
ListNode next = node.next;
if(next == null){
node.next = exist;
return node;
}
node.next = exist;
return reverse(next,node);
}
}
官方解法1
2
3
4
5
6
7
8
9class Solution {
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) return head;
ListNode p = reverseList(head.next);
head.next.next = head;
head.next = null;
return p;
}
}
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-linked-list-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
4个主要节点,一个m-1之前,m-n反转链表,一个n+1,
1 | class Solution { |
执行结果
执行用时 :1 ms, 在所有 Java 提交中击败了87.25%的用户
内存消耗 :35.2 MB, 在所有 Java 提交中击败了48.42%的用户
读这本书的初衷是了解机械思维是怎么产生了,开始仅仅以为是普通的传记,但读了之后收获很大。
本书从牛顿的出生到死亡,从他研究的各个领域一一抽丝剥茧的探寻发生的事情,有理有据,从书信、生者的记录,不带个人感情的客观的了解发生了什么。
虽然书的标题有些标题党,但内容确实详实。牛顿少年缺爱,父亲早逝,母亲在她童年一段时间改嫁其他人,导致他孤僻的性格,和对异性的态度。
牛顿在大学不算突出,勉强毕业,生活上也比较艰苦,但一些其他人的帮助,让他留在剑桥做了研究员,生活有了保障。
1666年是牛顿的奇迹年,正赶上瘟疫,他回到老家,万有引力和经典物理,虽然这个时候大部分思维已经有了,但也许是没有经过严密的论证,或者是他为了保守秘密,在20年后,才写成《自然哲学之数学原理》这一部集大成者,完成这部书只有18个月。
书中写了很多科学家与科学家的交往,牛顿是受到笛卡尔的影响,大环境影响着每一个人,伟大的科学家也是生活在时代里的一员,不能脱离时代。牛顿与胡可的争论不休,牛顿当权后打压其他人,牛顿与莱布尼茨同时独立发明微积分,即使有伟大成就的人也不能免俗,有着各种各样的缺点与错误。
牛顿第一次发表一些光学的见解的时候,受到很大的刺激,即使他的方法是最先进的,正确的,但还是很多人接受不了,对一些小毛病进行质疑,有些甚至没看过就质疑,这些还是皇家学会的受过良好教育的人,所以一个结论呗大家接受需要一段时间去验证,不是正确的事实大家都会很快接受,而且还有可能是刚出生的婴儿,看起来没什么用处,但如果后期突破会有很大成就。这些是客观事实,要认清事实。反馈有时延。
牛顿引发的机械思维的革命,在牛顿之前,人对不明白的事物只能解释为神的意志,牛顿让人有了信心,通过一个简单的公式,可以驾驭自然。
革新了科学研究的方法,之前都是查别人的经史典籍,前人的书籍中引用,现在是重数学推导,重实验。
先纵览spring cloud各个组件,只是大致了解一下各个功能,要明白每一个组件的主要原理,不能只会使用
配置中心,将系统中用到的一些配置信息存储到配置中心,方便维护,不用每次修改配置都重启服务。用的比较多的配置中心还有etcd、携程的 Apollo、Disconf 。
Netflix OSS 是一组开源的框架和组件库,是Netflix公司开发出来解决分布式系统的一些有趣的可扩展类库。Spring Cloud 把他们都放到 Spring Cloud Netflix 下,这是一个框架集合,它包括 Eureka 、Ribbon、Zuul、Hystrix 等。
服务中心,这可以说是微服务架构的核心功能了,微服务部署之后,一定要有服务注册和发现的能力,Eureka 就是担任这个角色的。如果你用过 dubbo 的话,那一定知道 dubbo 中服务注册和发现的功能是用 zookeeper 来实现的。
目前官方已停止升级,如果你的项目中还没有使用并且打算使用注册中心的话,可以直接使用 Spring Cloud Consul。
提供客户端负责均衡功能,例如一个服务提供者部署了 3 个实例,那么使用 Ribbon 可以指定负载均衡算法请求其中一个实例,Ribbon 如果配合 Eureka ,使用起来非常简单。
熔断器,假设有 3 个服务提供实例,其中有一个实例由于某中原因挂掉了,那么当再有请求进来的时候,如果还是向这个实例上发请求,那将会导致请求积压阻塞,这个时候,熔断器就要发挥它的作用,将这个有问题的实例下线,这样一来,再有新的请求进来,就不会再发到这个有问题的实例上了。
服务网关。主要实现了路由转发和过滤器功能,对于处理一些数据聚合、鉴权、监控、统计类的功能非常好用。
也是服务网关,可以认为它是 Zuul 的下一代,无论从易用性和性能方便都有所提高,如果你的系统中还没有使用 Zuul ,并且准备上网关,可以直接选择 Gateway 。
Consul 让服务注册和服务发现(通过 DNS 和 HTTP 接口)更加简单,甚至对于外部服务(例如SaaS)注册也一样。Spring Cloud Consul 可替代已有的 Spring Cloud Eureka。Eureka 2.x 版本也已经停止开发,并且 Spring Cloud 官方也建议用 Spring Cloud Consul 来替代,当然如果已经用了 Eureka 在项目中也没有关系,Eureka 已经足够稳定,正常使用没有任何问题。
Spring Cloud Stream 是消息中间件组件,它集成了 kafka 和 rabbitmq 。如果你的系统中打算集成 kafka 或 rabbitmq,可以考虑使用 Stream 。
消息总线,用于在集群(例如,配置变化事件)中传播状态变化,可与Spring Cloud Config联合实现热部署。集成了 Rabbitmq 和 kafka 。刚刚上面说到的 Stream 好像也是这个功能。没错,我们可以认为 Bus 是 Stream 的进一步封装,使用更简单。而 Stream 的灵活性更高。
Feign是一种声明式、模板化的HTTP客户端。它可以用注解的方式简化 HTTP 请求,可以快速简单的请求服务提供接口。如果你还在使用 restTemplate 或者其他方式,不妨考虑一下 Feign。
服务日志收集和链路追踪模块,封装了 Dapper 和 log-based 追踪以及 Zipkin 和 HTrace 操作。与之功能相同的框架还有 skywalking、Pinpoint,另外国内还有美团开源的 CAT,只不过 CAT 属于代码侵入的,需要开发人员在系统中做代码埋点,不过也更加灵活,更加精细。
可用做授权服务、单点登录等。如果服务需要做权限控制,那除非你自己实现。不然用到最多的就是 shiro 和 Spring Security 。Spring Boot 中用的比较多的就是 Security,众多授权机制中属于 OAuth2 最为流行。Spring Cloud Security 就是将 Security、OAuth2 做了集成,方便使用。
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/add-two-numbers
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
依次两个链表相加,主要分几种情况,一种是两个链表同时结束,一个是某个链表长
然后就是进位的处理,有可能链表结束了,但还要继续进位增加一个节点。
自己解法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/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode first = new ListNode(0);
ListNode node = first;
while(l1 != null || l2 != null || node != null){
int sum = node.val;
if(l1 != null){
sum += l1.val;
}
if(l2!= null){
sum +=l2.val;
}
//System.out.println("sum"+sum);
if(sum>=10){
node.val = sum%10;
node.next = new ListNode(sum/10);
//System.out.println(node.val);
}else{
node.val = sum;
//System.out.println(node.val);
}
if(l1 != null){
l1 = l1.next;
}
if(l2 !=null){
l2 = l2.next;
}
if(node.next == null && (l1 !=null || l2!=null)){
node.next = new ListNode(0);
}
node = node.next;
}
return first;
}
}
参考答案解法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
28class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode dummyHead = new ListNode(0);
ListNode node = dummyHead;
int carry = 0;
while(l1 != null || l2 != null){
int l1Val = l1 !=null ? l1.val : 0;
int l2Val = l2 != null ? l2.val :0;
int sum = l1Val +l2Val + carry;
carry = sum/10;
node.next = new ListNode(sum%10);
node = node.next;
if(l1 != null){
l1 = l1.next;
}
if(l2 !=null){
l2 = l2.next;
}
}
if(carry > 0){
node.next = new ListNode(carry);
}
return dummyHead.next;
}
}
jhipster是一种生产微服务的脚手架,最近想入门spring cloud,但很多组建无从下手,正好找到一个脚手架,这样快速搭建,才能快速上手。
创建应用类型4种
这里将应用简单的打包成4种,第一种是单体应用,第二种是微服务应用,第三种是微服务的网关,第四种是认证授权服务器。将服务抽象成这四种。
4种安全的方式
生成字段,有自定义的UML等,可以生成字段脚本等,可以验证字段等
生成访问路由,rest controller还有api swagger等
生成后端服务,提供服务
主要组件的包含技术
gateway:Zuul,Ribbon,Access-controll with UAA,front-end
register:Eureka server,Config server
microservice:spring boot
UAA
第二遍阅读,我变成主动探索阅读,探索几次科学界引起的思维的变化,比如笛卡尔科学方法论,到牛顿的机械思维,到后面的量子力学引起不确定性,掌握不同的思维模式,科学的思考。
科学方法论起源笛卡尔
大胆假设,小心求证,怀疑时智慧的源头
笛卡尔的方法论讲诉的是科学研究从感知到新知所应该遵循的过程。他认为,这个过程的起点是感知,通过感知得到抽象的认识,并总结出抽象的概念,这些是科学的基础。
《方法论》Discourse on the method
揭示了科学研究和发明创造的普适方法,并概括成4个步骤。
第一,不盲从,不接受任何自己不清楚的真理。
第二,对于复杂的问题,尽量分解成多个简单的小问题来研究。
第三,解决这些小问题时,应该按照先易后难的次序,逐步解决。
第四,解决每个小问题后,再综合起来,看看是否彻底解决了原来的问题。
实验+逻辑,成为实验科学的基础。
笛卡尔将科学发展的规律总结为:(1)提出问题;(2)进行实验;(3)从实验中得到结论并解释;(4)将结论推广并普遍化;(5)在实践中提出新的问题。如此循环往复。
笛卡尔总结出完整的科学方法,即科学研究时通过正确的论据(和前提条件),进行正确的推理,得到正确的结论的过程。
牛顿
构建了近代三大科学体系,即以微积分为核心的近代数学,牛顿三定律为基础的经典物理学,以万有引力定律为基础的天文学
其他建立数学体系的,欧几里得、笛卡尔和柯西,物理,爱因斯坦、玻尔
通过科学成就,改变了人们对世界的认识
在数学方面,牛顿最大的贡献是发明了微积分,是今天高等数学的基础。在微积分的背后,这个发明的意义更大。在微积分出现之前,数学家研究的对象和解决的问题都是静态的,而牛顿关注到了精确而瞬时的动态计算问题,以及对一个变量长期变化的积累效应的追踪问题。微积分便是解决这两个动态问题的数学工具。此外,牛顿还看到了追求瞬间动态和长期积累效应之间的关系,从而将微分和积分的理论统一起来。从静态到动态,从孤立到统一,数学从微积分开始,由初等数学进入高等数学阶段,这也是人类在认识上的一个飞跃。
在物理学方面,牛顿是经典力学的奠基人,他的力学三定律是整个力学的基础。牛顿是建立起严密的物理学体系的人。而建立一个学科体系,首要的任务是定义清楚各种基本概念。牛顿定义了经典物理学中的这些最基本的概念,比如质量、力、惯性、动能等,然后在此基础上,提出了力学三定律,进而搭起了经典力学的大厦。
后面继续深入机械思维,去看看牛顿的生平。
第二遍阅读,能从更高层次去看这篇文章。
首先学习如何写论文,要把前因后果写清楚,先写出目前的背景,再提出目标,定义功能,实现结构,最后结论。
该文章很清楚的写出来RPC诞生的背景,就是分布式系统,方法调用不像原来单机那么简单,多进程间调用,而且不在一台机器上,很复杂,想隔离这部分复杂度,简化这部分的难度。让方法间调用像单机一个方便。
目标有几点,
第一,希望像本地访问,移除不必要的困难,只留下构建分布式系统的基本困难:时序,组件的独立故障以及独立执行环境的共存。
第二,RPC沟通是高效的
第三,RPC 包的语义尽可能强大,不失简单和高效
第四,建立安全的连接。
这部分定义清楚,哪些是RPC该做的,哪些不是他该做的,划分边界。
实现结构上采用user,user-stub,RPCRuntime,server-stub,server的结构,server端写导出接口,自动生成server-stub,RPCRuntime是一个单独的包,用来连接client-server,user导入server接口,生成user-stub,用户只需要调用user-stub即可。
其中有几部分工作需要做,
1.server自动生成stub,以及user端的导入
2.RPCRuntime连接user和server,如何binding,以及多个server的Naming
3.网络传输,如何高效的传输数据,超时、异常等处理。
第一个问题比较好实现,第二个问题,作者的实现在user和server之间使用一个分布式数据库做连接,去查询这个数据库,server注册,user查询server地址,去实现binding和Naming,这个部分可以对比现在的实现。
第三个问题,也很重要,作者当时应该没有TCP/IP协议,所以是自实现协议的,现在看来都是基于TCP/IP的,然后就是使用在此之上的自定义协议,还是使用现有协议。而且还需要考虑BIO、NIO、AIO等网络传输的效率,现在基本都是使用Netty。
确实认识到实际上升到理论的重要性,可以一通百通,叠加式的进步,而不是一个个知识点的叠加。
后面再写一个文章分析一个binding和Naming,网络这块要继续学习Netty。
有 N 个网络节点,标记为 1 到 N。
给定一个列表 times,表示信号经过有向边的传递时间。 times[i] = (u, v, w),其中 u 是源节点,v 是目标节点, w 是一个信号从源节点传递到目标节点的时间。
现在,我们向当前的节点 K 发送了一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回 -1。
注意:
N 的范围在 [1, 100] 之间。
K 的范围在 [1, N] 之间。
times 的长度在 [1, 6000] 之间。
所有的边 times[i] = (u, v, w) 都有 1 <= u, v <= N 且 0 <= w <= 100。
最短路径,DisjKstra算法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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190class Solution {
private int v;
boolean[] inqueue;
private LinkedList<Edge> adj[];
PriorityQueue[] queue;
private class Vertex{
private int id;
private int dist;
public Vertex(int id ,int dist){
this.id = id;
this.dist =dist;
}
}
private class Edge{
private int src;
private int dst;
private int dist;
public Edge(int src ,int dst ,int dist){
this.src =src;
this.dst = dst;
this.dist = dist;
}
}
class PriorityQueue{
private Vertex[] nodes;
private int count;
private int n;
public PriorityQueue(int v){
this.nodes = new Vertex[v+1];
this.count =0;
this.n = v;
}
public void add(Vertex ver) {
if(count>=n){return;}
nodes[++count]=ver;
int i=count;
while(i/2>0&&nodes[i/2].dist>nodes[i].dist) {
Vertex temp=nodes[i/2];
nodes[i/2]=nodes[i];
nodes[i]=temp;
i=i/2;
}
}
public Vertex poll() {
if(count<1){return null;}
Vertex temp=nodes[1];
nodes[1]=nodes[count];
nodes[count] = null;
count--;
heaplify(nodes,count,1);
return temp;
}
private void heaplify(Vertex[] a,int n,int i) {
if(n<1){return;}
int min=i;
while(true) {
//找到子节点比该结点小的中较小的
if(2*i<=n&&a[2*i].dist<a[min].dist) {
min = 2 * i;
}
if(2*i+1<=n&&a[2*i+1].dist<a[min].dist){min=2*i+1;}
//该节点比子节点大堆化完毕
if(min==i){ return;}
//交换两节点
Vertex temp=a[min];
a[min]=a[i];
a[i]=temp;
i=min;//迭代条件
}
}
public void update(Vertex vertex) {
int i=1;
boolean exist = false;
for(;i<=n;i++) {
if(nodes[i]!= null && nodes[i].id==vertex.id){
exist = true;
break;
}
}
if(!exist){
add(vertex);
}else{
nodes[i].dist=vertex.dist;
}
heaplify(nodes,count,i);
}
public boolean isEmpty() {
if(count<1)return true;
return false;
}
private void treeifyUp(int k){
if(k > count +1){
return;
}
int i = k;
while(i < 1){
i = k/2;
if(nodes[i].dist > nodes[k].dist){
Vertex temp = nodes[i];
nodes[i] = nodes[k];
nodes[k] = temp;
}else{
break;
}
}
}
private void treeifyDown(int k){
int i = k;
while(i < count/2){
int left = i*2;
int right = i*2+1;
if(nodes[left].dist < nodes[i].dist){
Vertex tmp = nodes[i];
nodes[i] = nodes[left];
nodes[left] = tmp;
i = left;
}else if(nodes[right].dist < nodes[i].dist){
Vertex tmp = nodes[i];
nodes[i] = nodes[right];
nodes[right] = tmp;
i = right;
}else{
break;
}
}
}
}
public int networkDelayTime(int[][] times, int N, int K) {
this.v = N;
Vertex[] vertexs = new Vertex[v+1];
this.inqueue = new boolean[v+1];
this.queue = new PriorityQueue[v];
int first = times.length;
int second = times[0].length;
adj = new LinkedList[N+1];
for(int l= 0 ; l < N+1 ; l++){
adj[l] = new LinkedList<Edge>();
if(l != 0){
vertexs[l] = new Vertex(l,Integer.MAX_VALUE);
}
}
for(int m = 0 ; m< first ; m++){
int src = times[m][0];
adj[src].add(new Edge(times[m][0],times[m][1],times[m][2]));
}
PriorityQueue queue = new PriorityQueue(this.v);
vertexs[K].dist = 0;
queue.add(vertexs[K]);
inqueue[K] = true;
while(!queue.isEmpty()){
Vertex minVertex = queue.poll();
int minVertexId = minVertex.id;
LinkedList<Edge> list = adj[minVertexId];
for(int i = 0 ; i< list.size() ; i++){
Edge edge = list.get(i);
Vertex nextVertex = vertexs[edge.dst];
if(nextVertex.dist > edge.dist + minVertex.dist){
nextVertex.dist = edge.dist + minVertex.dist;
if(inqueue[nextVertex.id]){
queue.update(nextVertex);
}else{
queue.add(nextVertex);
inqueue[nextVertex.id] = true;
}
}
}
}
int d = 0;
for(int q = 1 ; q <= N ; q++){
if(vertexs[q].dist == Integer.MAX_VALUE){
return -1;
}
if(d < vertexs[q].dist){
d = vertexs[q].dist;
}
}
return d;
}
}
好不容易通过测试,找到临接表,从顶点开始,依次便利顶点相连的所有节点,将每个节点的vertex放入最小堆里面,然后弹出最小的值的节点,继续重复上面的循环,知道最小堆为空。有一个数组保存已经访问过的数据,保证不重复访问。如果堆里有,就更新数据,重新对花堆化。
我不能说完全明白,但经过一个星期的思考,从完全懵逼到入门了。还需要继续深入理解。