程序员面试——位运算

 5.1 二进制插入

有两个32位整数n和m,请编写算法将m的二进制数位插入到n的二进制的第j到第i位,其中二进制的位数从低位数到高位且以0开始。

给定两个数int n和int m,同时给定int j和int i,意义如题所述,请返回操作后的数,保证n的第j到第i位均为零,且m的二进制位数小于等于i-j+1。

测试样例:
1024,19,2,6
返回:1100

 画图——》移位+或

import java.util.*;

public class BinInsert {
    public int binInsert(int n, int m, int j, int i) {
        return n|(m<<j);
    }
}

 

5.2 二进制小数

有一个介于0和1之间的实数,类型为double,返回它的二进制表示。如果该数字无法精确地用32位以内的二进制表示,返回“Error”。

给定一个double num,表示0到1的实数,请返回一个string,代表该数的二进制表示或者“Error”。

测试样例:
0.625
返回:0.101

照着二进制和十进制小数的数学关系做就是了:乘2与1比

import java.util.*;

public class BinDecimal {
    public String printBin(double num) {
        StringBuffer res=new StringBuffer();
        res.append("0");
        res.append(".");
        for(int i=0;i<33;i++) {
            if(i==32) return "Error";
            num=num*2;
            if(num-1==0){
                res.append("1");
                break;
            }else if(num-1>0){
                res.append("1");
                num=num-1;
            }else{
                res.append("0");
            }
        }
        return res.toString();
    }
}

 

 当然,有时间可以试试跟0.5之类的做减法;思路差不多

 

5.3 最接近的数

蛮力法都还没做出来,等脑子清醒一点再做;

 

5.4 ((n&(n-1))==0)的含义

 从特殊到一般再到特殊:A&B==0

 

5.5 整数转化

编写一个函数,确定需要改变几个位,才能将整数A转变成整数B。

给定两个整数int A,int B。请返回需要改变的数位个数。

测试样例:
10,5
返回:4

计数就好,注意用while

import java.util.*;

public class Transform {
    public int calcCost(int A, int B) {
        // 直接的思路,直接干,然后计数就好了嘛
        int count=0;
        int index=0;
        if (A==B) return count;
        while (A!=B) {
            if((A&(1<<index))!=(B&(1<<index))){
                count++;
                A=A^(1<<index);
            }
            index++;
        }
        return count;
    }
}

 

细节:用num^(1<<index)来改变某一位的值;

 

5.6 奇偶位交换

请编写程序交换一个数的二进制的奇数位和偶数位。(使用越少的指令越好)

给定一个int x,请返回交换后的数int。

测试样例:
10
返回:5
import java.util.*;

public class Exchange {
    public int exchangeOddEven(int x) {
        // 首先,实现功能,就是从头开始,两位两位的跳
        //问题在于如何判断结束,不如再弄一个数字,慢慢赋值
        int[] tmp=new int[2];
        //int y=0;
        //int res=0;
        int index=0;
       // int slow=0;
        tmp[0]=x;tmp[1]=0;
        while(x!=tmp[1]){
            swap(tmp,index);
            index=index+2;
        }
        
        return tmp[0];
    }
    
    void swap(int[] tmp,int index) {
        int first=0;
        int second=0;
        int xx=tmp[0];
        //int yy=tmp[1];
        
        first=xx&(1<<index);
        second=xx&(1<<(index+1));
        if (first!=0) first=1;
        if (second!=0) second=1;
        
        //先清零再置位
        tmp[0]=(tmp[0]&(~(1<<index)))|(second<<index);
        tmp[0]=(tmp[0]&(~(1<<(index+1))))|(first<<(index+1));
        
        //更新y
        tmp[1]=(tmp[1]|(first<<index))|(second<<(index+1));       
        
        
    }
}

 

 关键点在于while的停止条件吧,对于我而言;

巧妙方法:先对所有奇数位操作,再是偶数位,再或一下

return (((x & 0xaaaaaaaa)>>1)) | (((x & 0x55555555)<<1));

 

 

5.7 找出缺失的整数

数组A包含了0到n的所有整数,但其中缺失了一个。对于这个问题,我们设定限制,使得一次操作无法取得数组number里某个整数的完整内容。唯一的可用操作是询问数组中第i个元素的二进制的第j位(最低位为第0位),该操作的时间复杂度为常数,请设计算法,在O(n)的时间内找到这个数。

给定一个数组number,即所有剩下的数按从小到大排列的二进制各位的值,如A[0][1]表示剩下的第二个数二进制从低到高的第二位。同时给定一个int n,意义如题。请返回缺失的数。

测试样例:
[[0],[0,1]]
返回:1

没意思。。不做。。

按照书上的思路:一般的是全部加起来,少那个就是那个;

这个的话,就奇偶缺失来做就行!!!

 

总结

5.3 和5.8没搞定,5.7不想做,其他做完了,对位运算,还是熟练是第一位的,思路要灵活些,什么快慢指针,递归,数组,字符串都可以用起;

 

---------------拓展--------------------------

1.1&1.7 见  数组与字符串http://www.cnblogs.com/andy1202go/p/5759047.html

 

17.1 无缓存交换

请编写一个函数,函数内不使用任何临时变量,直接交换两个数的值。

给定一个int数组AB,其第零个元素和第一个元素为待交换的值,请返回交换后的数组。

测试样例:
[1,2]
返回:[2,1]

我的思路是直接的公式退出来就好啊:

import java.util.*;

public class Exchange {
    public int[] exchangeAB(int[] AB) {
        AB[0]=AB[0]+AB[1];
        AB[1]=-(AB[1]-AB[0]);
        AB[0]=AB[0]-AB[1];
        return AB;
    }
}

 

书上的位运算解法没看懂。。。。

a=a^b;
b=a^b;//懂了,b=(a^b)^b=a;
a=a^b;

 

妈蛋,有点厉害!!!

 

 

 

 

18.1 另类加法

不用加号的加法

主体思路:位运算;

一般:捣腾出进位再进行相加之类的

public class Solution {
    public int getSum(int a, int b) {
        int[] array=new int[]{a,b};
        getReal(array);
        int sum=array[0]|array[1];
        return sum;
    }
    
    public void getReal(int[] array)
    {
        int jinWei=array[0]&array[1];
        int mask=~jinWei;
        int huo=array[0]|array[1];
        array[0]=mask&huo;
        array[1]=jinWei<<1;
        int state=array[0]&array[1];
        
        if (state!=0){
            getReal(array);
        }
    }
}

 进阶:高级一点的递归

import java.util.*;

public class UnusualAdd {
    public int addAB(int A, int B) {
         if (A==0) return B;
        if (B==0) return A;
        int a=A^B,b=(A&B)<<1;
        return addAB(a,b);
    }
}

 

 

18.4 有几个2

请编写一个方法,输出0到n(包括n)中数字2出现了几次。

给定一个正整数n,请返回0到n的数字中2出现了几次。

测试样例:
10
返回:1

一般思路,每一个数这么看下来就好

import java.util.*;

public class Count2 {
    public int countNumberOf2s(int n) {
        //要全部,看起来就像是递归
        int count=0;
        if (n<2) return count;
        for(int i=2;i<=n;i++) {
            count+=num2(i);
        }
        return count;
    }
    
    int num2(int n){
        int count=0;
        while(n>0){
            if (n%10==2){
                count++;
            }
            n=n/10;
        }
        return count;
    }
    
}

 

算法复杂度太大,时间太长。

找规律,得下面(我tm还没搞懂)

import java.util.*;
 
public class Count2
{
    public int countNumberOf2s(int n)
    {
        int result = 0;
        for(int i=1;i<=n;i*=10)
        {
            result+=(n/i+7)/10*i+(n/i%10==2?n%i+1:0)  ;      
        }
        return result;
            
             
    }
}

 

每十倍循环一下,然后对这个十倍中有多少2进行运算。

最开始想的是用递归,不是很好做,而且也是每一个这么搞,时间也太长。

 

posted @ 2016-08-11 20:54  韧还  阅读(810)  评论(0编辑  收藏  举报