- Algorithm。主要是为了编程训练和学习。每周至少做一个 leetcode 的算法题(先从Easy开始,然后再Medium,最后才Hard)。进行编程训练,如果不训练你看再多的算法书,你依然不会做算法题,看完书后,你需要训练。关于做Leetcode的的优势,你可以看一下我在coolshell上的文章 Leetcode 编程训练 - 酷 壳 - CoolShell。
- Review:主要是为了学习英文,如果你的英文不行,你基本上无缘技术高手。所以,需要你阅读并点评至少一篇英文技术文章,我个人最喜欢去的地方是http://Medium.com(需要梯子)以及各个公司的技术blog,如Netflix的。
- Tip:主要是为了总结和归纳你在是常工作中所遇到的知识点。学习至少一个技术技巧。你在工作中遇到的问题,踩过的坑,学习的点滴知识。
- Share:主要是为了建立你的影响力,能够输出价值观。分享一篇有观点和思考的技术文章
打卡地址
35. 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
示例 1:
输入: [1,3,5,6], 5 输出: 2
示例 2:
输入: [1,3,5,6], 2 输出: 1
示例 3:
输入: [1,3,5,6], 7 输出: 4
示例 4:
输入: [1,3,5,6], 0 输出: 0
这道题的考点是二分查找法,而且是在正常的二分查找法上进行了一点延伸,正是这点延伸,把我弄蒙了。
public static int binarySearch(int[] arr, int target) {
if (arr == null) {
return -1;
}
int start = 0;
int end = arr.length - 1;
while (end >= start) {
int middle = (end - start)/2 + start;
if (arr[middle] == target) {
return middle;
} else if (arr[middle] > target) {
// 目标值小于中间值.
end = --middle;
} else if (arr[middle] < target) {
// 目标值大于中间值.
start = ++ middle;
}
}
return -1;
}
正常的二分查找法,如果循环到最后,end小于start,说明数组中不包含该元素,直接返回-1。而该题除了要考虑包含元素的情况,还要考虑不包含时,元素应该在的位置。
既然跳出循环了,那么可以确定
特殊情况1:如果target小于数组中所有值的时候,start = 0 end = -1
特殊情况2:如果target大于数组中所有值的时候,start = arr.length end = arr.length - 1
任何情况结果都是 start = end + 1
而最后一次循环时的middle值也肯定等于 最后一次的start,因为最后一次循环时 无非两种情况,一种start = end,一种 start = end - 1
也就是说
target 大于 arr[start],start = start + 1 ,而且肯定,target 小于 start + 1(除了特殊情况2),返回start
target 小于 arr[start],start不变,而且肯定,target 大于 start - 1(除了特殊情况1),返回start
所有说,无论什么情况最后都是返回start
public static int binarySearch(int[] arr, int target) {
if (arr == null) {
return -1;
}
int start = 0;
int end = arr.length - 1;
while (end >= start) {
int middle = (end - start)/2 + start;
if (arr[middle] == target) {
return middle;
} else if (arr[middle] > target) {
// 目标值小于中间值.
end = --middle;
} else if (arr[middle] < target) {
// 目标值大于中间值.
start = ++ middle;
}
}
return start;
}
PRG设计(Post/Redirect/Get)
一种防止web表单重复提交的设计模式。
post方式表单提交,后台成功后,返回302跳转,把用户的前端页跳转到GET请求,把刚刚POST的数据给展示出来。
目前在做一个微信小程序中的签到功能,需求是:每个用户一天签到一次,然后将签到状态存储在缓存中,只有当天有效。
key使用 “isSignIn” + userId 的方式存储,这样能保证每个用户拿到不同的标识,value为true
小程序中的缓存没有失效时间这个设置,所以也就没办法保证这个缓存只在当天有效,如何实现呢?
参考了这篇文章:微信小程序--缓存的二次开发封装
所以在存储的时候除了正常的 key vlue存储之外,再存储另外一个 键值对,用来存储当前日期(或者过期时间)
例如:
isSignIn_64521:true
isSIgnIn_64521_deadtime:2019-05-20
第二个键值对标识,key为isSIgnIn_64521的缓存,只有在2019-05-20才有效。
var dtime = '_deadtime';
/**
* 存.
* @param k
* @param v
*
* 比如:今天是2011-01-01
* k是 loginName, v是 张三
* 首先
* wx.setStorageSync('loginName', '张三');
* 然后
* wx.setStorageSync('loginName_deadtime', '2011-01-01');
* 取的时候判断时间是不是2011-01-01,不是那么就代表缓存过期了,返回默认值或空.
*/
function put(k, v) {
wx.setStorageSync(k, v);
var today = new Date().Format('yyyy-MM-dd');
wx.setStorageSync(k + dtime, today)
}
// 取.
function get(k, def) {
// 存储日期.
var deadtime = wx.getStorageSync(k + dtime);
if (deadtime) {
var today = new Date().Format('yyyy-MM-dd');
// 如果不是当天.
if (today != deadtime) {
if (def != null && def != undefined) {
return def;
} else {
return;
}
}
}
// 是当天的直接获取.
var res = wx.getStorageSync(k);
if (res) {
return res;
} else {
return def;
}
}
// 移除.
function remove(k) {
wx.removeStorageSync(k);
wx.removeStorageSync(k + dtime);
}
module.exports = {
put: put,
get: get,
remove: remove
}
MySQL实战45讲-林奇-极客时间
分析器
分析器先做”词法分析”。你输入的是由多个字符串和空格组成的一条SQL语句,MySQL需要识别出里面的字符串分别是什么,代表什么。
MySQL从你输入的"select"这个关键字识别出来,这是一个查询语句。它也要把字符串"T”识别成“表名T”,把字符串"ID"识别成“列ID”。
做完了这些识别以后,就要做”语法分析”。根据词法分析的结果,语法分析器会根据语法规则,判断你输入的这个SQL语询是否满足MySQL语法。
注:该阶段就能判断,是否包含指定字段(如果某个表中没有该字段,会在该阶段发现,并抛出异常)
优化器
优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。比如你执行下面这样的语句,这个语句是执行两个表的join:
mysql> select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20;
- 既可以先从表t1里面取出c=10的记录的1D值,再根据ID值关联到表t2, 再判断t2里面d的值是否等于20。
- 也可以先从表t2里面取出d=20的记录的ID值,再根据ID值关联到t1,再判断t1里面C的值是否等于10。
这两种执行方法的逻辑结果是一样的,但是执行的效率会有不同,而优化器的作用就是决定选择使用哪一个方案。
执行器
开始执行的时候,要先判断一下你对这个表 T有没有执行查询的权限
如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。
没有索引,那么执行器的执行流程是这样的:
- 调用InnoDB引擎接口取这个表的第一行,判断ID值是不是10,如果不是则跳过,如果是则将这行存在结果集中;
- 调用引擎接口取"下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。
- 执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。
至此,这个语句就执行完成了
有索引,执行的逻辑也差不多。
第一次调用的是”取满足条件的第一行”这个接口,之后循环取”满足条件的下一行”这个接口,这些接口都是引擎中已经定义好的。