力扣338. 比特位计数

第一百一十天 --- 力扣338. 比特位计数

  • 题目一
    • 思路
      • 常规
      • 进阶(DP)
        • 最低设置位
        • 最高有效位
        • 最低有效位
    • 代码
      • 常规
      • 进阶

题目一

力扣:338. 比特位计数

力扣338. 比特位计数_第1张图片
力扣338. 比特位计数_第2张图片

思路

常规

对1到n每个数求一下他们中有多少个1即可,这种思路属于直接模拟。时间复杂度较高 : O(nlgn)。

进阶(DP)

我们自己写一些数,观察二进制位变化可得知,这些东西是有规律的,如果每次都重新计算,会造成大量重复计算,所以我们要观察好,利用已知的一些规律,用已经计算过的,来推出新的数的结果,所以想到了DP。

最低设置位

我们现在处理到了第 i 个数,那么0到i-1都是处理过的,第i个数中的1的数量=比i少一个1的数(一定小于i本身,属于已经计算过的)的1的数量+1。
所以递推关系式为:

ans[i] = ans[i&(i - 1)] + 1
(i&(i - 1))的作用就是干掉最右面的第一个1,因为少了最右面的一个1,所以一定小于i。

最高有效位

除了上面的方法,我们还可以通过观察1的变化来推导递推关系式。
力扣338. 比特位计数_第3张图片

最低有效位

1、以上面的图为例,两位的3求好之后,如果我们为其扩充到3位数,那么就左移一位就行,会产生两个新的数,即最后一位是0或者1。
2、从上面就可以知道如何从已求出的数推知新数的方法。所以拿到一个数,先右移一位,找到与之对应的已经求过的数,再加上最后一位即可。

代码

常规

class Solution {
public:
	int number(int n) {//复杂度是O(lgN),求1的个数
		int ans = 0;
		while (n > 0) {
			n = n & (n - 1);
			ans++;
		}
		return ans;
	}
	vector<int> countBits(int n) {
		vector<int> ans(n + 1, 0);
		for (int i = 1; i <= n; i++) {
			int num = number(i);
			ans[i] = num;
		}
		return ans;
	}
};


所有代码均以通过力扣测试
(经过多次测试最短时间为):
在这里插入图片描述
力扣338. 比特位计数_第4张图片

进阶

1、最低设置位

class Solution {
public:
	vector<int> countBits(int n) {
		vector<int> ans(n + 1, 0);
		for (int i = 1; i <= n; i++) {
			ans[i] = ans[i&(i - 1)] + 1;
		}
		return ans;
	}
};

所有代码均以通过力扣测试
(经过多次测试最短时间为):
在这里插入图片描述

力扣338. 比特位计数_第5张图片
2、最高有效位

class Solution {
public:
	vector<int> countBits(int n) {
		vector<int> ans(n + 1, 0);
		int front = 0;
		for (int i = 1; i <= n; i++) {
			if ((i&(i - 1)) == 0) {
				front = i;//找到基准数
			}
			ans[i] = ans[i - front] + 1;
		}
		return ans;
	}
};

所有代码均以通过力扣测试
(经过多次测试最短时间为):
在这里插入图片描述
力扣338. 比特位计数_第6张图片
3、最低有效位

class Solution {
public:
	vector<int> countBits(int n) {
		vector<int> ans(n + 1, 0);
		for (int i = 1; i <= n; i++) {
			ans[i] = ans[i >> 1] + (i & 1);//位运算优先级低,一定加好括号

		}
		return ans;
	}
};

所有代码均以通过力扣测试
(经过多次测试最短时间为):
在这里插入图片描述

力扣338. 比特位计数_第7张图片

你可能感兴趣的:(力扣题解,动态规划,算法,位运算,BrianKernighan,观察规律)