This contest was moderately difficult. Because of an issue with the judging program, many people were trapped by the third problem. The test case was corrected after the contest. This is already not the first LeetCode incident.
5083. Occurrences After Bigram
Idea: A warm-up problem. Solve it directly. Use a state machine to record the current state.
Time complexity: O(text.size()), Space complexity: O(1). In my implementation, I store tokens in a vector for convenience, but it is actually unnecessary.
classSolution { set<string> ret; voidbacktracking(map<char, int>& count, int size, int step, string& current){ if (step == size) { ret.insert(current); return; } for (auto& p : count) { char c = p.first; if (count[c] > 0) { --count[c]; current.push_back(c); backtracking(count, size, step + 1, current); current.pop_back(); ++count[c]; } } } public: intnumTilePossibilities(string tiles){ map<char, int> count; for (char tile : tiles) { ++count[tile]; } int s = tiles.size(); for (int len = 1; len <= s; ++len) { string current; backtracking(count, len, 0, current); } // for (auto& s : ret) { // cout << s << " "; // } return ret.size(); } };
5084. Insufficient Nodes in Root to Leaf Paths
A typical recursion problem. Just delete nodes according to the statement. If you are familiar with tree recursion, it is quick to write. One thing to note: the definition of a leaf node is that both left and right subtrees are null, not just the left subtree or the right subtree.
Time complexity: O(N), each node in the tree calls the recursive function once. Space complexity: O(N), the depth of the tree.
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ classSolution { int limit = 0; // return: 是否删除,子树从根到叶子最大的sum // current: 从根到父节点的sum pair<TreeNode*, int> recurse(TreeNode* root, int current){ if (root == nullptr) { return {nullptr, 0}; } auto l = recurse(root->left, current + root->val); auto r = recurse(root->right, current + root->val); TreeNode* ret_ptr = nullptr; int ret_int; if (root->left != nullptr && root->right != nullptr) ret_int = max(l.second, r.second); elseif (root->left != nullptr) ret_int = l.second; elseif (root->right) ret_int = r.second; else// 叶子结点 ret_int = 0; root->left = l.first; root->right = r.first; // cout << root->val << " : " << ret_int << endl; if (ret_int + root->val + current >= limit) { return {root, ret_int + root->val}; } else { return {nullptr, ret_int + root->val}; } } public: TreeNode* sufficientSubset(TreeNode* root, int limit){ this->limit = limit; auto ret = recurse(root, 0); return ret.first; } };
5086. Smallest Subsequence of Distinct Characters
I did not solve this problem during the contest. I tried a greedy solution, adding one character each time. But this greedy idea is actually wrong and cannot handle input like "ddeeeccdce". When processing the final d, "ecd" cannot be greater than "dec".
// 错误的贪心思路 // 时间复杂度: O(N^2) // 空间复杂度: O(N) classSolution { public: string smallestSubsequence(string text){ string current; for (int i = 0; i < text.size(); ++i) { char c = text.at(i); auto index = current.find(c); if (index == string::npos) { current.push_back(c); } else { string new_current = current.substr(0, index) + current.substr(index + 1); new_current.push_back(c); if (new_current < current) { current = std::move(new_current); } } } return current; } };
Correct idea: This is exactly the same problem as LeetCode 316. There are many high-quality answers in the discuss section for that problem.
For the input string, we try to maintain a monotonically increasing result string. If the input character is smaller than the last character of the result string, and that last character will appear again later, then we remove that character from the result string. This is also a greedy idea. Each operation makes the string smaller.