称球问题
- 12个一模一样的球,其中有一个坏球,或重或轻。问如果3次把此球找出
- 分3组每组4个球,第一次两两一称,最坏情况,天平不平衡。天平平衡的话很好处理,读者可以自己思考。
- 然后,将左侧的3个球拿下,把右侧的3个球放到左侧,再把底下的3个好球放到右侧。
- 进行枚举:天平可能出于3种状态,没有变化,变平衡,以及发生反向倾斜。
- 没有变化:很简单说明拿下去的3个球是好球。那么可以知道坏球只可能在天平上没动的两个球里,最后一次测出即可。
- 变平衡:说明3个坏球被拿下去了!呵呵,天平上所有的都是好球,且知道坏球是轻是重(从拿下去的3个球所在侧是偏重还是偏轻可以判断出来)。这样随便选俩一测即可。
- 反向倾斜:说明一个很关键的问题,就是坏球从一侧挪到另外一侧了,然后我们又可以知道拿3个球从一侧挪到了另外一侧,类似于变平衡的情况,找到坏球是重还是轻,然后一次测出。
- 老鼠问题
- 有1000瓶水,其中有一瓶有毒,小白鼠只要尝一点带毒的水24小时后就会死亡,至少要多少只小白鼠才能在24小时时鉴别出那瓶水有毒?
- 将瓶子编号,然后将编号表示成二进制,比如3就是0000000011,10位二进制对应10只老鼠,为1的喝为0的不喝
- 栈,push,pop,min操作
- 1.使用链表组织栈,每次push将新成员改为链表头,操作o(1);
- 2.每次pop将链表头弹出,第二个成员作为链表头,操作o(1);
- 3.如何求最小值?
- 这个问题要在常数内时间解决的话需要将这个链表做一个扩展,就是从空栈开始,每次push一个元素x后,获得当前最小值min(top担不pop);比较x与min,如果x<min 那么继续push x,表示pushx后的当前最小值为x;否则push min;
- 这样的扩展导致正常的push操作需要弹出当前最小元素和栈顶元素,同理每次pop的时候也是弹出两个。这样保证min的值始终是当前的最小。
- n条线最多把平面分成多少份?那n个面最多把空间分成多少份?
- (1)一维情况:一条直线上有n个点,显然把这条直线分成n+1段。
- (2)二维情况:即考虑平面上n条直线最多分得的平面块数。直线数为零时
- 有一个面,第k条直线与最多与前k-1条直线都相交,产生k-1 个交点,由(1)得这k-1个交点把这条直线分成k段,每段都使面的块数加1,那么n条直线最多分得的平面块数为1+1+2+3+...+n=(n+1)n/2+1。
- (3)三维情况:用N个面切割一个空间,求最多切得的空间的个数。没有面时有一个空间,第k个面与前k-1个面相交产生k-1条交线,把这个面最多分成k(k-1)/2+1个面,每个面新产生一个空间。
- 故用N个面切割一个空间,切得的空间的个数为:1+1+2+4+7+...+(N(N-1)/2+1)=N+1+(1*2+2*3+3*4+4*5+...+N(N-1))/2
- 其中1*2+2*3+3*4+......N*(N-1)={1^2+2^2+3^2+......(N-1)^2+N^2}-
- {1+2+3+4+......+N-1+N}=(2N+1)(N+1)N/6-N(N+1)/2
- 带入上式化简得到(N^2-N+6)(N+1)/6
- n*n的棋盘,每个格子上有一个数,要你从左上角出发,每次向右或向下走一步,最后走到右下角。问怎么找到一种走法,使得路径上的数的总和最大?
- 状态方程 f(i,j) = max(fi-1,j),f(i,j-1));
- 边界条件 f(0,0) = a[0][0];
- 如果是两个人走,每个人经过一个格子以后,那个格子里的数就变为0,那么怎么使两个人的总和最大?
- 甲随机走了一条路径 乙走最路径,求最大值
- <h3 dir="ltr">最长上升/不降子序列N LOG(N)复杂度算法。</h3>
- 我们先来看一个例子
- 4 1 3 2 5 11 9 10
- 正常的思路是 定一个数组F[] 表示包含这个数字的最长子序列长度,然后每到一个数字a[i],找到比这个数小的第j个数a[j],且F[i] =max{ F[j]+1 };
- 算法复杂度0(n^2).
- 如何来优化这个问题呢,
- 就是说如果让你找a[j]的时候更快,这里有个思路可以这样考虑:
- 定义一个数组C[] ; C[i] 记录长度为i的子序列的最大值。
- 则遍历到a[i]的时候 查看C[]中比a[i]要小的那个最大的数C[k](此处是效率的关键,用二分查找),C[k], 则F[i] =k+1; 然后C[F[i]] = min(a[i] ,C[F[i]] )。
- 模拟过程:
- 4 : F[0] = 1 ,C[1] = 4;
- 1: F[1] = 1, C[1] = 1;
- 3: (二分找到C[1]<2)F[2] = 1+1 = 2, C[2] = 3;
- 2: (二分找到C[1]<2)F[3] =1+1 = 2, C[2] = 2;
- 5: (二分找到C[2]<5)F[4] = 2+1 = 3, C[3] = 5;
- 11: (二分找到C[3]<11)F[5] =3+1 = 4, C[4] = 11;
- 9:(二分找到C[3]<9)F[6] = 3+1 = 4, C[4] = 9;
- 10: (二分找到C[4]<10)F[7] = 4+1 = 5, C[5] = 10;
- 按顺序输出C[] 1 2 5 9 10.
- <h1 dir="ltr">二叉树问题</h1>
- 在纸上写非递归中序遍历二叉树,如果不用栈只用父指针。
- <div dir="ltr">
- <table><colgroup><col width="*"></col><col width="*"></col></colgroup>
- <tbody>
- <tr>
- <td>void inOrder(Node* root)
- {
- stack s;
- while(root!=NULL&&!s.empty()){
- while(root!=null){
- <p dir="ltr">s.push(root);</p>
- <p dir="ltr">rootroot = root->left;</p>
- <p dir="ltr">}</p>
- <p dir="ltr">if(!s.empty()){</p>
- <p dir="ltr">s.pop(root);</p>
- <p dir="ltr">visit(root);</p>
- <p dir="ltr">rootroot =root->right;</p>
- <p dir="ltr">}</p>
- <p dir="ltr">}</p>
- }</td>
- <td>void inOrder2(Noder* root)
- {
- while(root!=null){ while(root-left!=NULL&&root->left->visited==false)
- {
- rootroot = root->left;
- }
- if(root!=null && root->visited==fasle)
- {
- visit(root);
- root->visited = true;
- }
- if(root->right!=NULL && root->right->visited==false)
- {
- rootroot = root->right;
- }
- else
- {
- rootroot = root->parent;
- }
- }</td>
- </tr>
- </tbody>
- </table>
- </div>
- 二叉树中找到中心点。(中心的定义:到其他点的距离之和最短)
- BST 删除节点
- 分为三种情况
- 1.如果删除节点无字节点,直接将删除节点用Null替换
- 2.如果删除节点只有左子树或者右子树,那么将删除节点的左(右)儿子的根代替他
- 3.如果删除节点有左右子树,那么找到左子树的最大节点(或者右子树的最小节点),将此节点代替删除节点即可。
- <h1 dir="ltr">找出二叉树上任意两个结点的最近共同父结点。</h1>
- 1.问有没有父指针
- 2.没有父指针
- 采用后序遍历的方法;注意在一条路径上的情况,那么上面的就是下面的父节点。
- 后序思路
- 后序时候如果访问到了A且则返回1;回溯,
- 后序时候如果访问到了B且则返回2;回溯,
- 如果非A非B则返回0
- 每次访问节点本身时候已经获取左右子树的信息了,将返回值相加看是否=3如果为3此节点就是最近祖先。
- 如果未发现则继续回溯。
- 怎么判断两个链表是否相交?怎么判断链表是否有环?
- <p dir="ltr">求两个单链表是否相交,如果相交,求出交点</p>
- <p dir="ltr">将链表2接在链表1后面,判断链表是否有环,如果有,则相交,最后,当然不要忘记恢复原来状态,去掉第一个链表到第二个链表头的指向。</p>
- <p dir="ltr">判断交点d2:分别求链表1,2的长度x,y,假设x>y,则让链表1先前进x-y部,然后两个链表同时单步前进,并比较地址,如果相等,则为交点,返回。</p>
- <p dir="ltr">2求两个链表是否相交,如果相交,求出交点(存在环)</p>
- <p dir="ltr">a)链表1单步前进,链表2双步前进,当链表2的next指针等于链表一的当前地址时,两者相交</p>
- <p dir="ltr">b)求交点,从a中的一点,将换断开,逆序链表1,此时相当于生成3个新的链表,只要求出这三个链表的交点,链表1还原,再判断生成的两个不同交点,是否在链表2上</p>
- 猴子搬香蕉
- 前面每前进1米,就要3趟,也就是吃掉3个香蕉;当然不可能50米全部这样,因为没有150个香蕉够吃^_^
- 这就需要找到一个点,当小猴子拿香蕉时能拿最多的香蕉(<=50),这样它可以一次到家,不用再往返。
- 设Y为要求的香蕉最大剩余数,X为要求的那个点(X米),可以列出方程式:
- 1. Y=(100-3X) - (50-X)
- 2. (100-3X)<=50
- 很容易求出Y=16
- 多边形面积
- 最好的解法 向量积叉乘
- 多矩形求面积算法
- 算法:单个矩形面积好求,但多个矩形进行重叠,这样形成的区域没有规律性,面积不好求。既然整体面积难求,就局部的进行求解(离散思想)。
- 对于输入的所有矩形,我们存储每个矩形的信息(对角的点坐标,存于rec数组中,两对角点为(rec0,rec1),(rec2,rec3)),然后定义两个一维数组x和y,用来存储所有矩形的所有的横坐标和纵坐标(每个矩形有两个横坐标和两纵坐标),之后对x和y中的元素分别进行升序排序,这样x和y中的坐标的依次组合能将平面分为多个区域。再定义一个二维数组flag。对于一个矩形((rec0,rec1),(rec2,rec3)),我们要找到一个x[i]和一个y[j],使它们满足x[i]>=rec0&&x[i]<rec2&&y[j]>=rec1&&y[j]<rec3,那么我们可以知道由x[i+1]->x[i]为横向,y[j+1]->y[j]为纵向所围成的区域在这个矩形中,此时,我们将这个区域的标置记为flag[i][j],并置flag[i][j]=1。
- 那么这块区域的面积s=flag[i][j]*(x[i+1]-x[i])*(y[j+1]-y[j]);
- 当我们沿着x和y数组顺序进行查找,并置相应的flag为1,而其它的flag为0(表示这样的区域没有被矩形覆盖,那么上式的s值为0),这样,将平面内所有离散后的区域的s加起来,就是我们要求的矩形并的面积了。
- 博弈问题
- 囚徒问题1
- <p dir="ltr">两个嫌疑犯(A和B)作案后被警察抓住,隔离审讯;警方的政策是“坦白从宽,抗拒从严”,如果两人都坦白则各判8年;如果一人坦白另一人不坦白,坦白的放出去,不坦白的判10年;如果都不坦白则因证据不足各判1年。在这里,博弈者就是两个嫌疑犯,他们每个人都有两个选择,即坦白和不坦白。</p>
- 如果是你你会如何选择?
- 从个人的角度,A会做如下考虑:如果B不坦白 那么我坦白 不会被判,不坦白还会判1年,不划算;如果B坦白,我坦白只会被判8年,不然会被判10年;所以我还是坦白吧!
- B同时也是这么想的;所以A、B各被判了8年。
- <p dir="ltr">人类的个人理性有时能导致集体的非理性。</p>
- 囚徒问题2
- 有100个无期徒刑囚徒,被关在100个独立的小房间,互相无法通信。
- 每天会有一个囚徒被随机地抽出来放风,随机就是说可能被抽到多次。
- 放风的地方有一盏灯,囚徒可以打开或者关上,除囚徒外,没有别人会去动这个灯。每个人除非出来防风,是看不到这个灯的。
- 一天,全体囚徒大会,国王大赦,给大家一个机会:如果某一天,某个囚徒能够明确表示,所有的囚徒都已经被放过风了,而且的确如此,那么所有囚徒释放;如果仍有囚徒未被放过风,那么所有的囚徒一起处死!
- 解法
- 有一个平均100*100 =10000天的算法:
- 编号1-100,1号负责开灯,2-100号负责关灯,且每人只能关一次;1号记下关灯次数。
- 如果关灯次数达到99次则他们就可以出笼了。
- 也就是说每个人大概随机到100次出来。大概10000/365 =30年左右。
- 囚徒问题3
- 有100个囚犯关在牢里,国王打算给他们一个机会,于是给他们一个看似不可能完成的任务:
- 让100个人每人头上戴一顶帽子,每顶帽子上随机的写上一个数字,数字的范围在0-99之间,囚犯们只能看到别人的帽子上的数字,看不到自己头上的数字。现在,国王要求他们每人同时写一个数字(无法知道别人写的数字,而且不得用任何方法提供信息给别人),如果100个人当中至少有一个写对了自己头上的数字,那么全体获释,否则全体杀头!在这之前给他们一点时间,让他们讨论一个方案。请问如果您是其中一个囚犯,您能想出一个100%获释的方案吗?请说说您的方案是什么?
- 解法:利用同余定理
- if(a = b (mod p) and c =d (mod p))
- 则有 a+b = c+d (mod p) a-b = c-d(mod p) a*b = c*d (mod p)
- 所以对于y[i] = i- T[i] ( mod 100 )T[i]为第个人看到所有的其他人的编号之和;
- 有y[i]-a[i] = i-S(mod 100); (因为a[i] = a[i](mod 100 ));
- 看右边 如果i取0- 99 则必存在某个特定的i
- 有i = S(mod p);
- 因此 i-S(mod 100) = 0; 则y[i]-a[i] (mod 100) = 0;
- 很显然 y[i] = a[i] (mod 100);
- 也就是说 只需要让每个人填写的数字为i-T[i] (mod 100)则能够必中一个。
- (一)巴什博奕(Bash Game):
- 只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个.最后取光者得胜.
- 显然,如果n=m+1,那么由于一次最多只能取m个,所以,无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,后者取胜.因此我们发现了如何取胜的法则:如果n=(m+1)r+s,(r为任意自然数,s≤m),那么先取者要拿走s个物品,如果后取者拿走k(≤m)个,那么先取者再拿走m+1-k个,结果剩下(m+1)(r-1)个,以后保持这样的取法,那么先取者肯定获胜.总之,要保持给对手留下(m+1)的倍数,就能最后获胜.
- 威佐夫博奕(Wythoff Game):有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
- 这种情况下是颇为复杂的。我们用(ak,bk)(ak ≤ bk ,k=0,1,2,...,n)表示两堆物品的数量并称其为局势,如果甲面对(0,0),那么甲已经输了,这种局势我们称为奇异局势。前几个奇异局势是:(0,0)、(1,2)、(3,5)、(4,7)、(6,10)、(8,13)、(9,15)、(11,18)、(12,20)。
- 设 (a[k],b[k]) ,a[k]<b[k] ;A[k-1],A[k]-1是离a[k]最近的奇异局势,那么 如果(c[k]=a[k]-a[k-1],d[k] = b[k]-b[k-1]) 是奇异局势那么,a[k],b[k] 肯定不是奇异局势所以a[k],b[k]是个奇异局势
- 集合问题
- 现在有一个数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数。
- 思路 类似芯片比较问题,采用两两比较的方法,缩小搜索空间。
- 一个出现了超过1/2的数的性质是:
- 每次删除最多删除1/2N 个目标数;剩下的数中还是目标数多于1/2N;
- 任意组成2元组(a,b);最后一个剩下的不做处理保留到下一轮就可以了
- 如果 a=b 那么随便删除一个;
- 如果a!=b 那么将两个都删除;
- 如果只剩下一个那么这个数就是正解。
- 找明星的问题:明星指所有人都认识他,但是他谁都不认识。在n个人里找明星。
- (选两个人 问 甲是否认识乙,认识则甲不是明星,不认识则乙不是明星,收敛速度n/2)
- 最后找到一个人,那么复杂度为O(n)
- 寻找中位数
- 5分法求中位数 5个一组,然后每组的中位数组成新的序列 递归查找。
- 21根电线杆问题
- 假设楼下的电线杆编号后进行划分
- {1} {2,3} {4,5,6},{7,8,9,10},{11,12,13,14,15},{16,17,18,19,20,21}
- 也就是6个区间,每个区间数目均不等
- 将区间内的电线杆用电池串联
- 上楼顶 两两用灯泡互联
- 找出 1,2,3,4,5,6 根电线杆的所属区间对应的接口
- {a1} {a2,a3} {a4,a5,a6},{a7,a8,a9,a10},{a11,a12,a13,a14,a15},{a16,a17,a18,a19,a20,a21};
- 然后进行如此划分
- {a1,a2,a4,a7,a11,a16} {a3,a5,a8,a12,a17} {a6,a9,a13,a18} {a10,a14,a19} {a15,a20} {a21}
- 将区间内的元素用电池串联起来;
- 到楼下来,很显然,f(a21)可以确定,f(a1)可以确定,
- 根据{a15 ,a20 } 与{m,n} 关联 则我们确定对应关系即可。
- 假设通过第一次测试我们发现m属于{11,12,13,14,15} , n属于{16,17,18,19,20,21}
- 则可以确定f(a15) = m, f(a20) = n 反之同理。
- 其他的依次类推,找各自对应集合既可以确定所有的对应关系。
- 网络
- OSI(Open System Interconnection,开放系统互连)7层模型:
- 物理层——网线和接口
- 数据链路层——数据帧 在不可靠的网络上传输数据
- 网络层——进行数据的打包,将网络地址翻译成物理地址,进行包的发送,会进行路径选择。
- 传输层——TCP/IP UDP 将下层数据进行分段传输,使得数据能够满足要求地抵达目的地。
- 会话层——发起协议://地址:端口号访问请求与应答 建立数据传输通路
- 表示层——数据解析成图片or 声音 or 视频等
- 应用层——QQ ftp Internet
- TCP/IP的3次握手
- 进程间相互通信方式
- 用于进程间通讯(IPC)的四种不同技术:
- 1. 消息传递(管道,FIFO,posix和system v消息队列)
- 2. 同步(互斥锁,条件变量,读写锁,文件和记录锁,Posix和System V信号灯)
- 3. 共享内存区(匿名共享内存区,有名Posix共享内存区,有名System V共享内存区)
- 4. 过程调用
- CMMI的分级
- 1.完成级 小作坊,能够完成一个软件,但无法保证能完成下一个,对人依赖很大。
- 2.管理级 加入管理成分,有计划和流程的实施项目。
- 3.定义级 根据标准定义自己的标准和流程,GB GJB,
- 4.量化管理级 增大管理粒度,量化管理的各个流程,可测量,最后可以定量的评价管理效果。
- 5.优化级 持续改进 不但可以完成,根据过程的量化反馈,可以优化项目的执行,出现问题后能够及时处理以及改善。