数字之魅--笔试题

1、整型数V的二进制中1的个数

//普通解法:除以2,看余数
int Count(int v)
{
    int num = 0;
    while(v)
    {
        if(v % 2 == 1)
            ++ num;
        v /= 2;
    }
    return num;
}

//使用位移
int Count(int v)
{
    int num = 0;
    while(v)
    {
        num += v & 1;
        v >>= 1;
    }
    return num;
}

位移的思路,当输入i是正数时没有问题,但当输入的i是一个负数时,不但不能得到正确的1的个数,还将导致死循环。以负数0x80000000为例,右移一位的时候,并不是简单地把最高位的1移到第二位变成0x40000000,而是0xC0000000。这是因为移位前是个负数,仍然要保证移位后是个负数,因此移位后的最高位会设为1。如果一直做右移运算,最终这个数字就会变成0xFFFFFFFF而陷入死循环。
为了避免死循环,我们可以不右移输入的数字i。首先i和1做与运算,判断i的最低位是不是为1。接着把1左移一位得到2,再和i做与运算,就能判断i的次高位是不是1……这样反复左移,每次都能判断i的其中一位是不是1。基于此,我们得到如下代码:

int Count1(int v)
{
    int num = 0;
    unsigned int flag = 1;
    while(flag)
    {
        if(v & flag)
            ++ num;
        flag <<= 1;
    }
    return num;
}

整数A 和B 的二进制表示中有多少位是不同的? 
把两个整数 A, B 异或, 然后又回归到判断 1 的个数

int Count(int a, int b)
{
    int num = 0;
    int v = a ^ b;
    while(v)
    {
       v &= (v-1);
       num++;
    }
    return num;
}

整数n,判断它是否为2的方幂(即二进制中只有一个1)
解答:n>0 && (n&(n-1)==0)
原理:由于2的N次方的数二进制表示是第1位为1,其余为0,而x-1(假如x为2的N次方)得到的数的二进制表示恰恰是第1位为0,其余为1,两者相与,得到的结果就为0,否则结果肯定不为0

2、N的阶乘中末尾有几个0

如果N!= K×10M,且K不能被10整除,那么N!末尾有M个0。再考虑对N!进行质因数分解,N!=(2^x)×(3^y)×(5^z)…,由于10 = 2×5,所以M只跟X和Z相关,每一对2和5相乘可以得到一个10,于是M = min(X, Z)。不难看出X大于等于Z,因为能被2整除的数出现的频率比能被5整除的数高得多,所以把公式简化为M = Z。问题相当于求N!中有质因数5的个数

//直接计算i(i=1,2,...,N)的因式分解中5的指数
int numberOfFive(int N)
{
    int ret = 0;
    for(int i = 1; i <= N; i++)
    {
        int j = i;
        while(j%5 == 0)
        {
            ret++;
            j /= 5;
        }
    }
    return ret;
}

// N!中含有质因数5的个数: Z = [N/5] + [N/5^2] + [N/5^3]+...
int numberOfFive2(int N)
{
    int ret = 0;
    while(N)
    {
        ret += N / 5;
        N /= 5;
    }
    return ret;
}

N!的二进制表示中最低位1的位置。给定一个整数N,求N!二进制表示的最低位1在第几位?例如:给定N=3,N!=6,那么N!的二进制表示(110)的最低位1在第二位。
这个问题实际上等同于求N!含有质因数2的个数。即答案等于N!含有质因数2的个数加1。
N!中含有质因数2的个数,等于 N/2 + N/4 + N/8 + N/16 + …

int lowestOne(int N)
{
    int ret = 0;
    while(N)
    {
        N >>= 1;
        ret += N;
    }
    return ret;
}

3、1的个数

给定一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。
例如输入12,从1到12这些整数中包含1 的数字有1,10,11和12,1一共出现了5次。

//统计一个整数的十进制表示中1出现的次数
unsigned int CountOneInAInteger(unsigned int n)
{
    unsigned int count = 0;
    while(n)
    {
        if(n % 10 == 1)
            count++;
        n /= 10;
    }
    return count;
}
//统计从1到n这n个整数的十进制表示中1出现的次数
unsigned int CountOneBitween1AndN_Solution1(unsigned int n)
{
    unsigned int count = 0;
    for(unsigned int i = 1; i <= n; i++)
        count += CountOneInAInteger(i); //穷举法
    return count;
}  

//优化的算法,来自《编程之美》,比较麻烦,只能看明白
unsigned int CountOneBitween1AndN_Solution2(unsigned int n)
{
    unsigned int count = 0;
    unsigned int factor = 1; //计算每一位上出现1的次数,从个位开始
    //每一位上出现1的次数与它的高位数字、低位数字、以及自身都有关系
    //比如12345,如果计算百位上出现1的次数,这要考虑高位数字12,以及低位数字45有关
    unsigned int lowNum = 0;   //低位数字
    unsigned int highNum = 0;  //高位数字
    unsigned int curNum = 0;   //当前位
    while(n / factor != 0)
    {
        lowNum = n - (n / factor) * factor;
        highNum = n / (factor * 10);
        curNum = (n / factor) % 10;
        switch(curNum)
        {
        case 0: //当前位的数字为 0
            count += highNum * factor; //只与高位有关
            break;
        case 1:
            count += highNum * factor + lowNum + 1; //与高位低位都有关
            break;
        default:
            count += (highNum + 1) * factor; //与高位有关
            break;
        }
        factor *= 10; //计算下一位
    }
    return count;
}  

4、最大公约数

//辗转相除法:f(x, y)= f(y, x % y)(y>0)
int gcd(int x, int y)
{
    if(y == 0)
        return x;
    else return gcd(y, x%y);
}

//辗转相减法:f(x, y)= f(x-y, y)(x>y)
int gcd(int x, int y)
{
    if(x < y)
        return gcd(y, x);
    if(y == 0)
        return x;
    else
        return gcd(x - y, y);
}

/*
x is even, y is even, f(x, y) = 2 * f(x>>1, y>>1)
x is even, y is odd, f(x,y) = f(x>>1, y)
x is odd, y is even, f(x,y) = f(x, y>>1)
x is odd, y is odd, f(x,y) = f(y, x-y)
*/
int gcd(int x, int y)
{
    if(x < y)
        return gcd(y, x);
    if(y == 0)
        return x;
    else
    {
        if(IsEven(x))
        {
            if(IsEven(y))
                return (gcd(x >> 1, y >> 1) << 1);
            else
                return gcd(x >> 1, y);
        }
        else
        {
            if(IsEven(y))
                return gcd(x, y >> 1);
            else
                return gcd(y, x - y);
        }
    }
}

5、判断一个自然数N是否是某个数的平方。当然不能使用开方sqrt()函数运算。

方法1:遍历从1到N的数字,求取平方并和N进行比较。如果平方小于N,则继续遍历;如果等于N,则成功退出;如果大于N,则失败退出。时间复杂度为O(n)。

方法2:使用二分查找法,对1到N之间的数字进行判断。复杂度为O(logN)。

unsigned int sqrt(unsigned int x)
{
    // x的最大值不超过max*max
    unsigned int max = (1 << (sizeof(x)/2*8))-1; //65535
    if (max*max < x) return max;

    unsigned int low = 0;
    unsigned int high = max-1;

    unsigned int mid = 0;
    while(1)
    {
        mid = (low+high)/2;
        if (x < mid * mid)
            high = mid-1;
        else if((mid+1)*(mid+1) <= x)
            low = mid+1;
        else //if(mid * mid <= x && x < (mid+1)*(mid+1))
            break;
    }

    return  mid;
}

方法3:由于(n+1)^2 = n^2 + 2n + 1 = ...= 1 + (2*1 + 1) + (2*2 + 1) + ... + (2*n + 1)
注意到这些项构成了等差数列(每项之间相差2),所以我们可以比较 N-1, N - 1 - 3, N - 1 - 3 - 5 ... 和0的关系。如果大于0,则继续减;如果等于0,则成功退出;如果小于 0,则失败退出。
复杂度为O(n)。不过方法3中利用加减法替换掉了方法1中的乘法,所以速度会更快些。

int square(int n)
{
    int i = 1;
    n = n - i;
    while(n > 0)
    {
        i += 2;
        n -= i;
    }
    if(n == 0)        //是某个数的平方
        return 1;
    else                //不是某个数的平方
        return 0;
} 

6、怎么能随即生成m个数,让其和等于n?

题目:假设生成26个非负随机数,要求其和是301,求程序生成此列数字
 
解法一:关于此种算法原理,可以假想是一根长301单位的绳子,然后随即在其上面截25个点,于是得到26根子绳,这26根子绳之和恰好就是绳子总长301。
于是可以:
1 初始化27的数组 
2 该数组0位和26位分别为0和301,其他位置填充0到301之间的随机数字 
3 对数组排序 
4 数组相邻数字相减,所得的26个差值即为所求数列。

解法二:这种方案利用了非负这个不显眼的条件,思路非常简单,就是将1随机加到一个26位数组中,随机301次,有点剑走偏锋,另辟蹊径。

 

作者:阿凡卢

出处:http://www.cnblogs.com/luxiaoxun/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

http://www.cnblogs.com/luxiaoxun/archive/2012/11/20/2779339.html

时间: 2024-09-16 12:16:27

数字之魅--笔试题的相关文章

经典算法(9) 从归并排序到数列的逆序数对(微软笔试题)

首先来看看原题 微软2010年笔试题 在一个排列中,如果一对数的前后位置与大小顺序相反 ,即前面的数大于后面的数,那么它们就称为一个逆序数对.一个排列中逆序的总数就称为这个排列的逆序 数.如{2,4,3,1}中,2和1,4和3,4和1,3和1是逆序数对,因此整个数组的逆序数对个数为4,现在给定 一数组,要求统计出该数组的逆序数对个数. 计算数列的逆序数对个数最简单的方便就最从前向后依 次统计每个数字与它后面的数字是否能组成逆序数对.代码如下: #include <stdio.h> int ma

算法-京东在线笔试题,关于排列组合的问题

问题描述 京东在线笔试题,关于排列组合的问题 考虑数字序列{1,3,4,2,6,7,5,5,8,10,9,10,7,17},任取其中几个数字相加,使得到的和为29, 则不同的组合有几种?(第2,第3,第7,第14个数的组合与第2,第3,第13,第14个数的 组合看起来是一样的,都是3,4,5,17,那么这里只视为一种) 解决方案 修正下,96种http://ideone.com/kNl4Mw using System; using System.Linq; using System.Collec

JS经典正则表达式笔试题汇总_javascript技巧

本文实例总结了JS经典正则表达式笔试题.分享给大家供大家参考,具体如下: 一.复习字符串的传统操作 如何获取一个字符串中的数字字符,并按数组形式输出,如 dgfhfgh254bhku289fgdhdy675gfh 输出[254,289,675] 分析:循环用charAt()的方法获取到每一个子字符串,判断他是不是在0~9之间,是就把他扔到准备好的数组里 var str="dgfhfgh254bhku289fgdhdy675gfh"; findNum(str); function fin

网页转换-请问设计了一套笔试题(word2007版),如何转换成网页格式并具备倒计时功能?

问题描述 请问设计了一套笔试题(word2007版),如何转换成网页格式并具备倒计时功能? 我设计了一套人格测试题,都是选择题,用的是word07版,希望将答题时间限定在15分钟内,在候选人点击进去时便开始倒计时,咨询了一位IT朋友,她说要转换成网页格式并下一个插件,请教各位大神,应该如何做才能实现计划功能?谢谢! 解决方案 http://www.officezu.com/a/word/6203.html 解决方案二: 网页的话,js有很多第三方计时库

阿里巴巴一道智力题笔试题

问题描述 阿里巴巴一道智力题笔试题 有三张牌A,B,C,其中一张是King.如果你押中了King,那么就获胜,否则就输.现在你选择了押其中的一张牌1,电脑帮你排除了另外两张牌中的一张2,那么你是否重新选择押3,从而更容易获胜? http://www.manong1024.com/q/403 解决方案 google 三扇门问题真怀疑这是不是阿里的题,感觉很低级很low,像庙会灯谜上的题. 解决方案二: 假设挑选A其为king的概率p=1/3剩下的BC中为king的概率p=2/3.假设主持人又给你排

C++笔试题汇总(45题)

本文转自:<程序员必看c++笔试题汇总>,经过整理正文如下: 本文通过对程序员笔试过程的总结,对程序员c++笔试题进行了汇总.希望能与大家共同分享.下面是一些常见题型: 1.求下面函数的返回值(微软) { int countx = 0; while(x) { countx ++; x = x&(x-1); } return countx; } 假定x = 9999. 答案:8 思路:将x转化为2进制,看含有的1的个数. 2. 什么是"引用"?申明和使用"引

程序员必看 c++笔试题汇总

本文通过对程序员笔试过程的总结,对程序员c++笔试题进行了汇总.希望能与大家共同分享.下面是一些常见题型: 1.求下面函数的返回值(微软) {   int countx = 0;   while(x)   {   countx ++;   x = x&(x-1);   }   return countx;   }  假定x = 9999. 答案:8 思路:将x转化为2进制,看含有的1的个数. 2. 什么是"引用"?申明和使用"引用"要注意哪些问题? 答:引用

代码分析-一道Java笔试题,求解答(关于类的加载与初始化)

问题描述 一道Java笔试题,求解答(关于类的加载与初始化) 自己查了一些资料,还是看不懂这个程序的输出结果,求各位详细解释初始化和执行过程,谢! public class Alibaba { public static int k = 0; public static Alibaba t1 = new Alibaba("t1"); public static Alibaba t2 = new Alibaba("t2"); public static int i =

java算法题,公司的笔试题

问题描述 java算法题,公司的笔试题 suppose you have N cakes, N is an interger>0 // at each time, you can either eat 1 cake, or 2 cakes or 3 cakes // PROBLEM: How many ways can you eat all N cakes // for example, N = 4, (1,2,1) and (1,1,2) are considered to be diffe