LeetCode 力扣周赛 258

166 阅读1分钟

周末去参见婚礼了,吃了两天大席哈哈哈。

周赛传送门

2000. 反转单词前缀

思路std::string::findstd::reverse

时间复杂度O(n)O(n)

首先调用 word.find(ch),得到 chword 中位置 pos:

  • 如果 pos == std::string::npos,说明未找到,直接返回 word
  • 反之,则使用 std::reverse 翻转 [0,pos] 区间内的字符。
class Solution {
public:
    string reversePrefix(string word, char ch) {
        auto pos = word.find(ch);
        if (pos != std::string::npos) {
            std::reverse(word.begin(), word.begin() + pos + 1);
        }
        return word;
    }
};

2001. 可互换矩形的组数

思路:最大公约数,哈希

时间复杂度O(nlgmax)O(n*\lg{max})maxmax 为宽高的最大值。O(lgmax)O(\lg{max}) 为求解最大公约数的时间复杂度。

设有两组正整数 (Wi,Hi)(W_i,H_i)(Wj,Hj)(W_j,H_j),其最大公约数分别为 DiD_iDjD_j

如果正整数满足 WiHi=WjHj\frac{W_i}{H_i} = \frac{W_j}{H_j},则必有:

  • WiDi=WjDj\frac{W_i}{D_i} = \frac{W_j}{D_j}
  • HiDi=HjDj\frac{H_i}{D_i} = \frac{H_j}{D_j}

因此,我们可将 nn(Wi,Hi)(W_i,H_i) 都化简为 (WiDi,HiDi)(\frac{W_i}{D_i},\frac{H_i}{D_i}),记为 (Wi,Hi)(W_i',H_i')

借助哈希表统计每种 (Wi,Hi)(W_i',H_i') 的个数 cntcnt,然后累加组合数 Ccnt2C_{cnt}^2 即可得到答案。

class Solution {
public:
    long long interchangeableRectangles(vector<vector<int>>& rects) {
        std::unordered_map<uint64_t, int> mark;
        
        for (const auto &p : rects) {
            int g = __gcd(p[0], p[1]);
            uint64_t w = p[0]/g;
            uint64_t h = p[1]/g;
            mark[w<<32|h]++;
        }

        int64_t sum = 0;
        for (const auto &p : mark) {
            int64_t cnt = p.second;
            sum += (cnt-1L)*cnt/2;
        }
        return sum;
    }
};

2002. 两个回文子序列长度的最大乘积

思路:暴力枚举

时间复杂度O(3nn)O(3^n*n)

每个字符只会有三种状态:

  • 在第一个序列中
  • 在第二个序列中
  • 都不在

考虑本题的数据范围较小,n[2.12]n\in[2.12],可以暴力枚举所有状态,共 3n3^n 种。对于每种状态检查下两个序列是否回文,记录最优解即可。

class Solution {
public:
    bool isValid(const std::string &s) {
        for (int i = 0, j = s.size()-1; i < j; i++, j--) {
            if (s[i] != s[j]) return false;
        }
        return true;
    }
    int dfs(const std::string &s, int pos, std::string &a, std::string &b) {
        if (pos == s.size()) {
            if (isValid(a) && isValid(b)) {
                return a.size() * b.size();
            }
            return 0;
        }
        int opt = 0;
        
        a += s[pos];
        opt = max(opt, dfs(s, pos+1, a, b));
        a.pop_back();

        b += s[pos];
        opt = max(opt, dfs(s, pos+1, a, b));
        b.pop_back();

        return max(opt, dfs(s, pos+1, a, b));
    }
    int maxProduct(string s) {
        std::string a, b;
        return dfs(s, 0, a, b);
    }
};

2003. 每棵子树内缺失的最小基因值

思路:自下而上合并子树

时间复杂度O(n)O(n)

如果所有节点的值都不为 1,则答案显而易见——所有子树最小缺失值均为 1。换言之,如果一棵子树中不含 1,那么该子树的答案必为 1。

不妨设值为 1 的节点为xx,而且题目约束了这种节点最多只有一个。

假设节点 xx 存在,我们只需求以「从 xxrootroot 这条路径上的节点」为根的子树的最小缺失值。其他子树的最小缺失值均为 1。

我们从 xxrootroot 依次遍历路径上的点 nodeinode_i,并对每个 nodeinode_i 做如下操作:

  • 把以 nodeinode_i 为根的子树中所有节点的值加入到集合 existexist 中。
  • 找出 exitsexits 中不存在的最小正整数即为 nodeinode_i 的最小缺失值。

具体思路可参考注释~

class Solution {
    int miss = 1; // 最小缺失值
    bool exist[100002] = {0}; // 记录已经被添加过的值
    vector<int> edge[100000]; // 边表
    bool mark[100000] = {0}; // 防止子树被重复添加
    void addSubTree(int root, const vector<int> &nums) {
        if (mark[root]) { return; } // 该子树已经添加过了,
        mark[root] = true; // 更新标记
        exist[nums[root]] = true; // 更新集合
        while(exist[miss]) { // 更新最小缺失值
            miss++;
        }
        for (auto e : edge[root]) { // 添加子树
            addSubTree(e, nums);
        }
    }
  public:
    vector<int> smallestMissingValueSubtree(vector<int>& parents, vector<int>& nums) {
      int n = parents.size();
      // 构造边表
      for (int i = 1; i < n; i++) {
        edge[parents[i]].emplace_back(i);
      }
      // 全部初始化为 1 
      vector<int> anw(parents.size(), 1);
      int x = -1; 
      // 寻找节点 x
      for (int i = 0; i < nums.size() && x == -1; i++) {
        if (nums[i] == 1) {
          x = i;
          break;
        }
      }
      // 从 x 到 root 依次遍历路径上的节点
      while(x != -1) {
        // 将子树中的值添加到集合 exist 中
        addSubTree(x, nums);
        // 更新最小缺失值。addSubTree 中会更新 miss
        anw[x] = miss;
        x = parents[x];
      }
      return anw;
    }
};