LeetCode 热题 HOT 100 打卡计划 | 第二十七天 | 每日进步一点点

137 阅读4分钟

图片.png

持续创作,加速成长!这是我参与「掘金日新计划 · 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、根据ks数组中找到一个分界线i,使得前k个高频元素的出现次数都>i次。

c++代码

图片.png

 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)

给定一个经过编码的字符串,返回它解码后的字符串。

样例:

image-20210917214415375

图片.png 如样例所示,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;
     }
 };