九章算法笔记 1.Introducing Algorithm Interview & Coding Style

Implement strStr

cs3k.com

http://www.lintcode.com/problem/strstr/

Returns the position of the first occurrence of string target in string source, or -1 if target is not part of source.

遇到这道题和面试官说什么,有什么要确认的么?cs3k.com

对性能有要求么?

–面试常见错误1:我知道有个算法叫KMP

–不应该扯KMP的原因,而应该从最简单的算法开始:

1.算法往往没那么难

2.用那么难得算法,写出不来咋办

3.用简单的算法,即使不能写全,写到完美,至少能得一部分分

4.所以我们要写一个O(m+n)的两个for的傻叉算法就可以了

面试常见错误2:Coding Style cs3k.com

screenshot-from-2017-03-05-21-39-17

–命名风格 s1, s2 神码鬼?

要用source, target

–if(){

}

一行也要用花括号, c++详见google coding style

–什么时候加空格?

1.二元运算符左右各一个space

2.++ — 不加space

3.分号右加左不加

常见错误3:没考虑corner case cs3k.com

screenshot-from-2017-03-05-21-39-17

要体现自己细心靠谱,考虑各种面试官都不一定能想到的情况:

1.检测空(字符串,集合….)

2.检测下标越不越界:

凡是返回下标的,都要检查越界不,万一返回-1呢?会不会返回大于n呢?

3.要有缩进

–如果问比O(n^2)更好的算法

Rabin-Karp算法:基于hash function的原理

–主动给出Test case而不是uni test????区别

null和空的情况啦

你真的会面试么? cs3k.com

–白纸上要写一遍

lintcode上面的N/A小于3是比较好的,自己动脑debug,不要提交错了再改

–吃透几道题?

看答案写出来的,过一周到两周要自己再做一遍

–面试不会就说不会么?

面试官是coworker, 程序员要有自己google然后搞定的能力

–面试官为难你?

追问是正常的,不要觉得面试官是傻逼

为什么要面试算法?算法面试难么? cs3k.com

算法难,算法面试不难,因为考察的范围很窄.

–为啥这些算法没啥用还考?为啥不写project呢?

1.45分钟内完成一段代码

2.主要考察写代码的能力,所以会考不太难想的算法,但是实现不太容易的算法

3.主要不是想题,而是写程序:像贪心法这种没有太大通用性的,考得很少

刷题的经验:cs3k.com

–总结类似题目,一道变一类

–给一类题目弄出个模板程序

排列与组合cs3k.com

搜索的复杂度

–构造每个答案的时间 * 答案的个数

子集这道题为:

=O( n * 2^n)

–permutation  排列

=O(n!  * n)

有时答案个数不确定的时候,假设S是所有答案的个数

= O(S  * n)

问时间复杂度,基本可以和面试官交流就ok了

找子集问题cs3k.com

http://www.lintcode.com/en/problem/subsets/

Given a set of distinct integers, return all possible subsets.

Example

If S = [1,2,3], a solution is:[ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]

img_1194

–从空集出发,怎样构造?

一层一层去想的,去搜索的,这种叫做宽度优先搜索

–深搜有什么好处呢?

1.宽搜需要记录上一的状态,而深搜只需要记录上一状态。

2.如果面试官要求打印出来就行,又因为print是不占用空间的,所以深搜空间更优。

深搜

DFS即深度优先搜索,本质是回溯,是back tracking。

是后悔的过程,是撞了南墙后悔,再回到之前的状态。

其中{1,3}之后不能加2,是因为不能重复,因为{1,2, 3}和{1, 3, 2}一样

–避免重复不应该采用的方法为:

记录所有状态,然后回去查查,如果重了,就不加。

因为这样的话,时间复杂度从O(n!)变成O(n^n)

–应该采用的方法为选代表:

{1,2,3} {1,3,2} {2,1,3} {2,3,1} {3,1,2} {3,2,1} 

选代表的原则是:看脸,看谁帅谁顺眼选谁

{1,2,3}明显比较顺眼,因为有规则的增序,所以最后的路径就是如图上的粉箭头的指向。

递归cs3k.com

递归的本质是由大化小

–递归需要主要的问题:

递归是不是太深?在找子集问题上,不会太深,因为解一共有(2^n)个,如果n太大,解根本解不完。所以n一定是一个很小的数,n不大,递归也就不会太深。

–开始new一个空的子集

并且所有函数先解决corner case,做异常检测。

此题即解决0和null的问题。

–这道题还需要排个序,因为题目有要求

–递归的是一个function叫func(A)自己调用自己,我们在这里构造一个helper()函数

这个helper的参数呢,需要subset和可加的nums以及传答案的results以及为了避免重复而传进去的最后一个数的index(可以不传,这里传进去比较直观)

递归三要素

1.递归的定义:

接受什么参数,返回什么值,做了什么事儿

这里是找到所有以subset开始的集合,然后丢到result里面

ps:一行不要超过80到100个字符,所以参数多要分行

2.递归的拆解,怎么拆成更小的?

{1}     拆成 {1, 2}  {1, 3}  {1, 4}

ps:soft copy 要注意,soft copy是reference

subset = [];

results.add(subset);

results.add(subset);

results.add(subset);

subset = 1;

最后results: [1]   [1]   [1]

所以results.add{new一个出来的deep copy}

–函数调用后全部删除:

四大步骤:1. add{new一个空的出来}   2.加一个数  3.调用自己的小任务   4.删这个数

3.递归出口(什么时候不忘下递归了,可以直接找到答案退出)

–怎么看一个题目是深搜

有all possible字样的

写程序不是从上往下写,先写思路。

重点是bug free和速度

课后小视频之Subsets IIcs3k.com

看到all 字样,很容易是深搜

如何去重呢? 错误的想法是找到所有的答案,然后再看重复与否, 去掉.

比如[1,1,1,1,1,1] 只有7个子集,但是有写2^6个答案, 浪费时间

应该开始就不加入重复的

helper应该是private的

[1,2,2′]什么时候我们应该避免重复呢?

遇到2’的时候,如果2’之前有2,而且2没有在已有的集合中,此时加2′,就会重复

Screenshot from 2017-03-13 21-55-16.png

课后小视频之字符串查找之 Rabin Karp 算法 cs3k.com

这种算法的本质是用hash function把字符串之间的比较由O(m)长的时间变为O(1)

hash function

哈希表就是个大数组, hash function是个把字符串, float, double, int都转换到数组一个位置的mapping.

ABCDE

= (a * 31^4 + b * 31^3 + c * 31^2 + d * 31 + e) % 10^6

其中31是个经验值, hash size 10^6, 越大越不容易重, 越小越容易冲突, 所以选一个不越界的大的值

如果用int的话, 保证 31 * 10^6不越界.

如果用10^8的话, 就需要long int 了

key到value唯一, 反之不成立.  abc 只等于123, cde也只等与123, 但是123对应两个string

Screenshot from 2017-03-13 22-31-26.pngScreenshot from 2017-03-13 22-32-09

开始要处理null和length=0

22行的power要边乘边模,防止越界.

42行负数的情况最好不要直接模, 因为不同的语言负数的模结果不同,所以手动if一下

48行, hash code一样串不一定一样,hash code 不一样的串一定不一样, false positive, 所以再比较一次

猜你喜欢

转载自www.cnblogs.com/jiuzhangsuanfa/p/9895638.html