描述 | 目的 | |
---|---|---|
Algorithm | 每周至少一道 Leetcode 的算法题 | 编程训练和学习 |
Review | 阅读并点评至少一篇英文技术文章 | 学习英文 |
Tip | 学习至少一个技术技巧 | 总结和归纳日常生活中遇到的知识点 |
Share | 分享一篇有观点和思考的技术文章 | 建立自己的影响力,能够输出价值观 |
Algorithm
题目:977-有序数组的平方
题目描述:给定一个按非递减顺序排序的整数数组 A
,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。
示例 1:
输入:[-4,-1,0,3,10]
输出:[0,1,9,16,100]
示例 2:
输入:[-7,-3,2,3,11]
输出:[4,9,9,49,121]
提示:
1 <= A.length <= 10000
-10000 <= A[i] <= 10000
A
已按非递减顺序排序。
解答
思路一
最简单的思路:对数组 A 的每一个元素进行平方操作,然后对数组 A 排序。
public int[] sortedSquares(int[] A) {
for(int i = 0; i < A.length; i++){
A[i] = A[i] * A[i];
}
Arrays.sort(A);
return A;
}
思路二
想了一段时间,实在想不出其他的方法,于是看了一下题解,发现还有一种双指针的解法(思路和归并排序类似):
- 将数组分为非负和负数部分;
- 指针 i 指向负数部分的最后一个元素;指针 j 指向非负部分的第一个元素
- 准备一个辅助数组;
- i 往前移动,j 向后移动,并在移动过程中比较对应元素的平方的大小,小的放入辅助数组;
- 当某一指针移动到该侧的最后,将另一侧的剩余元素平方后直接全部填入辅助数组
个人感觉思路二似乎不太合适,因为题目中数组 A 是非递减顺序排序的,而题解中的思路二则忽略了数组 A 可能是乱序的情况(如:“-3、4、5、-7、8、-1、0”),二仅仅当做 A 整体是一个升序的过程(可能有相等的情况),但是测试是通过的,所以这里也将思路二的代码写了出来:
public int[] sortedSquares(int[] A) {
int len = A.length;
int j = 0;
while (j < len && A[j] < 0) {
j++;
}
int i = j - 1;
int[] result = new int[len];
int t = 0;
while (i >= 0 && j < len) {
if (A[i] * A[i] < A[j] * A[j]) {
result[t++] = A[i] * A[i];
i--;
}else {
result[t++] = A[j] * A[j];
j++;
}
}
while (i >= 0) {
result[t++] = A[i] * A[i];
i--;
}
while (j < len) {
result[t++] = A[j] * A[j];
j++;
}
return result;
}
Review
第一周阅读的英文文章:《The Key To Accelerating Your Coding Skills》
这里简要列出了自己感觉重要的内容(英语水平太差,可能有不到位地地方,望指正)。
-
阶段一:The Tutorial Phase(3-8 weeks od serious coding)
- 借助他人辅导(文档、书籍、视频)的方式获取所学编程环境下的特殊领域知识,并动手编程。
- 注:看视频并不是一个好方法
- 这一阶段最重要的是注重细节(error message):自己在动手编程过程中会由于或大或小的错误而导致程序出错,此时的 error message 尤为重要,阅读 error message 并根据 error message 定位自己代码中出错的地方,利用好搜索引擎自己解决问题。
- 努力自己发现问题并解决问题可以帮助自己快速成长,每一位大牛都是在经历过无数的失败后才能成功的
- the master has failed more times than the beginner has even tried.(大师失败的次数比新手尝试的次数都多)
- 借助他人辅导(文档、书籍、视频)的方式获取所学编程环境下的特殊领域知识,并动手编程。
-
阶段二:The Inflection Point(2-4 weeks with the right mentality)
- 逐步抛弃他人辅导的方式,并开始自己解决编程中遇到的问题,这些问题可能从来没人给出过答案。
- 在这一阶段,你的编程速度可能会比之前慢10到20倍,你可能会感觉“in the dark”,但是一定要保持正确的心态,这样才能征服“拐点”。
- 那么该如何征服“拐点”呢?
- For the rest of your life,go outside your limits every single day.
- 不要满足于安逸的现状,而要去超越自己:扩展自己的视野,解决超出自己技能范围的问题,增加自己的技能。
- 以Web开发为例,实际上会有两个拐点:
- “mastering CRUD”。跨越这一拐点的人
- 能够通过 Github 和技术博客的文档来整合第三方库去构建任何基于数据库驱动的 Web 应用;
- 算法和数据结构。跨越这一拐点的人可以完成:
- 写排序算法
- 实现/反转链表
- 理解并使用栈、队列、树来写程序
- 使用递归和迭代思想写程序
- “mastering CRUD”。跨越这一拐点的人
对于编程而言,特定领域的知识在宏观角度并不重要,所以不要执着于某一种语言,而要关注解决问题的思路。
不要盲目追求热点,当你找到并跨越了拐点,获得成功后,学习新东西并不困难。
自力更生:不要等待别人帮助你,主动出击,利用网络、阅读材料来克服困难。
Share
这里列出了自己对于 Java 中接口和抽象类的对比总结,可能有不足的地方,希望指出:
-
共同点:
- 都可定义方法、属性;
- 都可以没有抽象方法;
- 没有任何方法接口称为 Marker Interface,其目的是作为一种标志,如
Serializable
接口。
- 没有任何方法接口称为 Marker Interface,其目的是作为一种标志,如
- 都不能实例化。
-
不同点:
对比项 抽象类 接口 继承 单继承 可实现多个接口,但接口可继承多个接口 构造方法 可有 不可有 main()
方法可有、可执行 不可有 属性修饰符 自定义 默认 public static final
静态代码块 可有 不可有 方法 1.抽象方法必须是 public
(默认)或protected
:否则不能被子类继承;
2.可有非抽象方法;
3.可有静态方法1.默认 public abstract
;
2.JDK1.8后可有默认方法(default
修饰,不能私有,有方法体);
3.JDK1.8后可有静态方法;
4.JDK1.9后可有私有方法- 接口的默认方法:
- 引入:JDK1.8以前,在接口中添加一个方法,所有接口实现类都要去实现,而部分实现类即使不需要这一功能也必须有一个空实现。接口的默认方法就是为了解决这一问题。
- 接口的默认方法以
default
修饰(该关键字只能用在接口中)。 - 如果继承了多个接口,多个接口都定义了多个同样的默认方法,实现类需要重写默认方法不然会报错。
- 接口的私有方法:
- 引入:如果一个接口中多个默认方法中有大量代码相同时怎么办?由于默认方法不能私有化,所以无法抽取出重复代码,而私有辅助方法则是为了解决这一问题。
- 接口的默认方法:
Tips
在项目中通常会定义很多的常量,可以在常量类中使用接口来区分不同组的常量:
/**使用内部接口来把常量进行分组*/
public class Const {
/**
* 用户组
*/
public interface Role{
/**普通用户*/
int ROLE_CUSTOMER = 0;
/**管理员*/
int ROLE_ADMIN = 1;
}
/**
* 购物车组
*/
public interface Cart{
/**购物车选中状态*/
int CHECKED = 1;
/**购物车未选中状态*/
int UN_CHECKED = 0;
/**库存数量限制失败,用于返回给前端*/
String LIMIT_NUM_FAIL = "LIMIT_NUM_FAIL";
/**库存数量限制成功,用于返回给前端*/
String LIMIT_NUM_SUCCESS = "LIMIT_NUM_SUCCESS";
}
}