ARTS是什么?
Algorithm:每周至少作一个leetcode的算法题;
Review:阅读并点评至少一篇英文技术文章;
Tip:学习至少一个技术技巧;
Share:分享一篇有观点和思考的技术文章。java
LeetCode 115. Distinct Subsequencesnode
思路分析
程序员
题目的意思是求出一个字符串(子串)在另外一个字符串(主串)的子序列中出现的次数,再换个说法,主串中有多少子序列是等于子串的。一个字符串匹配问题,咱们固然能够考虑到暴力求解,思路大概就是,咱们假设主串长度是 n,子串长度是 m,咱们在主串中选出全部的长度为 m 的子序列,看这些子序列有多少是等于子串的,这样的话时间复杂度是很高的,其实就是组合问题的时间复杂度,是指数级别的。因而要考虑动态规划,基本上和字符串匹配相关的题目均可以考虑试着画画表格,这道题拿到手我一开始想到要用动归,状态的定义也不是太难,就是 dp[i][j] -> 子问题 s[0...i], t[0...j] 的答案
,可是这个递推方程想了挺久的,由于想不出来还不停地试着从新定义状态,最后画表格总结规律,慢慢地就出来了;通常这样的字符串匹配问题,对于当前的问题,也就是 dp[i][j]
,咱们能够去观察相邻的子问题 dp[i - 1][j - 1], dp[i][j - 1], dp[i - 1][j]
,字符串匹配问题,咱们是一个个字符对比考虑,所以这里也只会有两种状况,当前比较的字符相等和当前比较的字符不相等,若是说相等,s[i] == t[j]
,这时咱们须要考虑的子问题是 s[0...i-1], t[0...j-1]
,对于这个子问题的答案咱们已经计算过了,是 dp[i - 1][j - 1]
,可是这尚未完,这只能算是一部分答案,还须要考虑的子问题是 s[0...i-1], t[0...j]
,也就是去掉当前 s 中的字符 s[i]
,答案也已经计算过了,就是 dp[i][j - 1]
,不少人可能会问,这么考虑会不会重复?其实不会,由于全部的当前问题不会去考虑子问题 s[0...i], t[0...j-1]
,也就会保证考虑的子问题不会重复,这么说可能很差理解,画个表格就会更好理解。若是说不相等,s[i] != t[j]
,这时咱们须要考虑的子问题就是 s[0...i-1], t[0,...j]
,直接点说就是,去掉主串当前考虑范围中的当前字符的解。算法
参考代码编程
public int numDistinct(String s, String t) {
if (s == null || t == null || s.length() < t.length()) {
return 0;
}
if (s.length() == 0 || t.length() == 0) {
return 1;
}
char[] sArr = s.toCharArray();
char[] tArr = t.toCharArray();
// dp[i][j] -> answer for subproblem: s[0...i] and t[0...j]
// if s[i] == t[j] -> dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]
// dp[i - 1][j - 1] means the count not consider s[i], which is s[0...i-1] match t[0...j-1]
// dp[i][j - 1] means the count consider s[i], which is s[0...i] match t[0...j-1]
// if t[i] != s[j] -> dp[i][j] = dp[i][j - 1]
int[][] dp = new int[sArr.length][tArr.length];
dp[0][0] = (sArr[0] == tArr[0] ? 1 : 0);
for (int i = 1; i < sArr.length; ++i) {
for (int j = 0; j < Math.min(i + 1, tArr.length); ++j) {
if (sArr[i] == tArr[j]) {
dp[i][j] = (j == 0 ? dp[i - 1][j] + 1 : dp[i - 1][j] + dp[i - 1][j - 1]);
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
return dp[sArr.length - 1][tArr.length - 1];
}
复制代码
两篇出于同一做者,观点鲜明,卓有见地的文章,讲的是编程当中的误区:
数组
The Greatest Developer Fallacy Or The Wisest Words You’ll Ever Hear?缓存
On The Value Of Fundamentals In Software Developmentbash
第一篇文章讲的是程序员耳熟能详的一句话 “我在须要的时候再去学习”,这句话本是没有错,由于计算机软件这个领域新技术层出不穷,不可能都学完,并且为了学习去学习也没有意义。可是如今的问题是,不少程序员把这句话当成了不去深刻专研和挖掘知识的借口,做者还给出了一个观点 “你不可能去学习你彻底不知道的东西”,怎么理解?假如说你只知道 Java Spring 这一个 Web 的框架,当你须要构建 Web 服务器的时候,你只会去考虑用 Java Spring,可是实际上,除了这个,还有 Python 的 Django,JavaScript 的 Express,Ruby 的 Ruby On Rails,这些都是 Web 框架,但它们适用于的场景不一样,上手难度不一样,适合解决的问题也不同,相对于 Java Spring,这些技术知识都是你不怎么了解,也不知道其优缺点,即便它们再好,对你来讲也等同于无。做者提出咱们应该成为一个 T 型人才,他同时也指出当你去深刻专研某个方向的时候,你会连带学到这个方向以外的不少东西,因此问题的解决方案就是,对于你感兴趣的东西,你要学的更深刻些,不要学在表面,固然相对于知识的积累,更重要的是对这个行业的热情,绝大多数的学习到最后是否有成效和收获都会归结为态度问题。服务器
第二篇文章讲的是基础知识的学习,做者给出了基础的定义,一个是从宏观来看,另外一个是从微观来看,从宏观上来看,好比数据结构和算法,操做系统,网络协议的知识,之因此是宏观上的,是由于这些东西每每是普适的,任何的技术都会基于此,举个例子,不论是 Java 中的 ArrayList,仍是 C++ 中的 Vector,Python 中的 list,JavaScript 中的 list,这些东西本质都是动态数组,只是表示的方式不同,你若是理解了数据结构和算法中的动态数组的相关知识和由来,这些你会学的很快,使用也会驾轻就熟,其余相关知识也同样。微观之因此是微观,是由于其落实到具体技术,好比对于 Java 的 ArrayList 的学习,你须要去熟悉相关的 API 文档,了解并熟练掌握其各类的常见 API 函数和相关的操做,这些东西能够帮咱们快速写代码,有时候不知道一个 API 或者内置函数,每每会大大影响咱们开发的效率。因此总结下就是宏观上的基础学习可以让你学的更快,微观上面的基础的学习会让你实现,写代码的效率更快,同时对比不一样技术之间的差别,达到举一反三的效果。网络
分享一个 Linux 上面挂载程序的指令,screen 命令,使用起来特别简单,通常步骤以下:
>$ screen
按 enter 键
>$ node ... (这里输入命令)
ctr + A (挂载)
ctr + D (退出)
复制代码
这周看极客上面的 HTTP 专栏,学习了一些网络的概念,以前彻底不知道,但又频繁见到的一些词汇如今有了概念了,算是扫盲吧,记录一下,巩固一下:
这周读了《清醒思考的艺术》这本书,书中给出了 52 个思惟误区,我觉的有些误区对于咱们这些程序员,或者说是想成就一番事业的人士很是有借鉴意义