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可以通过表达式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`)
- 每个无符号整数都可以表示为一个二进制数。对于任意的二进制数,
-
计数:
- 每次通过
n &= (n - 1)来消去最右边的1,并增加计数。重复此过程直到n为0。
- 每次通过
算法步骤
- 初始化:设置一个计数器
count为0,用于统计1的数量。 - 循环:
- 当
n不为0时,执行以下操作:n &= (n - 1):消去最右边的1。count++:每次消去后增加计数器。
- 当
- 返回计数:当
n为0时,返回计数器的值,即为汉明重量。
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 的特性,快速完成计数。这种方法在许多需要处理二进制位的场合都非常实用。
浙公网安备 33010602011771号