几何结构
美杜莎之筏
有时候我们看那些好的作品,总觉得好,但有说不出是哪里好。 其实牛b的画家在绘图之前,都会把内容抽象成对应的几何图图形。如上图整个构图是有两个三角形,让画面保存了平衡。
那么当我们撸代码的时候,看到需求原型的时候,也应该先把内容抽象成某种结构,再从结构上搭建代码。
这种结构就叫做:“数据结构”
《数据结构+算法=程序》pascal作者出版,可见数据结构的重要性
线性表
相当于几何图形中的直线,是最基本的数据结构,是有序的,如学生档案。
数组
- 定义:编了号的固定大小单元。
- 优化:可以直接索引到具体的行,如arr = ['a','b','c','d'],找到d只需要 arr[3]直接索引访问
- 缺点:数据插入非常麻烦,会导致这个数据重新调整。
链表
- 链表的每一个节点只关心下一个节点内容。所以插入数据非常方便,如:a->b,b->c,c->d, 这时候如果插入e到b后面,只需要把b->指向e,e->指向c,就完成插入。
- 缺点:不能直接找到某一个元素,如想找到d,必须从a开始一个个往下找。
二叉树
在我们生活中到底是具体的数值重要,还是相对大小重要?
- 在生活中钱数值越大,当然越重要,但是在比赛中第一名永远是相对于其他对手,所以相对重要。
- 在计算机里是相对是最重要的。
因为计算机经常要做的就是:判断真假,比较大小,排序,挑选最大值。
- 先来的占据根部,以及靠近根节点较高位置,后来的相对靠下(同一方向子节点都必须补齐,才能继续往下发展子节点)
- 每个分支都和根比较大小,小的放左边,大的放右边。
例子
[3,5,-2,0,6]
最终只需要把二叉树上的内容,从左边往右依次取出即可。
在网站中,目录结构也是树形结构,如果我们找到一个网站后,要下载他所有内容,只需要通过二叉树来进行算法遍历。
锦标赛排序算法
高盛面试题:
假定有二十五名短跑选手比赛竞争金银铜牌,赛场上有五条赛道,因此一次可以有五个人同时比赛。比赛并不计时,只看相应的名次。假如选手的发挥是稳定的,也就是说如果约翰比张三跑得快,张三比凯利跑得快,那么约翰一定比凯利跑得快。最少需要几组比赛才能决出前三名?
对应成表格如下:
需要注意:输给a1的a2不一定都输给其他组的第一名的情况
方案1
- 找到第一名很容易,只需要a-e组各比一次共5次,比出的结果(a1,b1,c1,d1,e1)再比一次就能找到NO.1,共6次
- 找第二名,则需要把输给a的b1,c1,d1,e1和a2比较。 共1次
- 如果b1才是第一,则把剩下的 b2,c1,d1,e1,a2。共1次 最终是8次能找出前三名
方案2
- 找到第一名很容易,只需要a-e组各比一次共5次,比出的结果(a1,b1,c1,d1,e1)再比一次就能找到NO.1,共6次
- 把有可能参加2-3名的名单才列入比赛
- (1) 由于第6次找到No.1的时候,已经确定,d1,e1是排在第4,5名所有重新比较可以把他们忽略。
- (2) 剩下有可能做第二名的是 输给a1的a2,b1,c1(当然三个里面,除了赢得,剩下的可能是第三名)
- (3) 剩下有可能做第三名的是 输给a2后面的a3,b1后面的b2
这样只需要把a2,a3,b1,b2,c1一起比较一次,就能得出前三名, 第六次。
总结:
- 比较的时候,要善用已经生成的信息,前6次比赛已经列出前3名的候选。
- 要少做一些无用工,由于d1,e1已经是是确定不在候选,所以后面的比较不应该把d1,e1也放进去比较。
谷歌面试题:
如何设计一个地图功能,找到离当前最近的加油站?
-
确定信息: 首先我们假定汽车是通过gps定位,加油站的信息也是通过gps已经收集好的。由于汽车是移动的,所以算法需要足够的快才支持快速的响应。 -
距离计算。使用动态规划,找出单个搜索的最佳路径。 -
所有路线进行排序,然后推荐给用户最优的几个方案: 比如深圳附近有100的加油站,每一个加油站都有对应的方案,要找到最近,则需要对所有加油站的路线进行排序,取最前面,则每次排序的量级会很大。这里关键在于用户只关心前几名,不关系后面的内容。可以使用“堆排序”,优化排序。 -
全局优化:比如A用户在Z的位置找加油站的需求,跟B用户在Z位置找加油站的需求是一样的。所以每次查询后,都应该把推荐的信息记录存储下来,下次再次发起一样的请求,可以直接返回已经记录号的信息。
大数据思维:不能像过去那样,只把事情看成彼此独立事件,分开处理,而是把所有数据集中起来,全局优化
如何找中值问题
假如有一个巨大的数组(你可以理解成一串数字),如何用最有效的方法找到它的中值?
- 中值不是平均值。比如1,4,9,100,0 中值是4,其实就是中间位置的值。当然如果总长度是偶数,则有两个中值。
- “巨大”是指数据量很大的数据。
- “最有效”,要找最好办法
如有:[1,-5,3,7,1000,2,-10]
方案1 排序
- 直接顺序排序后是
- [-10,-5,1,2,3,7,1000]
- 然后取中间的值是 2
方案2
利用堆排序可以只排到中间大就ok,节省一半空间。
方案2 划分
在数组里先随机取出一个值,然后与左右值比较,大于小于各分两边。如果左边等于右边则找到,如果一边大一边小,则取大的一边。再大的一边继续往下找,知道某一个值左边有没有值,或者右边没有值证明是中值。 比如:
- (1) 取出随机数1,分成两个数组,小于1 [-5,-10] A数组, 大于1[3,7,2,1000]B数组,这时候中值肯定在B数组里面,不在A数组-5,-10和1
- (2) 在数组B [3,7,1000,2]里面再取出随机数7,则小于7 [1,-5,3,2,-10]C数组, 大于7[1000]D数组。 那么中值肯定在C数组,不在7和1000.
- (3)那么有效数组就可以排除掉[-5,-10,1]和[7,1000],就只剩下[3,2],再套入3 发现还不是中间,再套入2,发现刚好在中间。 则2为中值