ARTS (第55周)
“看懂”和“会用”是两回事,而“用好”更是难上加难。
实际上,不管是应用设计原则还是设计模式,最终的目的还是提高代码的可读性、可扩展性、复用性、可维护性等。我们在考虑应用某一个设计原则是否合理的时候,也可以以此作为最终的考量标准。
出处:极客时间《设计模式之美》(作者:王争)
https://time.geekbang.org/column/intro/250
Algorithm 算法
孩子们的游戏(圆圈中最后剩下的数)
1 | 每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1) |
解法1 将数组视为环,逐个遍历。并创建个数组保存是否去除
1 | // 环形遍历数组 记录已遍历的数据 |
解法2
这个是解法1的优化,依旧将数组视为环,通过计算快速找出索引。并创建个数组保存是否去除
1 | // 根据索引快速找到位置 |
解法3 动态规划
在题解里看到,这个其实是个约瑟夫环问题
通过最后一个来逐个找到上一个。原本看到的是递归写法的动态规划,后面我改成这种。
1 | public int LastRemaining_Solution(int n, int m) { |
求1+2+3+…+n
1 | 求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。 |
解法 递归+短路
这题的重点是需要判断,而大部分判断语句都禁止使用,然后这里是使用&&短路的写法实现了判断。
1 | // 递归短路 |
不用加减乘除做加法
1 | 写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。 |
解法 二进制计算
1 |
|
把字符串转换成整数
1 | 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0 |
解法
逐个字符获取,然后旧值*10后进行累加的解法。但因为需要判断正负数、INT_MAX值的判断,加入了很多判断语句。
核心语句就是:
//cur代表当前字符
res = res * 10 + cur;//正数
res = res * 10 - cur;//负数
1 | // 逐个累加 |
数组中重复的数字
1 | 在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。 |
解法1 排序法
排序后,判断数组的前后位置是否相等,相等即可返回。
1 | public boolean duplicate_(int numbers[], int length, int[] duplication) { |
解法2 索引位置交换位置法
交换法也是一个很经常在数组中用到的解法。
遍历数组,将每个数都放到对应索引位置上,交换位置,这样最多一次遍历就可以找出重复。
1 | // 重复查找 |
构建乘积数组
1 | 给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。(注意:规定B[0] = A[1] * A[2] * ... * A[n-1],B[n-1] = A[0] * A[1] * ... * A[n-2];) |
解法 前后缀解法
其实就B[i]等于 A数组的乘积和 /A[i];
因为 B[i]=A[1] A[2] … A[i-1]A[i-1]…A[n]
所以整理两个数组,分别保存A[1] A[2] … * A[i-1]和A[i-1]…A[n]。
来快速计算
1 | public int[] multiply(int[] A) { |
正则表达式匹配
1 | 请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配 |
解法 动态规划
1 | // 动态规划 |
Review 英文文章
https://spring.io/guides/gs/managing-transactions/
spring 的事务管理器,以及搭配jdbctempleta使用。
Tip 技巧
面向对象特性分析
接口和抽象类定义。区别(是什么),存在意义(从哪来),应用(到哪去)。
1、定义:
抽象类:不允许实例化,只能被继承;可包含属性和方法,包含抽象方法;子类继承抽象类必须重写抽象方法。
接口:不允许实例化,只能被实现;不包含属性和普通方法,包含抽象方法、静态方法、default 方法;类实现接口时,必须实现抽象方法。
2、意义:
抽象类:解决复用问题,适用于is-a的关系。
接口:解决抽象问题,适用于has-a的关系。
3、应用:
例如:
解决复用问题:java中的子类FileInputStream和PipeInputStream等继承抽象类InputStream。重写了read(source)方法,InputStream 中还包含其他方法,FileInputStream继承抽象类复用了父类的其他方法。
解决抽象问题:抽象类InputStream实现了Closeable接口,该接口中包含close()抽象方法。Closeable这个接口还在很多其他类中实现了,例如Channel,Socket中都有close() 关闭这个功能,但具体实现每个类又各有不同的实现,这个就是抽象。
来源:极客时间 https://time.geekbang.org/column/article/165103
用户:辣么大
面向对象的实现
面向对象分析、设计、实现
面向对象分析、设计、实现,每个环节的界限划分都比较清楚。而且,设计和实现基本上是按照功能点的描述,逐句照着翻译过来的。这样做的好处是先做什么、后做什么,非常清晰、明确,有章可循,即便是没有太多设计经验的初级工程师,都可以按部就班地参照着这个流程来做分析、设计和实现。
出处:极客时间《设计模式之美》(作者:王争)
https://time.geekbang.org/column/intro/250
单一职责原则
类中的代码行数、函数或属性过多,会影响代码的可读性和可维护性,我们就需要考虑对类进行拆分;类依赖的其他类过多,或者依赖类的其他类过多,不符合高内聚、低耦合的设计思想,我们就需要考虑对类进行拆分;私有方法过多,我们就要考虑能否将私有方法独立到新的类中,设置为 public 方法,供更多的类使用,从而提高代码的复用性;比较难给类起一个合适名字,很难用一个业务名词概括,或者只能用一些笼统的 Manager、Context 之类的词语来命名,这就说明类的职责定义得可能不够清晰;类中大量的方法都是集中操作类中的某几个属性,比如,在 UserInfo 例子中,如果一半的方法都是在操作 address 信息,那就可以考虑将这几个属性和对应的方法拆分出来。
出处:极客时间《设计模式之美》(作者:王争)
https://time.geekbang.org/column/intro/250
开闭原则
如何理解“对扩展开放、对修改关闭”?
添加一个新的功能,应该是通过在已有代码基础上扩展代码(新增模块、类、方法、属性等),而非修改已有代码(修改模块、类、方法、属性等)的方式来完成。关于定义,我们有两点要注意。第一点是,开闭原则并不是说完全杜绝修改,而是以最小的修改代码的代价来完成新功能的开发。第二点是,同样的代码改动,在粗代码粒度下,可能被认定为“修改”;在细代码粒度下,可能又被认定为“扩展”。
如何做到“对扩展开放、修改关闭”?
我们要时刻具备扩展意识、抽象意识、封装意识。在写代码的时候,我们要多花点时间思考一下,这段代码未来可能有哪些需求变更,如何设计代码结构,事先留好扩展点,以便在未来需求变更的时候,在不改动代码整体结构、做到最小代码改动的情况下,将新的代码灵活地插入到扩展点上。很多设计原则、设计思想、设计模式,都是以提高代码的扩展性为最终目的的。特别是 23 种经典设计模式,大部分都是为了解决代码的扩展性问题而总结出来的,都是以开闭原则为指导原则的。最常用来提高代码扩展性的方法有:多态、依赖注入、基于接口而非实现编程,以及大部分的设计模式(比如,装饰、策略、模板、职责链、状态)。
出处:极客时间《设计模式之美》(作者:王争)
https://time.geekbang.org/column/intro/250
里式替换
而里式替换是一种设计原则,是用来指导继承关系中子类该如何设计的,子类的设计要保证在替换父类的时候,不改变原有程序的逻辑以及不破坏原有程序的正确性。
子类在设计的时候,要遵守父类的行为约定(或者叫协议)。父类定义了函数的行为约定,那子类可以改变函数的内部实现逻辑,但不能改变函数原有的行为约定。这里的行为约定包括:函数声明要实现的功能;对输入、输出、异常的约定;甚至包括注释中所罗列的任何特殊说明。
出处:极客时间《设计模式之美》(作者:王争)
https://time.geekbang.org/column/intro/250
Share 分享
https://blog.csdn.net/C_envelope/article/details/87920146 DDD四种模型
https://www.jianshu.com/p/b0379067c978 DDD介绍