磨刀不误砍柴工:取巧而已

问题1:输入任意整数序列,计算其最大子序列之和。例:-2,1,0,-1,3,-1,1,-2;结果应是3。

初始的想法可能会是计算所有的子序列S(i,j)之和,然后得出最大值,可能出现三种版本:O(N^3)、O(N^2)、O(N*logN)。

多想“最大子序列之和”,负数不能增加和值,和为负的子序列也不能增加和值,所以从头至尾计算子序列和,第一个值作为初始最大子序列和,如果遇见非负数或已计算出的最大子序列和非负,就可以抛弃负子序列了。

 

问题2:有很大数量的字符串序列(如用户名),其中有一个字符串重复次数超过总数的一半,请找出这个字符串。

初始的想法可能是统计每个字符串出现次数,然后找出重复次数超过总数一半的那个字符串,但若要求仅使用一个单位存储空间就束手了。

多想“重复次数超过总数的一半”,这个字符串比其他字符串出现次数的总和还要多,这个条件如此特别以致取巧罢了;依次读入字符串,前后两两判断是否相同,相同则给计数值加1,不同则给计数值减1(减到0就不用再减了,如果大于0就记住其中某个字符串),最后剩下的就是目标了。

这个题目和解法看似很不搭配,解出来的字符串未必就出现次数过半,但这个条件是由题目来满足的,取巧怎能面试出能力呢?

 

问题3:象棋中将帅不能照面(在一条竖线上),且限制在田字格内活动,给每个格子编号,打印将帅所有合法的相对位置,要求只能用1字节的内存。

这个题可用双重for循环轻易解决,但要求只能用1直接内存后就不容易了,因为现在大家的思维都很高级了。还好有参考答案,1字节有8位,每四位可表示0~15(超出我们的需求1~9),然后定义一些宏LeftGet、LeftSet、RightGet、RightSet,让前后四位遍历1~9形成双重循环即可。另一个思路,使用C编译器提供的结构struct{unsigned char a:4,b:4;};这样就可以直接使用变量a、b了,且只用了1字节。

 

问题4:连连看,连线拐弯不能超过两次,计算两个格子能否相消及棋局是否没有可消的了。

从某个格子出发,计算其横纵方向所能到达的格子(集合1可直线到达),对于所有能到达的空格子在次计算(集合2拐一次可到达),再对空格子计算一次(集合3拐两次可到达),如果另一个格子在这些集合中,则表示可以到达及相消,否则就不能或太绕了。每次可以对所有剩下的格子进行计算可判断是否还有可相消的格子对。

posted @ 2011-05-11 18:10 xlongwei 阅读(...) 评论(...) 编辑 收藏
xlongwei