看大神文章小结——微软等面试 27,28,29,30
2013-05-13 15:25
309 查看
大神 地址 :http://blog.csdn.net/v_JULY_v/article/details/6015165
27.跳台阶问题
题目:一个台阶总共有 n 级,如果一次可以跳 1 级,也可以跳 2 级。
求总共有多少总跳法,并分析算法的时间复杂度。
这一题 要结果 应该不难的。 就是 按顺序来。 先算 有0个 跳2级的情况。 再算 有1个跳2级的情况(位置 遍历前移。) 然后2个跳2级。。。。。。 递归计算。。 不过 毫无疑问 这个算法的复杂度 很复杂。。
先写个复杂的这个来看看:
。。我一开始想复杂了 其实 就是 f(n)=f(n-1)+f(n-2) 因为 在某一步。 可以选择跳一级 也可以选择跳2级。 跳一级 就是f(n-1) 2级就是 f(n-2) 。 这个就简单了。用递归能实现 而且 之前有一题 需求是 要求效率的 递归效率太低。 正推就ok了 就是 先算f(3) 得出后 再算f(4)...一直到 f(n) 一次循环就可以得出。
28.整数的二进制表示中 1 的个数
题目:输入一个整数,求该整数的二进制表达中有多少个 1。
例如输入 10,由于其二进制表示为 1010,有两个 1,因此输出 2。
这一题 如果 要求效率什么的 铁定是 移位 然后 与1 取与操作。 不停的移位 就ok了 算法没什么吧。。。
看了答案 思路是对的 不过 忽视了 负数。因为负数 会 补1. 换个思路 就是把1 左移 来与。 ok了。。
29.栈的 push、pop 序列
题目:输入两个整数序列。其中一个序列表示栈的 push 顺序,
判断另一个序列有没有可能是对应的 pop 顺序。
这个 题目 最简单的方法就是走一遍。 遍历第一个序列。 push 一个 判断 并且和第二个序列的比较。 如果相等 就pop 并且第二个序列的当前对象 移除。 继续判断当前。如果还相等 继续做这个操作。 一直到不相等了 就继续 push 。 如果 最后全部push完成 并且 还不相等。第二个序列还有值 就说明 是错的。
代码如下
30.在从 1 到 n 的正数中 1 出现的次数
题目:输入一个整数 n,求从 1 到 n 这 n 个整数的十进制表示中 1 出现的次数。
例如输入 12,从 1 到 12 这些整数中包含 1 的数字有 1,10,11 和 12,1 一共出现了 5 次。
分析:这是一道广为流传的 google 面试题。
这一题 应该 有点移位的思想来做。 但是 不是 移位操作,是对于十进制来操作。 仔细想想其实有点数学的那个 C 那个 组合更简单。就是在
m 中 取n 个有多少种取法。
1.获取这个数 有多少位。
2 假设5位 先计算 4位(9999 )里面有多少个1 就是 4中有一个1的个数*999(这里不应该是999 应该是 9*9*9 这是因为 每种组合的情况 其他位数都可以是 0到9 除了1之外的任何数字) 4位数中有2个1的个数 *2 *999 4位数中有3个1的个数*3*999 4位数很重有4个1的个数 * 4*999
3 再计算 从 10000 到给定数字的 有 1的个数。
当然 也可以 循环 从 1 一直到 给定的数字 一个个判断 不过 我估计 第一个效率要好很多。 2个代码都写一下 比较一下。
第一种 是大众 遍历方法。 写起来很简单 运算起来 。。。
第二种 快很多。非常多。 我的机器 第一种超过8位算不动了 电脑 第二种 一直到 越界了(long 类型) 都能 瞬间运算出来。
27.跳台阶问题
题目:一个台阶总共有 n 级,如果一次可以跳 1 级,也可以跳 2 级。
求总共有多少总跳法,并分析算法的时间复杂度。
这一题 要结果 应该不难的。 就是 按顺序来。 先算 有0个 跳2级的情况。 再算 有1个跳2级的情况(位置 遍历前移。) 然后2个跳2级。。。。。。 递归计算。。 不过 毫无疑问 这个算法的复杂度 很复杂。。
先写个复杂的这个来看看:
。。我一开始想复杂了 其实 就是 f(n)=f(n-1)+f(n-2) 因为 在某一步。 可以选择跳一级 也可以选择跳2级。 跳一级 就是f(n-1) 2级就是 f(n-2) 。 这个就简单了。用递归能实现 而且 之前有一题 需求是 要求效率的 递归效率太低。 正推就ok了 就是 先算f(3) 得出后 再算f(4)...一直到 f(n) 一次循环就可以得出。
28.整数的二进制表示中 1 的个数
题目:输入一个整数,求该整数的二进制表达中有多少个 1。
例如输入 10,由于其二进制表示为 1010,有两个 1,因此输出 2。
这一题 如果 要求效率什么的 铁定是 移位 然后 与1 取与操作。 不停的移位 就ok了 算法没什么吧。。。
看了答案 思路是对的 不过 忽视了 负数。因为负数 会 补1. 换个思路 就是把1 左移 来与。 ok了。。
29.栈的 push、pop 序列
题目:输入两个整数序列。其中一个序列表示栈的 push 顺序,
判断另一个序列有没有可能是对应的 pop 顺序。
这个 题目 最简单的方法就是走一遍。 遍历第一个序列。 push 一个 判断 并且和第二个序列的比较。 如果相等 就pop 并且第二个序列的当前对象 移除。 继续判断当前。如果还相等 继续做这个操作。 一直到不相等了 就继续 push 。 如果 最后全部push完成 并且 还不相等。第二个序列还有值 就说明 是错的。
代码如下
public boolean test(List<Integer> pushArr,List<Integer> popArr){ int pushIndex=-1; List<Integer> myPushArr=new ArrayList<Integer>();//我用一个 list 和一个变量 i 模拟栈 int popIndex=0;//记录 popArr 的index for(int j=0;j<pushArr.size();j++){ int data=pushArr.get(j); int popData=popArr.get(popIndex);//当前出栈。 if(data==popData){//相等 就是 进栈后立刻出栈。 popIndex++; boolean sign=true; while(sign&&pushIndex>=0){ data=myPushArr.get(pushIndex); popData=popArr.get(popIndex); if(data==popData&&pushIndex>=0){ pushIndex--; popIndex++; }else{ sign=false; } } }else{ //需要进栈。 pushIndex++; if(pushIndex>=myPushArr.size()){ myPushArr.add(data); }else{ myPushArr.set(pushIndex, data); } } } return pushIndex<0; }
30.在从 1 到 n 的正数中 1 出现的次数
题目:输入一个整数 n,求从 1 到 n 这 n 个整数的十进制表示中 1 出现的次数。
例如输入 12,从 1 到 12 这些整数中包含 1 的数字有 1,10,11 和 12,1 一共出现了 5 次。
分析:这是一道广为流传的 google 面试题。
这一题 应该 有点移位的思想来做。 但是 不是 移位操作,是对于十进制来操作。 仔细想想其实有点数学的那个 C 那个 组合更简单。就是在
m 中 取n 个有多少种取法。
1.获取这个数 有多少位。
2 假设5位 先计算 4位(9999 )里面有多少个1 就是 4中有一个1的个数*999(这里不应该是999 应该是 9*9*9 这是因为 每种组合的情况 其他位数都可以是 0到9 除了1之外的任何数字) 4位数中有2个1的个数 *2 *999 4位数中有3个1的个数*3*999 4位数很重有4个1的个数 * 4*999
3 再计算 从 10000 到给定数字的 有 1的个数。
当然 也可以 循环 从 1 一直到 给定的数字 一个个判断 不过 我估计 第一个效率要好很多。 2个代码都写一下 比较一下。
//第一种 大众的方法 public long getOneTime2(long data){ int time=0; for(int i=1;i<=data;i++){ //System.out.println("看看"+i); time+=getOneTimeByNum(i); //System.out.println("看看time"+time); } return time; } public long getOneTimeByNum(long data){ long re=0; while(data>0){ long d=data%10; data/=10; if(d==1){ re++; } } return re; } //第二种 方法 复杂一点但是快很多 public long getOneTime(long data){ if(data==0){ return 0; } if(data<10){ return 1; } int size=getSize(data); long time=0; // long 这个是考虑 第一位是1 的情况 有多少个。 因为第一位是1 比较特殊 long firstOneTime=1; for(int i=1;i<=size-1;i++){ time+=(getCombination(size-1, i)*i); firstOneTime*=10; } //到这里 只算了 第一位是0的时候的个数 //如果是1 再加 10000(size-1 个 0) 如果是2 还是这么多。。但是 最后一个 就不容了 //比如 给定的 是 3896 第一位 是0 假设有 100个; 第一位 是1 有 100+1000个 第一位是2 有100个 但是 第一位是3 就不同了 需要特殊处理。 //先获取到第一位的数字 long firstNum=data; while(firstNum>=10){ firstNum/=10; } //所以 现在1的个数 应该等于 if(firstNum==1){ //很特殊 time+=data-firstOneTime*firstNum+1;//出去第一位 有多少个数 就有多少个情况 还要kaolv 1000000000 这种 需要+1 }else{ //就是大约1的情况了 time*=firstNum;//取决于 第一位的 种类。 需要注意的是 最后一个 需要特殊处理的。第一个数字是1 的也要特殊处理 time+=firstOneTime;//当时1的情况 仍然很特殊 } //递归计算 去掉第一位之后 余下的情况 long nowData=data-firstOneTime*firstNum; long newTime=getOneTime(nowData); // System.out.println("data:"+data+"firstOneTime"+firstOneTime+"nowData:"+nowData+"newTime:"+newTime); return time+newTime; } public int getSize(long data){ int s=0; while(data>0){ s++; data=data/10; } return s; } /* * 获取组合个数 结果 已经 要乘以 m-1 位 9 相乘 这是因为 每种组合的情况 其他位数都可以是 0到9 除了1之外的任何数字。 */ public long getCombination(long m,long n){ if(m==n){ return 1; } long otherTime=1; for(int i=0;i<m-n;i++ ){ otherTime*=9; } long mm=m; long time=Math.min(m-n,n); long nn=time; long nnn=nn; for(int i=0;i<time-1;i++){ m--; nn--; mm*=m; nnn*=nn; } return mm/nnn*otherTime; }
第一种 是大众 遍历方法。 写起来很简单 运算起来 。。。
第二种 快很多。非常多。 我的机器 第一种超过8位算不动了 电脑 第二种 一直到 越界了(long 类型) 都能 瞬间运算出来。
相关文章推荐
- 看大神文章小结——微软等面试 23,24,25,26
- 看大神文章小结——微软面试3
- 看大神文章小结——微软等面试 35,36,37,38
- 看大神文章小结——微软面试2
- 看大神文章小结——微软面试5,6
- 看大神文章小结——微软等面试10,11
- 看大神文章小结——微软面试1
- 看大神文章小结——微软等面试 18,19
- 看大神文章小结——微软等面试 31,32,33,34
- 看大神文章小结——微软面试4
- 看大神文章小结——微软等面试 20,21
- 看大神文章小结——微软等面试12,13,14
- 看大神文章小结——微软等面试 39,40
- 看大神文章小结——微软等面试7,8
- 看大神文章小结——微软等面试 16,17
- 看大神文章小结——微软等面试 41-45
- EC读书笔记系列之14:条款26、27、28、29、30、31
- 笨方法学python 习题27(逻辑之前的内容)习题28(布尔)29、30、31
- 微软面试小结
- 精选微软等公司数据结构+算法面试100题带答案(11-30)