看大神文章小结——微软等面试 27,28,29,30

大神 地址 :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 类型) 都能 瞬间运算出来。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值