您的位置:首页 > 职场人生

看大神文章小结——微软等面试 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完成 并且 还不相等。第二个序列还有值 就说明 是错的。

代码如下

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 类型) 都能 瞬间运算出来。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: