持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第28天,点击查看活动详情
338. 比特位计数
思路
(动态规划) O(n)
状态表示: f[i]表示i 的二进制表示中1的个数。
状态计算:
考虑i的奇偶性,有两种不同选择:
i是偶数,则f[i] = f[i/2],因为i/2 * 2本质上是i/2的二进制左移一位,低位补零,所以1的数量不变。i是奇数,则f[i] = f[i - 1] + 1,因为如果i为奇数,那么i - 1必定为偶数,而偶数的二进制最低位一定是0,那么该偶数+1后最低位变为1且不会进位,所以奇数比它上一个偶数二进制表示上多一个1。
初始化: f[0] = 0。
时间复杂度分析: O(n)。
c++代码
class Solution {
public:
vector<int> countBits(int n) {
vector<int> f(n + 1);
f[0] = 0; //初始化
for(int i = 1; i <= n; i++){
if(i & 1) f[i] = f[i - 1] + 1;
else f[i] = f[i >> 1];
}
return f;
}
};
347. 前 K 个高频元素
思路
(计数排序) O(n)
我们可以先统计每个数字出现了多少次,在统计一下出现次数为t次的元素各有多少个,然后利用计数排序的思想判断一下出现次数前K多的数字最少出现多少次,求出这个下界i,最后再遍历一次哈希表,将所有出现次数大于等于这个下界的元素加入答案。
具体过程:
- 1、先统计每个元素出现次数。
- 2、用
s数组,s[i]表示出现了i次的元素有s[i]个。 - 3、根据
k在s数组中找到一个分界线i,使得前k个高频元素的出现次数都>i次。
c++代码
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
int n = nums.size();
unordered_map<int, int> cnt; // 统计每个元素出现的次数
for(int x : nums) cnt[x]++;
vector<int> s(n + 1); //统计每个次数出现的元素有多少个
for(auto p : cnt) s[p.second]++;
int i = n, t = 0;
while(t < k) t += s[i--];
vector<int> res;
for(auto p : cnt){
if(p.second > i)
res.push_back(p.first);
}
return res;
}
};
394. 字符串解码
思路
(递归) O(n)
给定一个经过编码的字符串,返回它解码后的字符串。
样例:
如样例所示,
s = "3[a]2[bc]",我们根据编码规则解码后输出aaabcbc,下面来讲解递归的做法。
我们首先来解析一下这个编码规则,方括号[]内包含要重复的字符串,方括号[]外的数字代表重复的次数,而且括号是可以嵌套的,比如样例2,s = "3[a2[c]]"。要想解码外层括号的字符串,就必须要先解码内层括号的字符串,这样就给了我们一种启发,我们可以先递归到内层,由内层到外层,层层解码。****
递归函数设计:
string dfs(string &s, int &u)
s是当前要遍历的字符串,u是当前遍历的字符串的位置下标。
具体过程如下:
从左到右遍历整个字符串:
- 1、如果当前遇到的字符是字母,我们将其加入到答案字符串
res中。 - 2、如果当前遇到了
k[encoded_string]规则,则解析出数字k和字符串encoded_string,然后递归解码字符串encoded_string。 - 3、每次递归结束后,我们将解码得到的结果字符串
str重复k次,然后将其添加到答案中。
我们以字符串3[a2[c]]为例,图示过程如下:
时间复杂度分析: 假设共有 n 个规则,则最坏情况下所有规则会嵌套 n 层:k[k[...k[encoded_string]]]。则最终解码后的字符串长度是 encoded_string.length * k^n。所以时间复杂度是 O(k^n)。
c++代码
class Solution {
public:
string decodeString(string s) {
int u = 0; //当前遍历的字符串的位置下标
return dfs(s, u);
}
string dfs(string &s, int &u){
string res;
while(u < s.size() && s[u] != ']'){
if(s[u] >= 'a' && s[u] <= 'z' || s[u] >= 'A' && s[u] <= 'Z') res += s[u++];
else if(s[u] >= '0' && s[u] <= '9')
{
int k = u, num = 0;
while(s[k] >= '0' && s[k] <= '9') num = num * 10 + s[k++] -'0'; //将字符转换成数字
u = k + 1; // 跳过左括号,递归到内层
string str = dfs(s, u); // 返回内层解码结果
u++; // 跳过右括号
while(num--) res += str;
}
}
return res;
}
};