lintcode天梯4- 数学与二进制运算

本文解析了LintCode中的七个经典数学与位操作习题,包括位翻转、快速幂运算、二叉搜索树计数等,并提供了详细的算法分析及C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LintCode Ladder4 - Math$Bit Manipulation

1、Flip Bits

题目:给你两个数字A和B,问你需要改变A的二进制位的几个位使其变成B。

Example:
A = 31(11111)
B = 14(01110)
return 2;
只需要修改第一位和第5个二进制位即可。

分析:
从题目的意思,我们可以直接比较所有对应的二进制位,因为A和B都是32位的整数。我们可以直接比较所有的32位,记录不同的位置的个数即可。
继续想,既然是相同的位置对赢得0-1不同,那不就是异或操作了吗,于是我们可以领 C = A ^ B.计算C的1的个数就是最终的结果。

Code:

class Solution {
public:
    /**
     *@param a, b: Two integer
     *return: An integer
     */
    int bitSwapRequired(int a, int b) {
        // write your code here
        int cnt = 0, x = a ^ b;
        for(int i = 0;i < 32;i++){
            cnt += ((x & (1 << i)) != 0); 

        }
        return cnt ;
    }
};

2、O(1) Check Power of 2

题目:使用O(1)的时间,判断一个数n是不是2的幂次方。

Example:
n = 4, return true;
n = 5, return false;

分析:
1、如果是一个数n = 2 ^ i.只需要对这个n判断是否能够被2除,到达1。如果可以达到1就return true;else return false。
2、但是题目要求是O(1)的操作,上面的解法显然不是O(1)的操作,而是O(logn)。分析一个一个数n如果可以表示成
n = 2 ^ i, (i>=0)。
n = (1000..000) 首先1个1,接着i个0。
n-1 = (0111..111) 首先1个0,接着i个1.
而且有 n & (n-1) = 0。
于是得到计算公式,n满足上式的都是2的幂次方。

Code:

class Solution {
public:
    /*
     * @param n: An integer
     * @return: True or false
     */
    bool checkPowerOf2(int n) {
        // write your code here
        if(n<=0) return 0;
        return (n&(n-1))==0;
    }
};

3、Trailing Zeros

题目:给你一个数n,计算n!的末尾的0的个数。

Example:
11! = 39916800, so should return 2.

分析:
对于这个题,我们可以想到一个知识,怎么才能在末尾出现0,一个数k * 10会在末尾出现一个0,又因为10可以分解素因子10 = 2 * 5。于是我们只需要知道n! 中素因子分解后,2的个数count(2)和5的个数count(5)的最小值即可。answer = min(count(2), count(5))。
1、根据素因子分解的原理,count(2)>=count(5).
2、计算出count(5)的个数。
3、根据 Legendre’s formula
vp(n!)=1npi 链接

Code:

class Solution {
 public:
    // param n : description of n
    // return: description of return 
    long long trailingZeros(long long n) {
        long long cnt = 0;
        while(n){
            cnt += n / 5;
            n /= 5;
        }
        return cnt;
    }
};

4、Update Bits

题目描述:给出两个32位的整数N和M,以及两个二进制位的位置i和j。写一个方法来使得N中的第i到j位等于M(M会是N中从第i为开始到第j位的子串)

Example:
给出N = (10000000000)2,
M = (10101)2, i = 2, j = 6
返回 N = (10001010100)2

分析:
我们可以直接想到,让N减去[i-j]对应位的值,再加上M左移i位的值,就是替换之后的值。
1、将N转化为二进制,计算[i-j]对应的位的值t,(n-t)+(m<

class Solution {
public:
    /**
     *@param n, m: Two integer
     *@param i, j: Two bit positions
     *return: An integer
     * 将n分成三段 a[0-i) b[i-j] c(j-N]
     * 掩码的问题,需要仔细考虑
     */
    int updateBits(int n, int m, int i, int j) {
        // write your code here
        int mask;
        if(j<31){
            mask=~((1<<(j+1))-(1<<i));
        }else{
            mask=(1<<i)-1;
        }
        return (m<<i)+(n&mask);

    }
};

5、Unique Binary Search Trees

题目:给出 n,问由 1…n 为节点组成的不同的二叉查找树有多少种?

分析:这是有公式的题目,问题是能不能记住这个公式。
h(n)=(4i2)h(n1)n+1
h(1)=1

Code:

class Solution {
public:
    /**
     * @paramn n: An integer
     * @return: An integer
     * catalan Number
     * h(n)=((4*n-2)/(n+1))*h(n-1);
     */
    int numTrees(int n) {
        // write your code here
        if(n==0) return 1;

        long long h = 1; //防止数值上溢
        for(int i=2;i<=n;i++){
            h = ((4*i-2)*h/(i+1));
        }
        return h; 

    }
};

6、Fast Power

题目:计算 an%b 的值,其中a,b和n都是32位的整数。

分析:
经典的二分快速幂,
a^n%b == a^(n/2)%b * a^(n/2)%b; n%2==0;
a^n%b == a^(n/2)%b * a^(n/2)%b * a%b; n%2==1;

Code:

class Solution {
public:
    /*
     * @param a, b, n: 32bit integers
     * @return: An integer
     */

    int fastPower(int a,int b,int n){//bud
        if(n==0) return 1%b;
        long long ans=1;
        long long x=a;
        while(n){

            if(n&1) ans=ans*(x%b)%b;

            x=((x%b)*(x%b))%b;

            n=n>>1;

        }
        return ans;

    }

    int fastPower1(int a,int b,int n){//递归形式,当然也有迭代形式
        long long ans=1;
        if(n==0) return 1%b;
        if(n==1) return a%b;
        long long x=fastPower(a,b,n>>1);//注意中间精度溢出

        ans=((x%b)*(x%b))%b;
        if(n&1){//n=2*k+1
            ans=(ans*(a%b))%b;
        }
        return ans;
    }
};

7、Binary Representation

题目:给定一个数将其转换为二进制(均用字符串表示),如果这个数的小数部分不能在 32 个字符之内来精确地表示,则返回 “ERROR”。

Example:
n = “3.72”, 返回 “ERROR”.
n = “3.5”, 返回 “11.1”.

分析:这个题其实很简单,就是模拟的时候需要注意一些问题。
1、找到小数点,分成两部分处理,整数和小数。
2、小数部分是每次乘以2
3、整数部分是除以2.
4、注意小数的不能满足的情况。

Code:

class Solution {
public:
    /**
     *@param n: Given a decimal number that is passed in as a string
     *@return: A string
     */

    string Int2Binanry(string n){
        string s = "";
        int t = 0;
        for(int i=0;i<n.size();i++){
            t = t*10 + (n[i] - '0');
        }
        if(t==0) s="0";
        while(t){
            s += char(t%2 + '0');
            t /= 2;
        }
        reverse(s.begin(),s.end());

        return s;
    }

    //处理小数部分
    string DecBinary(string n){
        string s = "";
        long long t = 0; // long long 防止乘法越界上溢
        for(int i=0;i<n.size();i++){
            t = t*10 + (n[i] - '0');
        }
        int k = 0;
        long long m = (long long)pow(10,n.size());
        //cout<<t<<" "<<m<<endl;
        while(k<32){
            s += (t*2 / m) + '0';
            t = t * 2 % m;
            if(t==0) break;
            k ++;
        }
        if(k >= 32) s = "2";
        return s;
    }

    string binaryRepresentation(string n) {
        // wirte your code here
        if(find(n.begin(), n.end(), '.') == n.end()) n += '.';

        //cout<<n<<endl;
        string::iterator it = find(n.begin(), n.end(), '.');
        string f(n.begin(),it);
        string d(it+1,n.end());
        //cout<<f<<endl;
        //cout<<d<<endl;
        string fs = Int2Binanry(f);
        string ds = Dec2Binary(d);

        if(ds == "2") return "ERROR";

        if(ds=="" || ds=="0") return fs;
        return fs+'.'+ds;

    }
};

ps: 欢迎批评指正,喵~

### PTA 团体程序设计天梯赛 L1 题目及解析 #### 关于PTA团体程序设计天梯赛 PTA(Programming Teaching Assistant)是一个在线编程评测平台,广泛用于高校计算机课程的教学以及竞赛训练。团体程序设计天梯赛是一项面向全国大学生的编程比赛,分为多个级别,其中L1是最基础的部分,主要考察选手的基础算法能力和代码实现能力。 以下是关于L1级别的几道经典题目及其解答思路: --- #### **L1-1 编程解决一切 (5分)** **问题描述**: 输入一个整数N,输出其二进制表示形式中的'1'的数量。 **解决方案**: 可以通过位运算来统计二进制中'1'的数量。具体方法如下:每次将数字`n-1`按位操作后,会消除最低位的一个‘1’,直到整个数字变为零为止。这种方法的时间复杂度为O(k),k为二进制中'1'的数量[^2]。 ```python def count_ones(n): count = 0 while n: n &= (n - 1) # 清除最低位的1 count += 1 return count # 测试样例 print(count_ones(9)) # 输出应为2 ``` --- #### **L1-2 字符串反转 (10分)** **问题描述**: 给定一个字符串S,将其逆序输出。如果输入为空,则返回空字符串。 **解决方案**: 使用Python内置切片功能可以轻松完成字符串反转的任务。对于其他语言如C++或Java,可以通过双指针法交换首尾字符逐步实现反转[^3]。 ```python def reverse_string(s): return s[::-1] # 测试样例 print(reverse_string("hello")) # 输出应为"olleh" ``` --- #### **L1-3 数字求和 (15分)** **问题描述**: 输入一串由空格分隔的正整数序列,计算这些数字之和并输出结果。注意处理可能存在的非法数据情况。 **解决方案**: 将输入按照空格分割成列表,逐一转换为整型数值后再累加即可。为了增强鲁棒性,在实际应用中还需要加入异常捕获机制以应对潜在错误输入[^4]。 ```python try: numbers = list(map(int, input().split())) total_sum = sum(numbers) print(total_sum) except ValueError as e: print(f"Error: {e}") ``` --- #### **L1-4 判断素数 (20分)** **问题描述**: 对给定范围内的所有自然数判断是否为质数,并打印所有的质数集合。 **解决方案**: 质数是指除了1和它本身外无法被任何其它数整除的大于1的自然数。一种高效的检测方式是从2到sqrt(N)之间遍历因子是否存在;或者采用埃拉托斯特尼筛法预先筛选出一定区间内的全部质数[^5]。 ```python import math def is_prime(num): if num < 2: return False sqrt_num = int(math.sqrt(num)) for i in range(2, sqrt_num + 1): if num % i == 0: return False return True # 打印指定范围内所有质数 lower, upper = map(int, input().split()) primes = [i for i in range(lower, upper+1) if is_prime(i)] print(primes) ``` --- #### **L1-5 排列组合计数 (25分)** **问题描述**: 计算从M个不同元素里选取N个的不同排列数目P(M,N)=M!/(M-N)! 和组合数目C(M,N)=P(M,N)/N!= M!/((M-N)!*N!) 。 **解决方案**: 运用阶乘定义直接展开公式进行递推计算能够有效减少重复劳动量的同时提高精度控制水平[^6]。 ```python from functools import reduce def factorial(x): return reduce(lambda a,b:a*b,range(1,x+1),1) m,n=map(int,input().strip().split()) if m>=n and n>0 : pmn=factorial(m)//factorial(m-n) cmn=pmn//factorial(n) else: raise Exception('Invalid Input') print(pmn,cmn) ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值