Offer68题 Day4

面试题 14- I. 剪绳子

#include <iostream>
#include <vector>
using namespace std;

class Solution {
public:
	static int cuttingBamboo(const int bamboo_len) {
		vector<int> dp(bamboo_len+1,0);      // dp数组存放乘积max
		if(bamboo_len<=1) return 0;					// 切割无效
		for(int i=2;i<=bamboo_len;i++)              // i表示绳子的长度
		{
			for(int j=1;j<i;j++)                    // 在长i的绳子的j处切割
			{
				dp[i]=max(dp[i], max(j*(i-j),j*dp[i-j]));
			}
		}
		return dp[bamboo_len];
	}
};

int main()
{
	constexpr int bamboo_len = 10;
	cout << "Maximum product for bamboo length " << bamboo_len << " is: " << Solution::cuttingBamboo(bamboo_len) << endl;
	return 0;
}

面试题 14- II. 剪绳子 II

class Solution {
public:
    int cuttingBamboo(int bamboo_len) {  
        // 不能用动态规划,大数组溢出,乘法溢出,longlong也不行
        // 用贪心,每次拆成n个3,如果剩下是4,则保留4,然后相乘
        if(bamboo_len<=1) return 0;
        if(bamboo_len==2) return 1;       //  1*1
        if(bamboo_len==3) return 2;       //  1*2
        if(bamboo_len==4) return 4;       //  2*2
        long long result=1;
        constexpr int MOD=1000000007;
        while(bamboo_len>4){
            result=(result*3)%MOD;
            bamboo_len-=3;
        }
        result=(result*bamboo_len)%MOD;

        return static_cast<int>(result);
    }
};

/*
时间复杂度:O(bamboo_len)(最坏情况下)
空间复杂度:O(1)
*/


LCR 133. 位 1 的个数


class Solution {
public:
    int hammingWeight(uint32_t n) {   
        int ans=0;
        while(n){
            ans+=n&1; // 判断最低为是否为1,是ans+1,不是ans+0;
            n>>=1;    // n右移一位
        }
        return ans;
    }
};

// 时间复杂度是O(n), n是整数二进制的位数

方法二:使用 Brian Kernighan 算法

Brian Kernighan 算法是一种高效的计算二进制表示中 1 的个数的技巧。其核心思想是利用位运算,通过每次消去最右边的 1 来逐步减少计数。下面是对这个算法的详细讲解:

算法原理

  1. 位运算

    • 每个无符号整数都可以表示为一个二进制数。对于任意的二进制数,1 的个数称为汉明重量。
    • 二进制数的最右边的 1 可以通过表达式 n & (n - 1) 来消去。这是因为:
      • n - 1 会把 n 的最右边的 1 变为 0,并把该位右边的所有位变为 1
      • 例如,若 n = 12(即 1100),则 n - 1 = 11(即 1011)。
        n:      1100
        n - 1:  1011
        ----------------
        n & (n - 1): 1000  (消去最右边的 `1`)
        
  2. 计数

    • 每次通过 n &= (n - 1) 来消去最右边的 1,并增加计数。重复此过程直到 n0

算法步骤

  1. 初始化:设置一个计数器 count0,用于统计 1 的数量。
  2. 循环
    • n 不为 0 时,执行以下操作:
      • n &= (n - 1):消去最右边的 1
      • count++:每次消去后增加计数器。
  3. 返回计数:当 n0 时,返回计数器的值,即为汉明重量。

C++ 代码实现

下面是该算法的 C++ 代码实现:

#include <iostream>
#include <string>

class Solution {
public:
    static int hammingWeight(unsigned int n) {
        int count = 0; // 初始化计数器
        while (n) {    // 当 n 不为 0 时继续循环
            n &= (n - 1); // 消去最右边的 1
            count++;      // 增加计数
        }
        return count;   // 返回汉明重量
    }
};

int main() {
    std::string binaryStr = "00000000000000000000000000001011"; // 示例二进制字符串
    unsigned int n = std::stoul(binaryStr, nullptr, 2); // 将二进制字符串转换为无符号整数
    std::cout << "Hamming weight: " << Solution::hammingWeight(n) << std::endl; // 输出汉明重量
    return 0;
}

复杂度分析

  • 时间复杂度O(k),其中 k 是二进制中 1 的数量。相比于逐位检查的 O(b),这个方法在 1 的数量较少时会更高效。
  • 空间复杂度O(1),只使用了常量级的额外空间,没有使用任何额外的数据结构。

总结

使用 Brian Kernighan 算法是一种非常高效的计算二进制数中 1 的数量的方法。它通过位运算的方式,利用消去最右边 1 的特性,快速完成计数。这种方法在许多需要处理二进制位的场合都非常实用。

posted @ 2024-10-30 21:02  itsinsane  阅读(22)  评论(0)    收藏  举报