《剑指offer》笔记-第5章(2)

来源:互联网 发布:传奇霸业战神装备数据 编辑:程序博客网 时间:2024/05/22 18:23

面试题42:连续子数组的最大和

      输入一个整型数组,数组里有正数也有负数。数组中一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度是O(n)。例如,数组为{1,-2,3,10,-4,7,2,-5},和最大的子数组为{3,10,-4,7,2},输出位18。

测试用例:

      功能测试:数组中有正数也有负数;数组中只有正数;数组中只有负数;

      特殊输入:数组为null;

分析:

      分析累加子数组的规律{1,-2,3,10,-4,7,2,-5}:

      1.    维护两个值,当前累加的子数组和nCurSum、最大的子数组和nGreatestSum,初始化为0;

      2.    第一步加1,nCurSum为1,nGreatestSum为1;

      3.    第二步加-2,nCurSum为-1,nGreatestSum为1;

      4.    第三步应加上3,但此时nCurSum<=0,说明如果相加,得到的结果比当前的数字还要小,说明从第一步开始累加小于从第三步开始累加,则抛弃之前的累加,nCurSum为3,nGreatestSum为3;

      5.    第四步加10,nCurSum为13,nGreatestSum为13;

      6.    第五步加-4,nCurSum为9,nGreatestSum为13;保存之前的13是因为这有可能是最大的子数组和;

      7.    第六步加7,nCurSum为16,nGreatestSum为16;

      8.    第七步加2,nCumSum为18,nGreatestSum为18;

      9.    第八步加-5,nCurSum为13,nGreatestSum为18;

      动态规划法:

      10.  f(i)表示以第i个数字结尾的子数组的最大和。函数要求出的是max[f(i)]。

      11.  当i= 0或者f(i-1)<=0时f(i) = pData[i];

      12.  当i!=0并且f(i-1)>0时,f(i) = f(i-1) + pData[i]

      13.  F(i)对应上一方法的nCurSum,max[f(i)]对应上一方法的nGreatestSum;

      处理无效输入:

      14.  输入数组是null、数组长度小于等于0,返回0,并且定义一个全局变量标记输入无效(定义全局变量是为了区别无效返回0和最大值是0)

面试题43:1~n整数中1出现的次数

      输入一个整数n,求1~n这n个整数的十进制表示中,1出现的次数。例如输入12,1至12的整数中,包含1的有1/10/11/12,1一共出现5次。

测试用例:

      功能测试:输入0/1(边界);输入其他整数;

      性能测试:输入较大的数字10000等:

分析:

      1.    得到每位数字的方法是:循环对10求余,除以10替换原数,直到原数等于0;

      2.    从1到n,对每一个数字,判断每一位数字是否是1,累加1的个数;对于数字n,n有O(logn)位,判断每一位是否是1的复杂度是O(logn),那么算法复杂度是O(nlogn),效率不高;

      分析数字规律:

      3.    例如1~21345,分成两段,一段是1~1345,一段是1346~21345;

      4.    对于1346~21345,1出现在最高位是10000~19999,一共10000次,如果最高位是1即1~11345,则最高位1出现是10000~11345,出现次数是1345+1;

      5.    对于1346~21345,分析1出现其他位的情况,由于最高位是2,拆分为1346~11345和11346~21345;每一段后4位数字,选择其中一位是1,其余3位可在0~9任意选择,排列组合一共出现的次数是2*4*1000=8000。

      6.    对于1~1345,可用步骤3/4/5的方法,递归求出;

      7.    每次去掉最高位进行递归,递归的次数和位数相同。n有O(logn)位,复杂度是O(logn);

 

面试题44:数字序列中的某一位的数字

      数字以0123456789101112131415……的格式序列化到一个字符序列中。写一个函数,求出任意第n位对应的数字(从第0位开始计数)。

测试用例:

      边界测试:输入0/1;

      功能测试:输入其他整数;

分析:

      1.    例如,输入1001,即求序列0123456789101112……的第1001位的数字;

      2.    0~9这10个数字,是前10位;10~99这90个数字接下来的2*90=180位;100~999这900个数字,是接下来的3*900=2700位;

      3.    1001位在三位数中的一个数中:1001>10,说明在一位数之后;1001-10=991>90,说明在两位数之后;1001-10-180=811<2700,说明在三位数中的一个;811=3*270+1,说明位于第270个三位数之后的一个数的中间位,即370的中间位即7。(100是第一个三位数,101是第二个三位数,100+270=370是第270+1个三位数)