所谓ARTS: 每周至少做一个LeetCode的算法题;阅读并点评至少一篇英文技术文章;学习至少一个技术技巧;分享一篇有观点和思考的技术文章。(也就是Algorithm、Review、Tip、Share 简称ARTS)这是第九期打卡。
这周的精力主要放在学习微服务上了,所以也是紧赶慢赶,把这个打卡的内容及时更新出来,不为别的,就为了对得起自己的付出和学习,不知道还能坚持多久,反正且行且珍惜吧。
Algorithm LeetCode算法
移除元素
(https://leetcode.com/problems/remove-element/submissions/)
题目描述:给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素
示例 1:
给定 nums = [3,2,2,3], val = 3,
函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。
你不需要考虑数组中超出新长度后面的元素。
示例 2:
给定 nums = [0,1,2,2,3,0,4,2], val = 2,
函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
注意这五个元素可为任意顺序。
你不需要考虑数组中超出新长度后面的元素。
说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}
当你看到这题的时候,是不是似曾相识呢?小编是随便选的,但是看完了这个描述,回忆起小编的上一道题目,删除排序数组中的重复项。这次,小编可是擦亮了眼睛,不胡乱来了。
还是审题、审题、审题,重要的事情说三遍,是不能改变数组的大小和结构哦,只在当前数组里进行操作,所以,还是和上一题的思路一样,来进行遍历的操作。
思路就是用双指针。我们可以保留两个指针i和j,其中i是慢指针,j是快指针。具体详解就看下我提供的代码吧,这个确实太简单了,没啥好解释的。不过我用的是其中一个双指针,看了其他的思路,其实还有一个适合删除元素少的双指针操作,小编也贴上哈。不是我解的,我得好好反思下了。
public static int remvoeElement(int[] nums,int val) {
int i = 0;
for (int j = 0; j < nums.length; j++) {
if (nums[j] != val) {
nums[i] = nums[j];
i++;
}
}
return i;
}
时间复杂度:O(n), 假设数组总共有 nn 个元素,ii 和 jj 至少遍历 2n2n 步。
空间复杂度:O(1)
双指针--当要删除的元素很少时
public int removeElement(int[] nums, int val) {
int i = 0;
int n = nums.length;
while (i < n) {
if (nums[i] == val) {
nums[i] = nums[n - 1];
// reduce array size by one
n--;
} else {
i++;
}
}
return n;
}
时间复杂度:O(n),ii 和 nn 最多遍历 nn 步。在这个方法中,赋值操作的次数等于要删除的元素的数量。因此,如果要移除的元素很少,效率会更高。
空间复杂度:O(1)。
Review 阅读并点评至少一篇英文文章
Quick Guide to Microservices with Spring Boot 2.0, Eureka and Spring Cloud
(https://piotrminkowski.wordpress.com/2018/04/26/quick-guide-to-microservices-with-spring-boot-2-0-eureka-and-spring-cloud/)
就如开头所说的,从这周开始,小编开启了Spring Cloud的学习,周一开始搭环境,看了下部分知识。周二还是实战,结果因为刚开始不懂Spring Cloud的版本命名规则,选择了一个比较老的版本进行实战,很多新版的问题没有留意到。
跟着书本再次学习的时候,发现还是需要使用新版本的,最终确定使用GA的最新版本,Spring Cloud Greenwich.SR1和Spring Boot 2.1.5 RELEASE开启我的微服务之旅。
因为是最新的版本,所以踩的坑比较多,给出的这篇文章给了我很大的启发和帮助,虽然是基于2.0的,但也适用我的最新版本,通过文中的快速构建向导,以及针对某些问题作出的解答,让我在很多迷茫的时候,都能及时走出来,并成功得到自己想要的结果。
其实,学习的时候,也查阅了很多资料,都做了小笔记,国内的资料确实太少了。这就需要锻炼自己的搜索能力,以及看第一手资料的能力,最重要的就是官方文档了。当初学习Android的时候,就是看的第一手资料,现在微服务也要按照这个思路前进。
Tip 一个技术技巧
继续分享《Java核心技术36讲》做的学习笔记,关于Java安全的系列,关于如何写出安全的Java代码的总结
典型回答
if(a + b < c) {
}
会有溢出的可能
所以,上面的条件判断,需要判断其数值范围,例如,写成类似下面的结构
if(a < c - b)
第三,Java提供了序列化等创新的特性,广泛使用在远程调用等方面,但也带来了复杂的安全问题。
针对序列化,通常建议:
- 敏感信息不要被序列化!在编码中,建议使用transient关键字将其保护起来
- 反序列化中,建议在readObject中实现与对象构件过程相同的安全检查和数据检查
《阿里巴巴Java开发手册》
落实到实际的开发流程中,以OpenJDK团队为例,我们应用了几个不同角度的实践:
- 在早起设计阶段,就由安全专家对新特性进行风险评估
- 在开发过程中,尤其是code review阶段,应用OpenJDK自身定制的代码规范
- 利用多种静态分析工具入FindBugs、Parfait等,帮助早期发现潜在安全风险,并对相应问题采取零容忍态度,强制要求解决
- 甚至OpenJDK会默认将任何(编译等)警告,都当做错误对待,并体现在CI流程中
- 在代码check-in等关键环节,利用hook机制去调用规则检查工具,以保证不合规代码不能进入OpenJDK代码库
爱生活,爱学习,爱感悟,爱挨踢