小米公司Android工程师社招面试(2016/08/03)

我在2016年8月3日下午3点半~6点半进行了三轮面试,除了自己做过的项目,也问了一些通用的问题。
当时本人能回答的包括:
 AsyncTask和Handler+Thread机制的区别;
 哈希表原理
 红黑树(由Java 8中HashMap的新特性引申)
 Int类型整数二进制1的个数(算法题,手写)
 楼梯走法次数(算法题,手写)
 ……
当时不会的包括:
 Java中final修饰成员函数的作用
 Java中线程池如何设计的(由AsyncTask引申出来的题目,参见“Java线程池原理与实例详解”)
 自定义控件如何设计,例如显示gif图片
 ……
##一面算法题
题目:Int类型整数二进制1的个数,例如3的二进制是11,1的个数是2。
【分析】
方法一:判断最后一位是否是1,然后不断右移该整数,继续判断,直到该数为0。这个算法对于正数有效,但是对于负数无效。因为右移时最左侧会补符号位,正数就是补0,而负数就是补1。不过,由于java中有右移补0的符号>>>,所以,该算法可行。

public static int bitCounter2( int n){
	    int c =0 ; // 计数器
	    while (n !=0)
	    {
	        if((n &1) ==1) // 当前位是1
	            ++c ; // 计数器加1
	        n >>>=1 ; // 移位,左侧补0,n改变了!
	    }
	    return c ;
	}

方法二:向左移动掩码1,然后进行位运算“&”,就能判断该位是否是1。本方法还能保证被判断数不变。

	public static int bitCounter(int n){
		int mask=1;
		int counter=0;
		while ((n&mask)!=0) {
			counter++;
			mask<<=1;
		}
		return counter++;
	}

这是我面试的回答,当然,回来一查,“算法-求二进制数中1的个数”中有更多好的方法。
##二面算法题
题目:一个人迈步上台阶,一次可以迈1阶、2阶、3阶,这样,到1阶的走法有1中,到2阶的走法有2中,到3阶的走法有4种,那么到第n级的走法有多少种?
【分析】走到n阶前,可能位于n-1阶,再迈1步1阶即可;可能为n-2阶,再迈1步2阶即可;可能位于n-3阶,再迈1步3阶即可。递归公式:f(n)= f(n-1)+ f(n-1)+ f(n-2)。
解法一:递归

public static int stepCounter(int n){
		if (n<=0) throw new IllegalArgumentException("参数错误,n必须大于0!");
		if (n==1) return 1;
		if (n==2) return 2;
		if (n==3) return 4;
		return stepCounter(n-1)+stepCounter(n-2)+stepCounter(n-3);
	}

解法二:空间换时间(类似动态规划)

public static int stepCounter2(int n){
		if (n<=0) throw new IllegalArgumentException("参数错误,n必须大于0!");
		
		int[] counter=new int[n+1];
		counter[1]=1;
		counter[2]=2;
		counter[3]=4;
		for (int i = 4; i < n+1; i++) {
			counter[i]=counter[i-1]+counter[i-2]+counter[i-3];
		}
		return counter[n];
	}

然后面试官问我是否可以优化,我说空间可以再小一点,只记录最近的3次。

public static int stepCounter2(int n){
		if (n<=0) throw new IllegalArgumentException("参数错误,n必须大于0!");
		
		int[] counter=new int[4];
		counter[1]=1;
		counter[2]=2;
		counter[3]=4;
		for (int i = 4; i < n+1; i++) {
			//counter[0]用来存储结果
			counter[0]=counter[1]+counter[2]+counter[3];
			//移动前三个数
			counter[1]=counter[2];
			counter[2]=counter[3];
			counter[3]=counter[0];
		}
		return counter[3];
	}

写这篇博客时我想,其实最后三个数的交换也是没有必要的,只要记住返回值的位置就OK。

	public static int stepCounter3(int n){
		if (n<=0) throw new IllegalArgumentException("参数错误,n必须大于0!");
		
		int[] counter=new int[4];
		int j=0;//返回值的位置
		for (int i = 1; i < n+1; i++) {
			j=i%4;
			if (i==1) {
				
				counter[j]=1;
			}else if (i==2) {
				
				counter[j]=2;
			}else if (i==3) {
				
				counter[j]=4;
			}else {
				counter[j]=0;//清0
				for (int k = 0; k < 4; k++) {
					if (k==j) continue;
					counter[j]+=counter[k];//其它三个数之和
				}
			}
		}
		return counter[j];
	}

请我喝咖啡

如果觉得写得不错,可以扫描我的微信二维码请我喝咖啡哦~

在这里插入图片描述
或者点击 打赏地址 请我喝杯茶~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值