Bootstrap

2022-7 刷题记录

20-01. 找到需要补充粉笔的学生编号

class Solution {
public:
    int chalkReplacer(vector<int> &chalk, int k) {
        int n = chalk.size();
        if (chalk[0] > k) return 0;
        for (int i = 1; i < n; ++i) {
            chalk[i] += chalk[i - 1];
            if (chalk[i] > k) return i;
        }
        k %= chalk.back();
        return upper_bound(chalk.begin(), chalk.end(), k) - chalk.begin();
    }
};

20-02. 最小平均差

class Solution {
public:
    int minimumAverageDifference(const vector<int> &nums) {
        int n = nums.size();
        vector<long long> sum_left(n), sum_right(n, 0);
        vector<long long> ave_left(n), ave_right(n, 0);
        for (int i = 0; i < n; ++i) {
            sum_left[i] = (i == 0) ? nums[i] : nums[i] + sum_left[i - 1];
            ave_left[i] = sum_left[i] / (i + 1);
        }
        for (int i = n - 2; i >= 0; --i) {
            sum_right[i] = nums[i + 1] + sum_right[i + 1];
            ave_right[i] = sum_right[i] / (n - i - 1);
        }
        int ans = -1, diff = INT_MAX;
        for (int i = 0; i < n; ++i) {
            if (abs(ave_left[i] - ave_right[i]) < diff) {
                diff = abs(ave_left[i] - ave_right[i]);
                ans = i;
            }
        }
        return ans;
    }
};

20-03. 满足三条件之一需改变的最少字符数

class Solution {
public:
    int minCharacters(const string &s1, const string &s2) {
        int n1 = s1.length(), n2 = s2.length(), ans = INT_MAX;
        int c1[26], c2[26];
        memset(c1, 0, sizeof c1);
        memset(c2, 0, sizeof c2);
        for (char c:s1) c1[c - 'a']++;
        for (char c:s2) c2[c - 'a']++;
        for (int i = 0; i < 26 && ans != 0; ++i) {
            ans = min(ans, n1 + n2 - c1[i] - c2[i]);
            if (i == 0) continue;
            int r1 = accumulate(c1 + i, c1 + 26, 0) + accumulate(c2, c2 + i, 0);
            int r2 = accumulate(c2 + i, c2 + 26, 0) + accumulate(c1, c1 + i, 0);
            ans = min({ans, r1, r2});
        }
        return ans;
    }
};

20-04. 蜡烛之间的盘子

class Solution {
public:
    vector<int> platesBetweenCandles(string s, vector<vector<int>> &queries) {
        int n = s.length();
        vector<int> preSum(n), left(n), right(n);
        for (int i = 0, sum = 0; i < n; i++) {
            if (s[i] == '*') sum++;
            preSum[i] = sum;
        }
        for (int i = 0, l = -1; i < n; i++) {
            if (s[i] == '|') l = i;
            left[i] = l;
        }
        for (int i = n - 1, r = -1; i >= 0; i--) {
            if (s[i] == '|') r = i;
            right[i] = r;
        }
        vector<int> ans;
        for (auto &query : queries) {
            int x = right[query[0]], y = left[query[1]];
            ans.push_back(x == -1 || y == -1 || x >= y ? 0 : preSum[y] - preSum[x]);
        }
        return ans;
    }
};

21-01. 快照数组

class SnapshotArray {
private:
    vector<vector<pair<int, int>>> store;
    int time;

public:
    SnapshotArray(int length) : time(0) {
        store.assign(length, {{0, 0}});
    }

    void set(int index, int val) {
        int s = store[index].back().first;
        if (s == time) {
            store[index].back().second = val;
        } else {
            store[index].emplace_back(time, val);
        }
    }

    int snap() { return time++; }

    int get(int index, int snap_id) {
        auto &elem = store[index];
        int lo = 0, hi = elem.size();
        while (lo < hi) {
            int mi = lo + ((hi - lo) >> 1);
            elem[mi].first <= snap_id ? lo = mi + 1 : hi = mi;
        }
        return elem[--lo].second;
    }
};

21-02. 满足条件的子序列数目

class Solution {
public:
    static constexpr int mod = 1e9 + 7;
    static constexpr int MAX_N = 1e5 + 5;

    int f[MAX_N];

    void pretreatment() {
        f[0] = 1;
        for (int i = 1; i < MAX_N; ++i) {
            f[i] = (long long) f[i - 1] * 2 % mod;
        }
    }

    int numSubseq(vector<int> &nums, int target) {
        pretreatment();

        sort(nums.begin(), nums.end());

        int ans = 0;
        for (int i = 0; i < nums.size() && nums[i] * 2 <= target; ++i) {
            int maxValue = target - nums[i];
            int pos = upper_bound(nums.begin(), nums.end(), maxValue) - nums.begin() - 1;
            ans = (ans + f[pos - i]) % mod;
        }

        return ans;
    }
};

20-03. 有界数组中指定下标处的最大值

class Solution {
private:
    using ull = unsigned long long;

    ull check(ull h, ull l1, ull l2) {
        auto get = [](ull h, ull l) -> ull {
            l = min(h, l);
            return ((h - 1) + (h - l)) * l / 2;
        };
        return get(h, l1) + get(h, l2) + h;
    }

public:
    int maxValue(int n, int index, int s) {
        unsigned int lo = 0, hi = s + 1, l1 = index, l2 = n - index - 1;
        while (lo < hi) {
            unsigned int mi = lo + ((hi - lo) >> 1);
            check(mi, l1, l2) <= s - n ? lo = mi + 1 : hi = mi;
        }
        return lo;
    }
};

21-01. 两个有序数组的第 K 小乘积

class Solution {
private:
    using ll = long long;

    ll get(ll val, const vector<int> &nums1, const vector<int> &nums2) {
        ll ans = 0;
        for (ll x : nums1) {
            int lo = 0, hi = nums2.size();
            if (x >= 0) {
                while (lo < hi) {
                    int mi = (lo + hi) >> 1;
                    x * nums2[mi] <= val ? lo = mi + 1 : hi = mi;
                }
                ans += lo;
            } else {
                while (lo < hi) {
                    int mi = (lo + hi) >> 1;
                    x * nums2[mi] > val ? lo = mi + 1 : hi = mi;
                }
                ans += nums2.size() - lo;
            }
        }
        return ans;
    }

public:
    ll kthSmallestProduct(const vector<int> &nums1, const vector<int> &nums2, ll k) {
        ll lo = -1e10, hi = 1e10;
        while (lo < hi) {
            ll mi = (lo + hi) >> 1;
            get(mi, nums1, nums2) < k ? lo = mi + 1 : hi = mi;
        }
        return lo;
    }
};

21-02. 设计一个文本编辑器

struct Node {
    char val;
    Node *prev, *next;
    Node(char val = 0) : val(val), prev(nullptr), next(nullptr) {}
    Node(char val, Node *prev, Node *next) : val(val), prev(prev), next(next) {}
};

class TextEditor {
private:
    Node *dummyHead, *dummyTail, *curNode;

    inline void insertBefore(char val) {
        auto node = new Node(val, curNode->prev, curNode);
        curNode->prev->next = node;
        curNode->prev = node;
    }

    inline bool deleteBefore() {
        if (curNode->prev == dummyHead) return false;
        curNode->prev = curNode->prev->prev;
        curNode->prev->next = curNode;
        return true;
    }

    string readBefore(int n = 10) {
        auto node = curNode;
        while (n-- && node->prev != dummyHead)
            node = node->prev;
        string s;
        while (node != curNode) {
            s.push_back(node->val);
            node = node->next;
        }
        return s;
    }

public:
    TextEditor() {
        dummyHead = new Node();
        dummyTail = new Node();
        dummyHead->next = dummyTail;
        dummyTail->prev = dummyHead;
        curNode = dummyTail;
    }

    void addText(string text) { for (char ch:text) insertBefore(ch); }

    int deleteText(int k) {
        for (int i = 0; i < k; i++) {
            if (!deleteBefore()) return i;
        }
        return k;
    }

    string cursorLeft(int k) {
        while (k-- && curNode->prev != dummyHead)
            curNode = curNode->prev;
        return move(readBefore());
    }

    string cursorRight(int k) {
        while (k-- && curNode->next != nullptr) curNode = curNode->next;
        return move(readBefore());
    }
};

21-03. 翻转等价二叉树

class Solution {
public:
    bool flipEquiv(TreeNode *root1, TreeNode *root2) {
        if (!root1 && !root2) return true;
        if (root1 && !root2) return false;
        if (!root1 && root2) return false;
        if (root1->val != root2->val) return false;
        return (flipEquiv(root1->left, root2->left) && flipEquiv(root1->right, root2->right)) ||
               (flipEquiv(root1->left, root2->right) && flipEquiv(root1->right, root2->left));
    }
};

21-04. 找到所有的农场组

class Solution {
private:
    int n, m;
    vector<vector<int>> result;

    void dfs(vector<vector<int>> &land, int x, int y) {
        land[x][y] = 0;
        result.back()[2] = max(result.back()[2], x);
        result.back()[3] = max(result.back()[3], y);
        if (x + 1 < n && land[x + 1][y] == 1) dfs(land, x + 1, y);
        if (y + 1 < m && land[x][y + 1] == 1) dfs(land, x, y + 1);
    }

public:
    vector<vector<int>> findFarmland(vector<vector<int>> &land) {
        n = land.size();
        m = land[0].size();
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                if (land[i][j] == 0) continue;
                result.push_back({i, j, i, j});
                dfs(land, i, j);
            }
        }
        return result;
    }
};

21-05. 寻找重复的子树

class Solution {
public:
    string dfs(TreeNode *root, vector<TreeNode *> &res, unordered_map<string, int> &mp) {
        if (!root) return "";
        string str = to_string(root->val) + "," + dfs(root->left, res, mp) + "," + dfs(root->right, res, mp);
        if (mp[str]++ == 1) res.push_back(root);
        return str;
    }

    vector<TreeNode *> findDuplicateSubtrees(TreeNode *root) {
        vector<TreeNode *> res;
        unordered_map<string, int> mp;
        dfs(root, res, mp);
        return res;
    }
};

21-06. 二叉搜索树的范围和

class Solution {
public:
    int rangeSumBST(TreeNode *root, int low, int high) {
        stack<TreeNode *> st;
        int ans = 0;
        TreeNode *cur = root;
        while (cur || !st.empty()) {
            if (cur) {
                st.push(cur);
                cur = cur->left;
            } else {
                cur = st.top();
                st.pop();
                if (cur->val > high) return ans;
                if (cur->val >= low) ans += cur->val;
                cur = cur->right;
            }
        }
        return ans;
    }
};

21-07. 所有大于等于节点的值之和

class Solution {
public:
    TreeNode *convertBST(TreeNode *root) {
        stack<TreeNode *> st;
        int ans = 0;
        TreeNode *cur = root;
        while (cur || !st.empty()) {
            if (cur) {
                st.push(cur);
                cur = cur->right;
            } else {
                cur = st.top();
                st.pop();
                cur->val += ans;
                ans = cur->val;
                cur = cur->left;
            }
        }
        return root;
    }
};

21-08. 把二叉搜索树转换为累加树

class Solution {
public:
    TreeNode *convertBST(TreeNode *root) {
        stack<TreeNode *> st;
        int ans = 0;
        TreeNode *cur = root;
        while (cur || !st.empty()) {
            if (cur) {
                st.push(cur);
                cur = cur->right;
            } else {
                cur = st.top();
                st.pop();
                cur->val += ans;
                ans = cur->val;
                cur = cur->left;
            }
        }
        return root;
    }
};

21-09. 点菜展示表

class Solution {
    using foodMap = unordered_map<string, int>; // food - count
public:
    vector<vector<string>> displayTable(vector<vector<string>> &orders) {
        map<int, foodMap> tableMap;  // table - foodMap
        set<string> foodSet;
        for (auto &order:orders) {
            foodSet.insert(order[2]);
            tableMap[stoi(order[1])][order[2]]++;
        }
        vector<vector<string>> result;
        result.reserve(tableMap.size());
        vector<string> line;
        line.reserve(foodSet.size());
        line.emplace_back("Table");
        for_each(foodSet.begin(), foodSet.end(), [&](const string &s) {
            line.emplace_back(s);
        });
        result.emplace_back(line);
        for_each(tableMap.begin(), tableMap.end(), [&](map<int, foodMap>::value_type &f) {
            line.clear();
            line.emplace_back(to_string(f.first));
            for_each(foodSet.begin(), foodSet.end(), [&](const string &s) {
                line.emplace_back(to_string(f.second[s]));
            });
            result.emplace_back(line);
        });
        return result;
    }
};

23-01 字符流

struct Node {
    bool isEnd;
    Node *children[26];
    Node() : isEnd(false) { memset(children, 0, sizeof children); };
};

class StreamChecker {
private:
    Node *root;
    string s;
public:
    StreamChecker(vector<string> &words) {
        root = new Node();
        for (auto &w:words) {
            auto node = root;
            for (int i = w.size() - 1; i >= 0; --i) {
                if (!node->children[w[i] - 'a']) node->children[w[i] - 'a'] = new Node();
                node = node->children[w[i] - 'a'];
            }
            node->isEnd = true;
        }
    }

    bool query(char letter) {
        s.push_back(letter);
        auto node = root;
        for (int i = s.size() - 1; i >= 0; --i) {
            if (node->isEnd) return true;
            if (!node->children[s[i] - 'a']) return false;
            node = node->children[s[i] - 'a'];
        }
        return node->isEnd;
    }
};

23-02 使网格图至少有一条有效路径的最小代价

class Solution {
private:
    int DIR[5][2] = {{0,  0}, {0,  1}, {0,  -1}, {1,  0}, {-1, 0}};
    
public:
    int minCost(vector<vector<int>> &grid) {
        int n = grid.size(), m = grid[0].size();
        vector<vector<int>> cost(n, vector<int>(m, INT_MAX));
        deque<tuple<int, int, int>> deq;
        deq.emplace_back(0, 0, 0);
        while (!deq.empty()) {
            auto[x, y, c] = deq.front();
            deq.pop_front();
            if (c >= cost[x][y]) continue;
            cost[x][y] = c;
            for (int i = 1; i <= 4; ++i) {
                int nx = x + DIR[i][0], ny = y + DIR[i][1];
                if (nx < 0 || ny < 0 || nx == n || ny == m) continue;
                if (grid[x][y] == i) {
                    if (cost[nx][ny] > c) deq.emplace_front(nx, ny, c);
                } else {
                    if (cost[nx][ny] > c + 1) deq.emplace_back(nx, ny, c + 1);
                }
            }
        }
        return cost[n - 1][m - 1];
    }
};
;