算法 64式 20、位运算与异或算法整理

1算法思想

位运算与异或

1.1含义

位运算:

含义:对整数在内存中的二进制位进行操作。

 

异或:

含义:a与b两个值不同,异或结果位1;如果a与b相同,异或结果位0

运算法则: a与b异或结果=(非a&b)V(a&非b)

样例: a^a=0, 0^1=1,0^0=0,1^1=0

1.2特点

位运算:

数字的二进制表示中1的个数: 每次用n与n-1进行与运算,令n=n-1,操作次数即为所求。

异或:

数组中唯一出现1次的数字只有1个时,其余出现偶数次,则数组所有元素异或的结果即为出现1次的那个数字

数组中唯一出现1次的数字有两个时,数组所有元素异或结果从最低位到最高位的值如果为1,则根据该位上值是否为1

划分整个数组,对划分后的数组分别异或,则可以得到出现1次的数字。

还有其他特点,不一一列举。

1.3适用

1.4通用解法

位运算与异或算法:

1 位运算记住位的特点和如何操作位。

2 异或算法牢记两个数不同则异或结果为1,两个数相同,则异或结果为0.

 

1.5经典例题讲解

Single Number

Given an array of integers, every element appears three times except for one, which appears exactly once. Find that single one.

Note:

Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

 

分析:数组中每个元素出现了3次,只有一个元素出现了1次,找到这个元素。

必须在线性时间找到。尽量不要使用额外的空间。

leecode的解法:https://leetcode.com/problems/single-number-ii/?tab=Solutions

想不到。对0~31位上,统计每个数在每一位上出现次数,如果出现的总次数sum % 3 != 0

说明这一位肯定是只出现了一次的那一位,把所有位异或连接,即可。

获取每个数第i位用: 掩码mask = 1 << 1,然后 mask & nums.at(i) 即得到

代码如下:

 

class Solution {

public:

    int singleNumber(vector& nums) {

              if(nums.empty())

              {

                     return 0;

              }

        unordered_map numToTimes;

              int size = nums.size();

              int mask;

              int sum;

              int result = 0;

              for(int i = 0 ; i < 32 ; i++)

              {

                     mask = 1 << i;

                     sum = 0;

                     for(int j = 0 ; j < size ; j++)

                     {

                            //这里相与结果是第i位为1或者全0

                            if((nums.at(j) & mask) != 0)

                            {

                                   sum++;

                            }

                     }

                     if(sum % 3 != 0)

                     {

                            result |= mask;

                     }

              }

              return result;

    }

};

 

 

2 位运算与异或系列

类别-编号

题目

遁去的一

1

中国象棋将帅问题:

自古将帅不能照面

                __ __ __

10              将

9

8

7

6

5

4

3

2

1                       帅

 a b c d e f g h i

A表示将,B表示帅,A被限制在{d10,f10,d8,f8}中,B被限制在{d3,f3,d1,f1}中。

每一步A,B可以横向或纵向移动一个。A与B不能在同一条纵向直线上,比如A在d10位置,B就不能在d1,d2,d3位置

 

请写出一个程序,输出A、B所有合法位置。要求在代码中只能使用一个字节存储变量。

编程之美

https://blog.csdn.net/qingyuanluofeng/article/details/39272911

关键:

1 因此将该字节一分为二,前4位表示A,后4位表示B,这样每个棋子都有16种位置表示方法,已经足够(牛逼啊)

2 算法:

遍历A的位置

 遍历B的位置

  判断A、B的位置组合是否满足要求

  如果满足则输出

3 #define LEFT_MASK (FULL_MASK << 4) //注意,用define定义东西的时候,若有两个变量,需要加括号

4 #define RIGHT_MASK (FULL_MASK >> 4) //右掩码就是右边4位全是1

5 #define LSET(b,n) (b = ((b & RIGHT_MASK) | ((n) << 4) ) )//将比特b的左边设定为n,主要为循环遍历使用。采用的方法是,

//左边清零(通过与右掩码(00001111)相与即可),然后将数n向左移4位,然后将上述两个数用或即可,注意别漏了赋值操作

//注意n要用括号括起来,他表示一个数,不是一个字符

6 #define LGET(b) ( (b & LEFT_MASK) >> 4)//获取比特b的左边4位的方法是,先将右边4位清零,

//再右移4位即可

7    if(LGET(b) % STEP != RGET(b) % STEP)//牛逼,用九宫格模拟两者取模之后的余数不同,就表示

    //不在一条竖线上就可以

 

#define FULL_MASK 255

//#define HALF_MOVE 4

#define LEFT_MASK (FULL_MASK << 4) //注意,用define定义东西的时候,若有两个变量,需要加括号

#define RIGHT_MASK (FULL_MASK >> 4) //右掩码就是右边4位全是1

#define LSET(b,n) (b = ((b & RIGHT_MASK) | ((n) << 4) ) )//将比特b的左边设定为n,主要为循环遍历使用。采用的方法是,

//左边清零(通过与右掩码(00001111)相与即可),然后将数n向左移4位,然后将上述两个数用或即可,注意别漏了赋值操作

//注意n要用括号括起来,他表示一个数,不是一个字符

#define RSET(b,n) (b = ((b & LEFT_MASK) | (n) ) )//将比特b的右边设定为n,采用的方法是:

//右边清零(将该数与左掩码(11110000)相与),然后与该数n相或

#define LGET(b) ( (b & LEFT_MASK) >> 4)//获取比特b的左边4位的方法是,先将右边4位清零,

//再右移4位即可

#define RGET(b) (b & RIGHT_MASK)//获取比特b的右边4位的方法是,将该数右边4位与右掩码相与即可

#define STEP 3

 

void ChineseChess_define()

{

 unsigned char b;

 int iCnt = 0;

 for(LSET(b,1) ; LGET(b) <= STEP * STEP ; LSET(b,(LGET(b) + 1) ) )

 {

  for(RSET(b,1) ; RGET(b) <= STEP * STEP ; RSET(b,(RGET(b) + 1) ) )

  {

   if(LGET(b) % STEP != RGET(b) % STEP)//牛逼,用九宫格模拟两者取模之后的余数不同,就表示

    //不在一条竖线上就可以

   {

    printf("A=%d,B=%d\n",LGET(b),RGET(b));

    iCnt++;

   }

  }

 }

 printf("%d\n",iCnt);

}

2

快速找出机器故障

为了保证搜索引擎的服务质量,我们需要保证每份数据都有多个备份

假设一个机器仅存储了一个标号为ID的记录(假设ID是小于10亿的整数),假设每份数据保存了两个备份,这样

就有两个机器储存了同样的数据。

1在某个时间,如果得到一个数据文件ID的列表,是否能够快速地找出这个表中仅出现一次的ID?

2如果已经知道只有一台机器死机(也就是说只有一个备份都是)呢?如果有两台机器死机呢(假设同一个数据

的两个备份不会同时丢失)?

3如果丢失的两台机器ID相同呢?

 

样例输入:

8

2 4 3 6 3 2 5 5

2 4 3 6 3 2 5 5 4 6

样例输出:

4 6

 

编程之美

https://blog.csdn.net/qingyuanluofeng/article/details/39273013

分析:

这个问题可以转化成:有很多的ID,其中只有一个ID出现的次数小于2,其他正常ID出现的次数都等于2,如何找到

这个次数为1的ID。

这样就转化成剑指上面的:所有元素全部异或,最终剩下的数就是那个数

 

第二问转化为这群数中有两个数各出现一次,其余出现0次,所以也是剑指上的题目,需要全部异或得到数字

x,然后获取x的比特表示中最右边的1,记为该位为第n位,根据比特表示中的第n位是否为1,将数组划分

成两部分,每一部分中在分别全部异或一遍,即可。

局限:只能解决两台故障机器ID不同的情况。如果ID相同,则无法解决

 

第三问:

预先计算并保存好所有ID的求和(不变量),顺序列举当前所有剩下的ID,对它们求和,然后用总值 - 剩余值 = 死机

的机器ID值。由于总和可以先计算好,算法的时间复杂度为O(N),空间复杂度为O(1)

 

当两个ID不同时:总和 - 剩余和 = x + y

当两个ID相同时:这个时候,x = (总和-剩余和)/2

 

这个时候可以构造二元一次方程组来做,比如:总乘积/剩余乘积 = x*y(或者求出x*x + y*y = b)

联立解方程

{x + y = a

{x * y = b

此方法的缺陷是:需要事先知道原来n个数,如果题目只给你丢失的数,那就坑爹了

 

void process()

{

 int n;

 while(EOF != scanf("%d",&n))

 {

  if(n < 0)

  {

   break;

  }

  int iRemainArr[MAXSIZE];

  long long lRemainSum = 0,lRemainMul = 1,lIntactSum = 0,lIntactMul = 1;

  for(int i = 0 ; i < n ; i++)

  {

   scanf("%d",&iRemainArr[i]);

   lRemainSum += iRemainArr[i];

   lRemainMul *= iRemainArr[i];

  }

  int iIntactArr[MAXSIZE];

  for(int j = 0 ; j < n + 2 ; j++)

  {

   scanf("%d",&iIntactArr[j]);

   lIntactSum += iIntactArr[j];

   lIntactMul *= iIntactArr[j];

  }

  long long lSum = lIntactSum - lRemainSum;

  long long lMul = lIntactMul/lRemainMul;

  long long lSqrt = (long long)sqrt(double(lSum*lSum - 4*lMul) + 0.5);

  long long lX = (long long)((lSum - lSqrt)/2);

  long long lY = (long long)((lSum + lSqrt)/2);

  printf("%lld %lld\n",lX,lY);

 }

}

3

桶中取黑白球

有一个桶,里面有白球,黑球各有100个,人们按照以下规则把球取出来:

1每次从桶里面拿出两个球2如果是两个同色的球,那么就放入一个黑球

3如果是两个异色的球,就再放入一个白球

问:最后桶里面只剩下一个黑球的概率是多少?

 

int XOR(int iBlackNum,int iWhiteNum)

{

       int iRet = 1;//因为我们把黑球当成0,白球当成1,因此黑球不需要参加异或运算,最后的结果只与白球个数有关

       for(int i = 2 ; i <= iWhiteNum ; i++)

       {

              iRet = !iRet;

       }

       return iRet;

}

编程之美

https://blog.csdn.net/qingyuanluofeng/article/details/47187921

解法3:

用离散横纵的异或(XOR)

两个相同的数,异或为0

    不              1

由于当球不用时,就可以放入一个黑球,那我们只能把黑球赋值1,白球赋值0

闹中想起里面装了100个1和100个0

对每次捞出的两个数字做一次异或,并将所得结果1或0丢回桶中,这样每次操作不会改变球权值的亦或值

假设黑白球各有两个,

1取出两个黑球,放回一个黑球, 0^0 = 0,剩下的结果为(1,2)

2取出一黑一白,放回一个白球, 0^1 = 1,剩下的结果为(0,2)

3最后只能取出两个白球,放回黑球, 1^1 =0,剩下的结果为(1,0)

因为异或满足结合律,即 (a ^ b) ^ c = a ^(b ^ c),操作顺序不会影响后面结果

取球的过程相当于把里面所有的求进行异或操作,也就是1 ^ 1 ^ 0 ^ 0 = 0,因此剩下一个球的时候,桶中权值等于初始时刻所有权值的亦或值,也就是0,所以剩下

的求一定是黑球

扩展:

1如果各有99个黑球和白球,那么异或值为1,必然剩下白球。每种球个数为偶数,剩下的为黑球,个数为奇数,剩下的是白球。

2如果黑白球数量不定,我们不在乎球的数量,只需要看最后异或值

 

int XOR(int iBlackNum,int iWhiteNum)

{

       int iRet = 1;//因为我们把黑球当成0,白球当成1,因此黑球不需要参加异或运算,最后的结果只与白球个数有关

       for(int i = 2 ; i <= iWhiteNum ; i++)

       {

              iRet = !iRet;

       }

       return iRet;

}

4

给定两个32位的整数N与M,以及表示比特位置的i与j。编写一个方法,将M插入N,使得M从N的第j位开始,到第i位结束(j>i)。

假定从j位得到i位足以容纳M,也即若M=10011,那么j和i之间至少可以容纳5个位。例如,不可能出现j=3和i=2的情况,因为第3位和第2位之间放不下M。

示例输入:

N= 100 0000 0000

M=      100 11

i= 2,j =6

输出:N= 100 0100 1100

程序员面试金典

https://blog.csdn.net/qingyuanluofeng/article/details/53993092

分析:这个问题实际上就是寻找这样一个整数x,x与y进行位操作后,以y全部出现。

      等同于以下步骤:

         1:先将N从第j位到第i位之间变成0,设置数M,问题转化为如何使得某一位变成0,从而将从第j位到第i位依次都变成0

         2:将M整体向左移动i位得到新的M

         3: 将N和新的M进行或运算

 

关键:

1

书上解法:

对一个数从第j位到第i位进行清零,涉及到两次掩码运算。

首先:将0取反,得到全1的数,将该全1的数向左移动j+`位,因为这里最低位是从0开始计算的,0到第j位全为0,实际上是j+1个位都为0,因此

      向左移动j+1位,记得到P

然后:需要将第i位以下的位全部变成1,可以用1向左移动i位,然后减去1,记得到Q

最后: P|Q 得到最终掩码R,将R和N进行与运算

想不到:将0取反右移j+1位即可使得第j位前面均为1

2 注意输入的N和M都是字符串,需要转化为二进制

 

 

 

/*

对一个数从第j位到第i位进行清零,涉及到两次掩码运算。

首先:将0取反,得到全1的数,将该全1的数向左移动j+`位,

因为这里最低位是从0开始计算的,0到第j位全为0,实际上是j+1个位都为0,因此

      向左移动j+1位,记得到P

然后:需要将第i位以下的位全部变成1,可以用1向左移动i位,然后减去1,记得到Q

最后: P|Q 得到最终掩码R,将R和N进行与运算

*/

int clearBit(int N , int i , int j)

{

       if(i > j)

       {

              return -1;

       }

       int allOnes = ~0;

       int P = allOnes << (j+1);

       int Q = (1 << i) - 1;

       int R = P | Q;

       int result = R & N;

       return result;

}

 

/*

         1:先将N从第j位到第i位之间变成0

         2:将M整体向左移动i位得到新的M

         3: 将N和新的M进行或运算

*/

int replaceBit(int N , int M , int i , int j)

{

       if(i < 0 || j < 0 || i > j)

       {

              return -1;

       }

       int C = clearBit(N , i , j);

       M = M << i;

       int result = C | M;

       return result;

}

 

stack  tenToTwo(int num)

{

       stack stackResult;

       do{

              int j = num % 2;

              stackResult.push(j);

              num /= 2;

       }while(num);

       return stackResult;

}

 

void print(stack stackResult)

{

       while(!stackResult.empty())

       {

              int value = stackResult.top();

              stackResult.pop();

              cout << value;

       }

       cout << endl;

}

 

//将字符串中表示的二进制整数转化为10进制整数,只能每次取一位,并乘以2^i,进行累加

int toInt(string& str)

{

       if(str.empty())

       {

              return -1;

       }

 

       //字符串应该从后向前获取

       int size =str.size() ;

       int num;

       int count = 0;

       int result = 0;

       for(int i = size -1 ; i >= 0 ; i--)

       {

              num = str[i] - '0';

              int value = (int) pow(2 , count);

              result += num * value;

              count++;

       }

       return result;

       //int value = atoi(str.c_str());//这里输入的是二进制整数需要转换,不能直接用字符串转换

       //return value;

}

 

void process()

{

       string strN , strM ;

       int N , M;

       int i ,j;

       while(cin >> strN >> strM >> i >> j)

       {

              N = toInt(strN);

              M = toInt(strM);

              int result = replaceBit(N , M , i , j);

              //得到结果后,需要转化成二进制数,十进制转二进制就是除二取余,然后逆序输出即可

              stack stackResult = tenToTwo(result);

              print(stackResult);

       }

}

5

对一个浮点数,打印它的二进制表示

给定一个介于0和1之间的实数(如0.72),类型为double,打印它的二进制表示。如果该数字无法精确地用32位以内的二进制表示,则打印"ERROR"

 

输入:

0.25

0.72

输出

0.01

ERROR

程序员面试金典

https://blog.csdn.net/qingyuanluofeng/article/details/53993279

分析:其实就是浮点数转二进制整数。

十进制浮点数转二进制的规则是:

将数字N乘2取整,如果计算结果R为1就退出,否则如果计算结果R>1,则取1,

      并使得N=R-1;如果R<1,则取0,。

         重复上述处理,直到超过指定计算次数就退出。

      将取整后的数字放在"0."后面依次排列好,即为所求

 

vector toBinarySystem(string& num)

{

       vector vecResult;

       if(num.empty())

       {

              return vecResult;

       }

       //判断第一位是否为0,如果大于0,不符合要求

       int value = num[0] - '0';

       if(value > 0)

       {

              return vecResult;

       }

       //将字符串转化为小数

       double dNum = atof(num.c_str());

       int count = 0;

      

       do{

              if(count >= 32)

              {

                     break;

              }

              dNum *= 2;

              //如果结果恰好为1,将1存入结果

              if( fabs(dNum - 1) < 1e-6 )

              {

                     vecResult.push_back(1);

                     break;

              }

              else

              {

                     if( dNum > 1)

                     {

                            dNum -= 1;

                            vecResult.push_back(1);

                     }

                     else

                     {

                            vecResult.push_back(0);

                     }

              }

              count++;

       }while(true);

       if(count >= 32)

       {

              vecResult.clear();

       }

       return vecResult;

}

6

给定一个正整数,找出与其二进制表示中1的个数相同、且大小最接近的那两个数(一个略大,一个略小)

 

输入:

11100111

10011

10010

111

输出

11011110, 11101011

1110(略小的数) ,10101(略大的数)

10001 , 10100

No Less Number , 1011

程序员面试金典

https://blog.csdn.net/qingyuanluofeng/article/details/53995467

关键部分:

1 位运算中关键技巧:

  技巧1:以第i位将一个数拆num分上高位部分和低位部分,然后高位部分和低位部分分别进行操作,最后将操作后的高位部分和

         低位部分进行或运算,即可得到最终运算结果

               低位第i位以下部分全为1的掩模lowMask= 1 << i - 1;

               高位第i位及以上部分全为1的掩模highMask = ~( (1 << i) - 1 )

               低位lowNum = num & lowMask

               高位highNum = num & highMask

  技巧2:将数num的第i位变成0:

                              highMask = ~( 1 << (i + 1) - 1 );注意高位部分的掩模不含第i位本身,则第i位变成0

                              lowMask= 1 << i - 1; 然后利用技巧1获取高位数和低位数部分进行处理

                                                   int lowNumber = num & lowMask;

                                                   int highNumber = num & highMask;

                                                   int result = highNumber | lowNumber;

         将数num的第i位变成1:num != (1 << position); 【另第i位变成1】,变为1只需要与2^i进行或运算

               将数num的第i位之后全变成0:只需要与一个最后i位都为0,前面都为1的数做与运算

                                         mask = ( (~0) << i )

               将数num前面n位设置为1,后面m位设置为0:

                                     先生成n个1,然后向左移动m位

                                                    mask = (1 << n) -1;

                                                    mask <<= m;

                                                    num |= mask;

  技巧3:寻找最低位的0:将数num和1做相与运算,如果相与结果为0,则当前位即为所求;否则令num >>= 1,即令数向右移动,之所以不用num与2^i运算,会溢出,

                        且无法判定何时停止运算

         寻找最低位的1:                                 不为0

  技巧4:(n & (n-1) ) == 0判断一个整数是否为2的某次方

         需要n个1,就 (1 << n) - 1

         全是1的数= ~0

         判断是否为全是1的数: 将num和1做与运算,如果相与结果为0,肯定不是;否则,令num >> = 1,

                                     如果num变成0了,则必定为全1(会溢出,不能用该方法:将该数加1后与2^i比较,当2^i > 该数时,则必定不是全为1)

2 寻找略小的数

考虑到本质上是将一个1变成0,将一个0变成1.

变小,所以改变的1的位置比0的位置要大,所以寻找的应该是类似这种"10"

3 寻找略大的数

那么要改变的0的位置要在1的前面,应该是寻找这种"01",

寻找到这样的0的位置P:使其右边一位为1,该位置P最小。统计P右侧的0的个数为C0,1的个数为C1。

将P本身变为1,并将P右侧全部清零,P右侧应该存放C1 - 1 个1,并需要将这些1放在离P最远的位置。

例如: 1001110, P = 4,C0=1,C1=3,

将位置P从1变成0,并将P右侧清零得到   :1010000

将C1-1个1放在P右侧离P最远的的地方得到:1010011

 

typedef struct Result

{

       Result(bool isResult , int result)

       {

              _isResult = isResult;

              _result = result;

       }

       bool _isResult;

       int _result;

}Result;

 

 

/*

统计一个十进制数转换为2进制数中1的个数,统计方法采用:

将该数不断与2^i,进行相与处理,如果相与后结果不为0,表示当前位为1

如果2^i超过最大整数或小于最小整数,则统计停止

*/

int count1(int num)

{

       int count = 0;

       //采用num & 1比较, num >>= 1的方法做,不会溢出

       while( num != 0 )

       {

              if( (1 & num) == 1 )

              {

                     count++;

              }

              num >>= 1;

       }

       return count;

}

 

//统计一个整数中0的个数

int count0(int num)

{

       int count = 0;

       while( num != 0)

       {

              if( ( num & 1)  == 0)

              {

                     count++;

              }

              num >>= 1;

       }

       return count;

}

 

//将十进制整数转换为二进制整数,打印出来

string toBinarySystem(int num)

{

       int total = 0;

       int count = 0;

       stack stackResult;

       do{

              int value = num % 2;

              stackResult.push(value);

              total += value * ( int( pow(2, count) ) );

              num /= 2;

       }while(num);

       stringstream ss;

       while(!stackResult.empty())

       {

              int value = stackResult.top();

              ss << value ;

              stackResult.pop();

       }

       return ss.str();

}

 

//找到类似“01”这种位置,用于找到略大的数

int find01Position(int num)

{

       int value = num;

       int pos = 0;

 

       //必须先找到1

       while( value && ( (value & 1) == 0 ) )

       {

              pos++;

              value >>= 1;

       }

 

       //说明这个数中没有1,直接返回-1

       if(value == 0)

       {

              return -1;

       }

 

       //接下来找相邻的0

       //pos--;//下面会多计算一次,因此位置要减一

       while( value && (value & 1) == 1 )

       {

              pos++;

              value >>= 1;

       }

       if(value == 0)

       {

              return -1;

       }

       return pos;

}

 

//找出类似"10"的位置,用于寻找略小的数

int find10Position(int num)

{

       //先找到0

       int value = num;

       int pos = 0;

       while( value && ( (value & 1) == 1 ) )

       {

              pos++;

              value >>= 1;

       }

       if(0 == value)

       {

              return -1;

       }

       //寻找1

       while( value && ( (value & 1) == 0 ) )

       {

              pos++;

              value >>= 1;

       }

       if(0 == value)

       {

              return -1;

       }

       return pos;

}

 

Result getLessNumber(int num)

{

       int pos = find10Position(num);

       if(-1 == pos)

       {

              return Result(false , -1);

       }

       //统计位置P右侧1的个数

       int rightValue = num & ( ( 1 << pos) - 1 );

       int countOne = count1(rightValue);

       int countZero = pos - countOne;//0的位置不需要统计,直接拿P-countOne

       //将位置P的1变成0,并将P右侧全部变成0

       int mask = ~( (1 << (pos + 1) ) -1 );

       num &= mask;

       //将P右侧离P最近的 C1+1个位置全部设置为1 , C1-1个0,组成,总位数就是P,可以先生成C1+1个1

       mask = ( 1 << (countOne + 1) ) - 1;

       //将这个C1+1个1向左移动C0-1位,使其包含C0-1个0

       mask <<= countZero -1;

       num |= mask;

       return Result(true , num);

}

 

/*

那么要改变的0的位置要在1的前面,应该是寻找这种"01",

寻找到这样的0的位置P:使其右边一位为1,该位置P最小。统计P右侧的0的个数为C0,1的个数为C1。

将P本身变为1,并将P右侧全部清零,P右侧应该存放C1 - 1 个1,并需要将这些1放在离P最远的位置。

例如: 1001110, P = 4,C0=1,C1=3,

将位置P从1变成0,并将P右侧清零得到   :1010000

将C1+1个1放在P右侧离P最远的的地方得到:1010011

*/

Result getGreaterNumber(int num)

{

       int pos = find01Position(num);

       if(-1 == pos)

       {

              return Result(false , -1);

       }

       //计算P位置右侧的1的个数

       int rightValue = num & ( (1 << pos) - 1);

       int countOne = count1( rightValue );

       //找到位置P,将P位置本身变为1

       num |= (1 << pos);

       //将P位置右侧全部清零,不含P位置

       int mask = ~( (1<

       num &= mask;

       //从P右侧,离P最远的C1 - 1个0全部变成1,记住:需要n个1,就 (1 << n) - 1

       num |= ( (1 << countOne - 1) - 1  );

       return Result(true , num);

}

7

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

 

输入:

1011 1101

1011 0101

1111 1111

输出:

2

3

0

程序员面试金典

https://blog.csdn.net/qingyuanluofeng/article/details/53998346

关键:

1 两数异或后的结果,然后统计1的个数即可

那么问题转化为如何统计1个整数中1的个数,设这个整数为num:

用 num & 1 == 1来判断,然后令 num >>= 1(向右移动),直到num变为0,这个时间复杂度为O(n),n为整数的二进制长度

2 如果用 ( num & (num-1) ) != 0,就累加1个个数,则时间复杂度为O(k),k为该整数中1的个数,

之所以: num & (num-1),并且后续循环令num = num & (num -1),是因为这样每次会消去最低位的1,

通过不断翻转最低有效位,计算多少次c才会变成0,操作c=c & (c-1)会清除c的最低有效位

 

typedef struct Result

{

       Result(){}

       Result(const Result& other){ *this = other; }

       Result(bool isResult , int result):_isResult(isResult) , _result(result){}

       bool _isResult;

       int _result;

}Result;

 

Result toTenRadix(string& sNum)

{

       if(sNum.empty())

       {

              return Result(false,-1);

       }

       //字符串逆序遍历,累加即可

       int sum = 0;

       int size = sNum.size();

       int value = 0;

       int count = 0;

       for(int i = size - 1 ; i >= 0 ; i--)

       {

              if( '0' <= sNum[i] && sNum[i] <= '9')

              {

                     value = sNum[i] - '0';

                     sum += value * ( (int) pow(2 , count));

              }

              else

              {

                     return Result(false , -1);

              }

              count++;

       }

       return Result(true, sum);

}

 

int count1(int num)

{

       if(0 == num)

       {

              return 0;

       }

       int count = 0;

       while( ( num & (num-1)) != 0 )

       {

              count++;

              num &= (num - 1);

       }

       count++; //最后一次退出一定是因为相与为0,此时包含1个1,需要累加

}

 

int getChangeTimes(int numA , int numB)

{

       int resultNum = numA ^ numB;

       //统计1的个数

       int count = count1(resultNum);

       return count;

}

8

交换某整数的奇数位和偶数位

编写程序,交换某个整数的奇数位和偶数位,使用指令越少越好(也就是说,位0与位1交换,位2与位3交换,以此类推)

 

输入:输入1个十进制整数,整数可能为负数

11

-8

输出:

7

-12

程序员面试金典

https://blog.csdn.net/qingyuanluofeng/article/details/53998915

弄错:误解题目意思,题目意思不是左移,而是奇数位和偶数位分别交换。

      1001 -> 0110

         所谓的交换 = 奇数位

关键:

1

书上解法:

牛逼,设整数为n,通过 n & 10101010 提取出奇数位的值为nOdd, 然后将nOdd向右移动1位

                     n & 01010101 提取出偶数位的值为nEven, 然后将nEven向左移动1位

                                    将nOdd 与 nEven 进行或运算,

没想到单独提取奇数位和偶数位

所以共需要5次= 提取奇数位+提取偶数位+奇数位右移1位+偶数位左移一位+奇数位与偶数位对应的数进行或运算

2 10101010转换为十六进制为0xaaaaaaa

 

int swapOddAndEvenBit(int n)

{

       int nOdd = n & (0xaaaaaaaa);

       int nEven = n & (0x55555555);

       nOdd >>= 1;

       nEven <<= 1;

       int result = nOdd | nEven;

       return result;

}

9

寻找丢失的整数

数组A包含0到n的所有整数,但其中缺了一个。在这个问题中,只用一次操作无法取得数组A里某个整数的完整内容。此外,数组A的元素皆以二进制表示,唯一可用的访问操作是“从A[i]取出第j位数据”,该操作的时间复杂度为长度。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗?

 

输入:

6(0到n中的n,接下来给出n个元素)

00000 00001 00010 00100 00101 00110(n个元素)

输出:

3

程序员面试金典

https://blog.csdn.net/qingyuanluofeng/article/details/54003221

关键:

1     通过分析最低有效位(若指定最低有效位为1,则表明每个整数的最后一位上的数字)中1和0的数字结果来确定。

    假设: 0000, 0001, 0010

       观察发现:如果n为奇数,则在最低有效位为1时,count(0)=count(1);n为偶数,count(0) = count(1) + 1

       规律: count(0) >= count(1)

       如果除去丢失的整数,统计的某最低有效位: count(0) <= count(1),则说明该丢失的整数的该最低有效位应该为0

                                                  count(0) > count(1),  则说明                                1

       再做下一次处理时,将数组中最低有效位与计算出实际有效位不等的整数全部排除,用剩下的整数进行下一个有效位

       的计算

2 bitset是一个bit对象,而不是一群bit对象

bitset<32> bitesetNum(value);//设定bit最长长度为32位,并用字符串初始化比特对象

3     //如果为空,直接返回0,必须返回0,否则递归的结果用于左移会有问题

       if( vecBitset.empty() )

       {

              return 0;

       }

       //说明丢失整数的第coulumn位为0,则只保留当前位为0的所有整数

       if(count0 <= count1)

       {

              int v = findLostNumber(vecZeros , column + 1 , columnMax);

              return (v << 1) | 0; // 插入当前结果最低有效位为0

       }

 

//除了传入需要计算的biset集合外,还需要传入当前处理的是第几位的比特

int findLostNumber(vector< bitset<32> >& vecBitset , int column , int columnMax)

{

       //如果为空,直接返回0,必须返回0,否则递归的结果用于左移会有问题

       if( vecBitset.empty() )

       {

              return 0;

       }

       if(column >= columnMax)

       {

              return 0;

       }

       vector< bitset<32> >::iterator it;

       vector< bitset<32> > vecOnes;

       vector< bitset<32> > vecZeros;

       for(it = vecBitset.begin() ; it != vecBitset.end(); it++)

       {

              bitset<32> bitsetNum = *it;

              //统计当前第i位为0或1

              int value = bitsetNum[column];

              if(value == 1)

              {

                     vecOnes.push_back(bitsetNum);

              }

              else

              {

                     vecZeros.push_back(bitsetNum);

              }

       }

       int count0 = vecZeros.size();

       int count1 = vecOnes.size();

       //说明丢失整数的第coulumn位为0,则只保留当前位为0的所有整数

       if(count0 <= count1)

       {

              int v = findLostNumber(vecZeros , column + 1 , columnMax);

              return (v << 1) | 0; // 插入当前结果最低有效位为0

       }

       else

       {

              int v = findLostNumber(vecOnes , column + 1 , columnMax);

              return (v << 1) | 1;

       }

}

 

void process()

{

       int n;

       string value;

       vector< bitset<32> > vecBitset;

       while(cin >> n)

       {

              for(int i = 0 ; i < n ; i++)

              {

                     cin >> value;

                     bitset<32> bitesetNum(value);//设定bit最长长度为32位,并用字符串初始化比特对象

                     vecBitset.push_back(bitesetNum);

              }

              //

              int result = findLostNumber(vecBitset , 0 , 32);

              cout << result << endl;

       }

}

10

通过位操作进行两点连线

有个单色屏幕存储在一个一维字节数组中,使得8个连续像素可以存放在一个字节里。屏幕宽度为w,且w可以被8整除(即一个字节不会分布在两行上),屏幕宽度可由数组长度及屏幕宽度推算得出。请实现一个函数drawHorizontalLine(byte[] screen, int width, int x1 ,int x2, int y),绘制从点(x1,y)到(x2,y)的水平线。

程序员面试金典

https://blog.csdn.net/qingyuanluofeng/article/details/54017989

分析:绘制水平线本质上是找到水平线上的起点和终点,然后连接,起点和终点都已经确认,这个应该没什么难度,由于是一维数组,

         首先明确在屏幕中:x代表水平方向,也就是实际意义上的竖轴(列),y代表垂直方向,代表了矩阵中实际意义的横轴(行)

         假设给定的像素位置为(x,y),那么它实际在一维数组的位置p=x+w*y

         所以起点(x1,y)在是screen[x1+w*y]中的字节,(x2,y)对应screen[x2+w*y]字节,

         找到两个字节后,调用drawLine函数即可绘制

书上解法:我没理解绘线的本质实际上将线上的所有像素的颜色都设置为同一个颜色。那么暴力破解解法就是遍历从(x1,y)到(x2,y)上所有

          经过的像素,设置颜色,时间复杂度为O(x2-x1)

                注意:给定的x是像素的横坐标而不是字节,一个像素占据一个bit

关键:

1 绘线的本质实际上将线上的所有像素的颜色都设置为同一个颜色

2

确定比特x1对应的字节x1Byte = x1 / 8,以及起始比特位x1Bit = x1 % 8

确定比特x2对应的字节x2Byte = x2 / 8, 以及结束比特位x2Bit = x2 % 8

如果x1Bit不为0,说明x1Byte不是完整的字节,令起始字节startByte = x1Byte + 1;否则,令startByte = x1Byte

如果x2Bit不为7,说明x2Byte不是完整的字节,令结束字节endByte = x2Byte - 1;否则,令endByte = x2Byte

将startByte~endByte中字节全部设置为0xff(即白色)

设置左边不完整字节(左边起始字节)掩码,用于后续与运算,必须将不完整字节前面x1Bit位排除,即前面x1Bit位为0,后面8-x1Bit位为1,

     所以左边掩码leftMask = 0xff >> x1Bit

设置右边不完整字节(右边最后字节)掩码,必须将x2Bit位包含,即前面x2Biit(包含x2Bit位本身)位为1,后面8-x2Bit位为0,

     所以右边掩码rightMask = ~ ( 0xff >> (x2Bit + 1) )

还需要判断x1与x2对应的字节是否在同一个字节中,因为如果在同一个字节中,需要对左边掩码和右边掩码进行与操作才能得到真实的掩码

     mask = leftMask & rightMask

        对应字节在screen中位置pos = w * y/8 + x1Byte

        对应的字节为 screen[ pos ] |= mask

        易错,容易漏掉

如果不在同一个字节,则对左边不完整字节,掩码处理

     posLeft = w * y/8 + x1Byte

        screen[ posLeft ] |= leftMask

右边不完整字节取掩码

     posRight = w * y/8 + x2Byte

        screen[ posRight ] |= leftMask    

结束

3 screen.at(pos) |= leftMask;//注意是或运算,通过1来设置颜色,其余保持字节原先的颜色

 如果用与,那么掩码中0的部分会使得像素颜色发生变化,而我们真正需要的是掩码中的1,

 掩码中的0应该不起作用,所以用或运算

 

 

 

//这里的宽度width,对应的是比特

void drawHorizontalLine(vector< bitset<8> >& screen, int width, int x1 ,int x2, int y)

{

       if(screen.empty())

       {

              return;

       }

       //判断x1和x2大小,使得x1为较小值

       if(x1 > x2)

       {

              int temp = x1;

              x1 = x2;

              x2 = x1;

       }

       //计算起始和结束字节位置

       int x1Byte = x1 / 8;

       int x1Bit = x1 % 8;

       int startByte = x1Byte;

       if(x1Bit != 0)

       {

              startByte++;

       }

       int x2Byte = x2 / 8;

       int x2Bit = x2 % 8;

       int endByte = x2Byte;

       if(x2Bit != 0)

       {

              endByte--;

       }

       int leftMask = 0xff >> x1Bit;

       int rightMask = ~ ( 0xff >> (x2Bit + 1) );

 

       //对起始到结束部分完整字节设置为白色

       for(int i = startByte ; i <= endByte ; i++)

       {

              //宽度是比特,需要转化为字节

              int pos = width/8 * y + i;

              screen.at(pos) = 0xff;

       }

 

       //判断两个x1和x2是否位于同一个字节中,易漏,注意不要

       if( x1Byte == x2Byte )

       {

              int mask = leftMask & rightMask;

              int pos = width/8 * y + x1Byte;

              screen.at(pos) |= mask;

       }

       else

       {

              //判断左边起始字节是否是不完整字节,如果是不完整字节,就对左边起始字节进行掩码运算

              if(x1Bit != 0)

              {

                     int pos = width/8 * y + x1Byte;

                     screen.at(pos) |= leftMask;//注意是或运算,通过1来设置颜色,其余保持字节原先的颜色

              }

 

              //对右边结束字节进行掩码运算

              if(x2Bit != 7)

              {

                     int pos = width/8 * y + x2Byte;

                     screen.at(pos) |= rightMask;

              }

       }

}

11

编写一个函数,不用临时变量,直接交换两个数。

输入:

3 5

输出:

5 3

程序员面试金典

https://blog.csdn.net/qingyuanluofeng/article/details/54565735

书上解法:

关键:

1还可以用异或的方式:利用异或中相同两数异或结果为0,任意数和0异或结果为该数本身

a = a^b;//假设3或5,011 和 101,异或是: 110

b = a^b;// 等同于 (a^b)^b = a

a = a^b;//等同于 (a^b)^a = b

 

void swap(int* ptrA , int* ptrB)

{

       *ptrA = *ptrA + *ptrB;

       *ptrB = *ptrA - *ptrB;

       *ptrA = *ptrA - *ptrB;

}

 

//异或进行交换

void swapXOR(int* ptrA , int* ptrB)

{

       *ptrA ^= *ptrB;

       *ptrB ^= *ptrA;

       *ptrA ^= *ptrB;

}

12

编写一个函数,将两个数字相加。不得使用+或其他算术运算符。

 

输入:

3 5

3 -5

-3 -5

0 5

输出:

8

-2

-8

5

程序员面试金典

https://blog.csdn.net/qingyuanluofeng/article/details/54588232

关键:

1

书上解法:比如759 + 674,加法的:相加和进位拆分开:

           1】759和674相加,不进位,得到323

                 2】759和674相加,只进位,得到1110

                 将1110 + 323 = 1433

                 上述只加不进位,就是异或操作

                     只进位不加,只要a和b的i-1位皆为1,总和的第i位为1,就是AND加上位移操作

//递归得加法

int addRecursive(int a ,int b)

{

       //注意递归的出口是: b为0,会导致sum为a , pass为0; 如果a为0,那么sum=0,pass为0

       if(0 == a)

       {

              return b;

       }

       if(0 == b)

       {

              return a;

       }

       //累加,但不进位,通过异或实现

       int sum = a ^ b;

       //只进位,通过与操作,然后左移一位实现

       int pass = (a & b) << 1;

       return addRecursive(sum , pass);

}

2 注意,由于负数即使右移,填充的也是1,导致while(num1 && num2)陷入死循环,最好的办法就是采用(1<

int add(int num1 , int num2)

{

       int pass = 0;

       int result = 0;

       pair resultPair;

       int resultBit;

       int count = 0;

       //注意,由于负数即使右移,填充的也是1,导致while(num1 && num2)陷入死循环,最好的办法就是采用(1<

       //while(num1 || num2)

       while(true)

       {

              //说明其中有一个是负数,直接退出循环

              if(count >= 32)

              {

                     break;

              }

              int bit1 = num1 & (1 );

              int bit2 = num2 & (1 );

              resultPair = getPassAndBit(bit1 , bit2 , pass );

              resultBit = resultPair.first;

              pass = resultPair.second;

              result |= (resultBit << count);

              num1 >>= 1;//右移一位

              num2 >>= 1;

              count++;

       }

       return result;

}

 

//计算当前位和进位,pair第一个元素为当前位,第二个元素为进位

pair getPassAndBit(int bit1 , int bit2 , int pass )

{

       //如果全为0,进位为0,当前位为0

       if( 0 == bit1 && 0 == bit2 && 0 == pass )

       {

              pair result(0, 0);

              return result;

       }

       //如果全为1,进位为1,当前位为1

       else if( 1 == bit1 && 1 == bit2 && 1 == pass)

       {

              pair result(1, 1);

              return result;

       }

       //排除全1和全0的情况后:只剩两种可能:三者异或结果为0或1

       else

       {

              //bit1,bit2,pass中有两个1,1个0,三者异或结果为0,此时当前位为0,进位为1

              if( (bit1^bit2^pass) == 0)

              {

                     pair result(0, 1);

                     return result;

              }

              //bit1,bit2,pass中有两个0,1个1,三者异或结果为1,此时当前位为1,进位为0

              else

              {

                     pair result(1, 0);

                     return result;

              }

       }

}

13

First Missing Positive

Given an unsorted integer array, find the first missing positive integer.

For example,

Given [1,2,0] return 3,

and [3,4,-1,1] return 2.

Your algorithm should run in O(n) time and uses constant space.

分析:寻找首次丢失的整数,但是给定的数组可能含有0和负数。

题目只能用O(n)时间,不能排序。

Leecode

https://blog.csdn.net/qingyuanluofeng/article/details/54944906

14

Add Binary

Given two binary strings, return their sum (also a binary string).

For example,

a = "11"

b = "1"Return "100".

分析:题目是给定两个二进制字符串,求出两者的二进制和。

Leecode

https://blog.csdn.net/qingyuanluofeng/article/details/54985268

15

Single Number

Given an array of integers, every element appears twice except for one. Find that single one.

Note:

Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

分析:一个数组中,每个元素都出现了两次,只有一个元素不是。

Leecode

https://blog.csdn.net/qingyuanluofeng/article/details/55549051

16

Single Number

Given an array of integers, every element appears three times except for one, which appears exactly once. Find that single one.

Note:

Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

分析:数组中每个元素出现了3次,只有一个元素出现了1次,找到这个元素。

必须在线性时间找到。尽量不要使用额外的空间。

Leecode

https://blog.csdn.net/qingyuanluofeng/article/details/55549604

17

Reverse Bits

Reverse bits of a given 32 bits unsigned integer.

For example, given input 43261596 (represented in binary as 00000010100101000001111010011100), return 964176192 (represented in binary as 00111001011110000010100101000000).

Follow up:

If this function is called many times, how would you optimize it?

Related problem: Reverse Integer

分析:对给定的无符号32位整数的bit位进行逆置。

Leecode

https://blog.csdn.net/qingyuanluofeng/article/details/56293588

18

Number of 1 Bits

Write a function that takes an unsigned integer and returns the number of ’1' bits it has (also known as the Hamming weight).

For example, the 32-bit integer ’11' has binary representation 00000000000000000000000000001011, so the function should return 3.

输入:此题主要是计算二进制中1的个数。

Leecode

https://blog.csdn.net/qingyuanluofeng/article/details/56294335

19

Bitwise AND of Numbers Range

Given a range [m, n] where 0 <= m <= n <= 2147483647, return the bitwise AND of all numbers in this range, inclusive.

For example, given the range [5, 7], you should return 4.

分析:bitwise:按位。题目将给定范围内的数据全部进行与操作,返回结果。

Leecode

https://blog.csdn.net/qingyuanluofeng/article/details/56313416

20

Power of Two
Given an integer, write a function to determine if it is a power of two.

分析:给定一个整数,写一个函数确定它是否是2的n次方

Leecode

https://blog.csdn.net/qingyuanluofeng/article/details/56683202

21

Add Digits

Given a non-negative integer num, repeatedly add all its digits until the result has only one digit.

For example:

Given num = 38, the process is like: 3 + 8 = 11, 1 + 1 = 2. Since 2 has only one digit, return it.

Follow up:

Could you do it without any loop/recursion in O(1) runtime?

分析:这里的一位是指在十进制下面,只剩一位数

Leecode

https://blog.csdn.net/qingyuanluofeng/article/details/56916070

22

Single Number III

Given an array of numbers nums, in which exactly two elements appear only once and all the other

elements appear exactly twice. Find the two elements that appear only once.

For example:

Given nums = [1, 2, 1, 3, 2, 5], return [3, 5].

Note:

The order of the result is not important. So in the above example, [5, 3] is also correct.

Your algorithm should run in linear runtime complexity. Could you implement it using only

constant space complexity?

分析:数组中只有两个数各自出现一次,其余数出现两次。需要在线性时间和常量空间求解该问题。

Leecode

https://blog.csdn.net/qingyuanluofeng/article/details/56962533

23

Maximum Product of Word Lengths

Given a string array words, find the maximum value of length(word[i]) * length(word[j]) where the two words do not share common letters. You may assume that each word will contain only lower case letters. If no such two words exist, return 0.

Example 1:

Given ["abcw", "baz", "foo", "bar", "xtfn", "abcdef"]

Return 16

The two words can be "abcw", "xtfn".

Example 2:

Given ["a", "ab", "abc", "d", "cd", "bcd", "abcd"]

Return 4

The two words can be "ab", "cd".

Example 3:

Given ["a", "aa", "aaa", "aaaa"]

Return 0

No such pair of words.

分析:本题实际上是求不包含相同字母的两个字符串长度的最大乘积

Leecode

https://blog.csdn.net/qingyuanluofeng/article/details/58616845

24

Counting Bits

Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1's in their binary representation and return them as an array.

Example:

For num = 5 you should return [0,1,1,2,1,2].

Follow up:

It is very easy to come up with a solution with run time O(n*sizeof(integer)). But can you do it in linear time O(n) /possibly in a single pass?

Space complexity should be O(n).

Can you do it like a boss? Do it without using any builtin function like __builtin_popcount in c++ or in any other language.

分析:题目是要求给定数num,中0~num的各个数1的位数,

举例:num=9

[0 , 1 , 1 , 2, 1 , 2, 2, 3, 1, 2]

bun = 16

[0 , 1 , 1 , 2, 1 , 2, 2, 3, 1, 2, 2, 3, 2 , 3, 3, 4, 1]

题目要求尽量在O(n)时间完成。

Leecode

https://blog.csdn.net/qingyuanluofeng/article/details/59111789

25

如何找出数组中唯一的重复元素

数字1~1000放在含有1001个元素的数组中,其中只有唯一的一个元素值重复,

其他数字均只出现一次。设计一个算法,将重复元素找出来,要求每个数组元素

只能访问一次。如果不使用辅助存储空间,能否设计一个算法实现?

Python程序员面试算法宝典

https://blog.csdn.net/qingyuanluofeng/article/details/92077343

26

如何找出数组中丢失的数

给定一个由n-1个整数组成的未排序的数组序列,其元素都是1到n中的不同的整数。

请写出一个寻找数组序列中缺失整数的线性时间算法。

Python程序员面试算法宝典

https://blog.csdn.net/qingyuanluofeng/article/details/92389996

27

如何找出数组中出现奇数次的数

数组中有N+2个数,其中,N个数出现了偶数次,2个数出现了奇数次(

这两个数不相等),请用O(1)的空间复杂度,找出这两个数。

注意:不需要知道具体位置,只需要找出这两个数。

Python程序员面试算法宝典

https://blog.csdn.net/qingyuanluofeng/article/details/92428203

28

如何找出数组中出现1次的数

一个数组里,除了三个数是唯一出现的,其余的数都出现偶数次,找出

这三个数中的任意一个。比如数组序列为[1,2,4,5,6,4,2],只有

1,5,6这三个数字是唯一出现的,数字2与4均出现了偶数次(2次),

只需要输出数字1,5,6中的任意一个就行。

Python程序员面试算法宝典

https://blog.csdn.net/qingyuanluofeng/article/details/92803196

29

如何判断一个数是否为2的n次方

Python程序员面试算法宝典

https://blog.csdn.net/qingyuanluofeng/article/details/95919266

30

如何求二进制数中的1的个数
给定一个整数,输出这个整数的二进制表示中1的个数。例如:

给定整数7,其二进制表示为111,因此输出结果为3.

Python程序员面试算法宝典

https://blog.csdn.net/qingyuanluofeng/article/details/96630872

31

如何不使用^操作符实现异或运算

Python程序员面试算法宝典

https://blog.csdn.net/qingyuanluofeng/article/details/96725215

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

参考:
[1]计算机考研--机试指南,王道论坛 组编
[2]剑指offer
[3]算法设计与分析
[4]编程之美
[5]程序员面试金典
[6]leecode
[7]Python
程序员面试算法宝典
[8]刘汝佳算法竞赛入门经典
[9]算法导论
[10]编程珠玑

 

 

 

 

 

你可能感兴趣的:(算法,64式)