LeetCode 221场周赛题解

£神魔★判官ぃ 2023-01-01 13:53 234阅读 0赞

【GiantPandaCV导语】这是LeetCode的第221场周赛的题解,本期考察的知识点有模拟,贪心,优先队列,01Trie树等。

比赛链接

  • https://leetcode-cn.com/contest/weekly-contest-221/

题目一:判断字符串的两半是否相似

题面

解题思路:直接模拟即可。
时间复杂度:O(s.length)
解题代码如下:

  1. class Solution {
  2. public:
  3. bool yuan(char c){
  4. if(c=='a'||c=='e'||c=='i'||c=='o'||c=='u'||c=='A'||c=='E'||c=='I'||c=='O'||c=='U') return 1;
  5. else return 0;
  6. }
  7. bool check(string t1, string t2){
  8. int cnt1=0, cnt2=0;
  9. for(int i=0; i<t1.size(); i++){
  10. if(yuan(t1[i])) cnt1++;
  11. }
  12. for(int i=0; i<t2.size(); i++){
  13. if(yuan(t2[i])) cnt2++;
  14. }
  15. return cnt1==cnt2;
  16. }
  17. bool halvesAreAlike(string s) {
  18. string t1 = "", t2 = "";
  19. int len = s.size();
  20. for(int i=0; i<len; i++){
  21. if(i<len/2) t1+=s[i];
  22. else t2+=s[i];
  23. }
  24. bool ans=check(t1, t2);
  25. return ans;
  26. }
  27. };

题目二:吃苹果的最大数目

题面

解题思路:这道题的核心思路是要每次优先吃最早过期的苹果。然后,我们用优先队列保存到当前时间为止拥有的苹果(苹果有数量和过期时间两个属性),每次从优先队列里面取出最早过期的苹果。

如果取到的苹果已经过期,即过期的时间小于等于当前的天数,那么将其从优先队列中移除并继续取。直到取到第一个可以吃的苹果,并吃掉它,将它的数量减1,如果苹果的数量不为0,则再次将其放入优先队列。

直到队列为空,程序结束。

时间复杂度:O(nlogn)

解题代码

  1. struct node{
  2. // cnt代表个数,idx代表过期时间
  3. int cnt, idx;
  4. node(){
  5. }
  6. node(int cnt_, int idx_):cnt(cnt_),idx(idx_){
  7. }
  8. bool operator<(const node& rhs) const{
  9. return idx > rhs.idx;
  10. }
  11. };
  12. class Solution {
  13. public:
  14. int eatenApples(vector<int>& apples, vector<int>& days) {
  15. int n = apples.size();
  16. int ans = 0;
  17. priority_queue <node> pq;
  18. int i = 0;
  19. int nn=n; //定义可变右边界
  20. while(i<nn){
  21. while(!pq.empty() && pq.top().idx<=i){
  22. //移除烂掉的苹果
  23. pq.pop();
  24. }
  25. if(i<n && apples[i]>0){
  26. //添加有效苹果到优先队列里
  27. pq.push(node(apples[i],i+days[i]));
  28. nn=max(nn,i+days[i]+1); //比较,获得较大的右侧边界
  29. }
  30. if(!pq.empty()){
  31. node now=pq.top(); //拿出靠前的一堆苹果,并吃掉一个
  32. pq.pop();
  33. now.cnt-=1;
  34. ans++;
  35. if(now.cnt>0){
  36. //如果这堆没吃完,再放回去
  37. pq.push(now);
  38. }
  39. }
  40. i++;
  41. }
  42. return ans;
  43. }
  44. };

题目三:球会落在何处

题面

题面

解题思路:仔细观察可以发现

  • 如果在当前格子中 为’’,那么它右边格子也应该为’’,小球才能移动到下一行。
  • 如果在当前格子中 为’/’,那么它右边格子也应该为’/’,小球才能移动到下一行。
  • 其它情况均无法移动到最后一行。
    时间复杂度:O(n*m)

解题代码如下:

  1. class Solution {
  2. public:
  3. vector<int> ans;
  4. vector<int> findBall(vector<vector<int>>& grid)
  5. {
  6. int m = grid.size();
  7. int n = grid[0].size();
  8. ans.resize(n);
  9. // 初始化每一个小球的位置
  10. for (int i = 0; i < n; i++) {
  11. ans[i] = i;
  12. }
  13. for (int i = 0; i < m; ++i) {
  14. // 计算小球将出现在下一行的哪个位置
  15. for (int j = 0; j < n; ++j) {
  16. // 计算每一列的每一个小球
  17. if (ans[j] == -1) {
  18. // 如果当前列的小球已经停止向下运动, 跳过
  19. continue;
  20. }
  21. int now = ans[j]; // 得到小球在这一列的位置
  22. // 根据辅助图, 如果在当前格子中 为'\',那么它右边格子也应该为'\',小球才能移动到下一行
  23. if (grid[i][now] == 1 && now < n - 1 && grid[i][now + 1] == 1) {
  24. ans[j] += 1;
  25. } else if (grid[i][now] == -1 && now >= 1 && grid[i][now - 1] == -1) {
  26. // 如果在当前格子中 为'/',那么它右边格子也应该为'/',小球才能移动到下一行
  27. ans[j] -= 1;
  28. } else {
  29. // 其他情况都无法向下移动
  30. ans[j] = -1;
  31. }
  32. }
  33. }
  34. return ans;
  35. }
  36. };

题目四:与数组中元素的最大异或值

题面

解题思路:我们可以使用01字典树来存储数组中的所有元素。另外,由于每个查询包含一个上界 m i m_i mi,因此我们可以在字典树的每一个节点再维护一个以当前节点为根节点的子树的最小元素。它的作用是,如果当前节点的子树的最小元素大小都大于 m i m_i mi,我们就没有必要继续对这个子树进行搜索了。

然后考虑每一次查询,我们从高位到低位进行依次处理,实际上有以下两种情况:

  • 如果 x i x_i xi的当前二进制位为1,那么我们应该在Trie树上优先走位为0的分支;否则,我们需要尝试走Trie树上位为1的分支,如果分支不存在或者分支的最小元素已经超过了 m i m_i mi,则本地查询无解。
  • 如果 x i x_i xi的当前二进制位为0,那么我们应该优先走当前位为1的分支,但要求这一分支的最小元素不超过 m i m_i mi;否则,我们继续走当前位为0的分支。

如果我们能顺利走到了最低位,那么我们就获得了这一查询的最优解。

时间复杂度:O(n+q*log(maxx))

空间复杂度:O(nlog(maxx)+q)

解题代码如下:

  1. struct TrieNode {
  2. int minn = 1e9;
  3. TrieNode* children[2]{
  4. };
  5. };
  6. class Solution {
  7. public:
  8. vector<int> maximizeXor(vector<int>& nums, vector<vector<int>>& queries) {
  9. TrieNode* root = new TrieNode();
  10. for (int j = 0; j < nums.size(); j++) {
  11. int num = nums[j];
  12. TrieNode* p = root;
  13. for (int i = 30; i >= 0; --i) {
  14. int nxt = (num & (1 << i)) ? 1 : 0;
  15. if (!p->children[nxt]) p->children[nxt] = new TrieNode();
  16. p = p->children[nxt];
  17. p->minn = min(p->minn, num);
  18. }
  19. }
  20. vector<int> ans;
  21. for (int j = 0; j < queries.size(); j++) {
  22. int x = queries[j][0], limit = queries[j][1];
  23. int sum = 0;
  24. TrieNode* p = root;
  25. for (int i = 30; i >= 0; --i) {
  26. if (x & (1 << i)) {
  27. if (p->children[0]) {
  28. p = p->children[0];
  29. sum ^= (1 << i);
  30. } else if (!p->children[1] || (p->children[1]->minn > limit)) {
  31. ans.push_back(-1);
  32. break;
  33. } else {
  34. p = p->children[1];
  35. }
  36. } else {
  37. if (p->children[1] && (p->children[1]->minn <= limit)) {
  38. p = p->children[1];
  39. sum ^= (1 << i);
  40. } else if (!p->children[0]) {
  41. ans.push_back(-1);
  42. break;
  43. } else {
  44. p = p->children[0];
  45. }
  46. }
  47. if (i == 0) ans.push_back(sum);
  48. }
  49. }
  50. return ans;
  51. }
  52. };

欢迎关注GiantPandaCV, 在这里你将看到独家的深度学习分享,坚持原创,每天分享我们学习到的新鲜知识。( • ̀ω•́ )✧

有对文章相关的问题,或者想要加入交流群,欢迎添加BBuf微信:

二维码

为了方便读者获取资料以及我们公众号的作者发布一些Github工程的更新,我们成立了一个QQ群,二维码如下,感兴趣可以加入。

公众号QQ交流群

发表评论

表情:
评论列表 (有 0 条评论,234人围观)

还没有评论,来说两句吧...

相关阅读