2022年5月每日一题

5月1日:1305. 两棵二叉搜索树中的所有元素

题目链接

先遍历,后排序

s Solution {
public:
    vector<int> res;
    void dfs(TreeNode* root)
    {
        if (root == nullptr) return;
        dfs(root->left);
        res.push_back(root->val);
        dfs(root->right);
    }

    vector<int> getAllElements(TreeNode* root1, TreeNode* root2) {
        dfs(root1);
        dfs(root2);
        sort(res.begin(), res.end());
        return res;
    }
};

分别对BST数进行遍历,后归并

class Solution {
public:
    void dfs(TreeNode* root, vector<int> &nums)
    {
        if (root == nullptr) return;
        dfs(root->left, nums);
        nums.push_back(root->val);
        dfs(root->right, nums);
    }

    vector<int> getAllElements(TreeNode* root1, TreeNode* root2) {
        vector<int> nums1, nums2,res;
        dfs(root1, nums1);
        dfs(root2, nums2);

        int i = 0, j = 0; 
        while (i < nums1.size() && j < nums2.size())
        {
            if (nums1[i] < nums2[j])
                res.push_back(nums1[i ++ ]);
            else if (nums1[i] > nums2[j])
                res.push_back(nums2[j ++ ]);
            else 
            {
                res.push_back(nums1[i ++ ]);
                res.push_back(nums2[j ++ ]);
            }
        }

        while (i < nums1.size()) res.push_back(nums1[i ++ ]);
        while (j < nums2.size()) res.push_back(nums2[j ++ ]);

        return res;
    }
};

5月2日:591. 标签验证器

题目链接

注意这个题的思路,先检查什么,后检查什么!

class Solution {
public:
    bool isValid(string code) {
        int n = code.size();
        stack<string> tags;

        int i = 0;
        while (i < n) {
            if (code[i] == '<') {
                if (i == n - 1) return false;
                if (code[i + 1] == '/') {
                    int j = code.find('>', i); // 从code的第i个字符查找'>'
                    if (j == string::npos) return false; // 未找到
                    string tagname = code.substr(i + 2, j - (i + 2));
                    if (tags.empty() || tags.top() != tagname) return false;
                    tags.pop();
                    i = j + 1;
                    if (tags.empty() && i != n)
                        return false;
                } else if (code[i + 1] == '!') {
                    if (tags.empty()) return false;
                    string cdata = code.substr(i + 2, 7);
                    if (cdata != "[CDATA[") return false;
                    int j = code.find("]]>", i);
                    if (j == string::npos) return false;
                    i = j + 1;
                } else {
                    int j = code.find('>', i);
                    if (j == string::npos) return false;
                    string tagname = code.substr(i + 1, j - (i + 1));
                    if (tagname.size() < 1 || tagname.size() > 9) return false;
                    if (!all_of(tagname.begin(), tagname.end(),  // 检查tagname中的字母是否都是大写
                                [](unsigned char c) { return isupper(c); }))
                        return false;
                    tags.push(move(tagname)); // 掏空tagname,并将其值压入栈
                    i = j + 1;
                }
            } else {
                if (tags.empty()) return false;
                i++;
            }
        }

        return tags.empty();
    }
};

5月3日:937. 重新排列日志文件

题目链接

class Solution {
public:
    vector<string> reorderLogFiles(vector<string>& logs) {
        queue<string> st_nums;
        vector<pair<string, string>> mp;
        
        for (auto s : logs)
        {
            int first_space = s.find(' ', 0);
            string str = s.substr(first_space + 1);
            bool flag = true;
            for (auto c : str)
                if (isalpha(c))
                {
                    string tag = s.substr(0, first_space);
                    mp.push_back({str, tag});
                    flag = false;
                    break;
                }
            if (flag) st_nums.push(s);
        }
        
        sort(mp.begin(), mp.end());
        
        vector<string> res;
        for (auto s : mp)
            res.push_back(s.second + ' ' + s.first);
        while (st_nums.size())
        {
            res.push_back(st_nums.front());
            st_nums.pop();
        }
        
        return res;
    }
};

5月4日:1823. 找出游戏的获胜者

这个题目与ACwing 4400 玩游戏类似,但是这个题目的k值是不变的,那个题目会改变。那个题目用的是队列模拟来解决。

方法一:队列

class Solution {
public:
int findTheWinner(int n, int k) {
        queue<int> q;
        
        for (int i = 1; i <= n; i ++ ) q.push(i);
        
        while (n != 1)
        {
            for (int i = 0; i < k - 1; i ++ )
                {
                    q.push(q.front());
                    q.pop();
                }
            
            q.pop();
            
            n -- ;
        }
        
        return q.front();
    }
};

上面的方法当n很大的时候会TLE,比如这个题目:剑指 Offer 62. 圆圈中最后剩下的数字

动态规划

思路以及下面评论1的公式推导。

注意这个题解的返回值下标是从0开始,而本题要求是从1开始的。注意理解f[n, m] = (m + x) % n的推导。

递归写法

class Solution {
public:
    int f(int n, int m)
    {
        if (n == 1) return 0;
        int x = f(n - 1, m);
        return (m + x) % n;
    }
    int findTheWinner(int n, int k) {
       return f(n, k) + 1; 
    }
};

迭代写法,避免递归调用栈

class Solution {
public:
    int findTheWinner(int n, int k) {
        int f = 0;
        for (int i = 2; i <= n; i ++ )
            f = (f + k) % i; // 注意这里的i
        return f + 1;
    }
};

5月5日:713. 乘积小于 K 的子数组

滑动窗口思路:枚举滑动窗口的右端点

class Solution {
public:
    int numSubarrayProductLessThanK(vector<int>& nums, int k) {
        int n = nums.size(), ret = 0;
        int prod = 1, i = 0;
        for (int j = 0; j < n; j ++ )
        {
            prod *= nums[j];
            while (i <= j && prod >= k)
            {
                prod /= nums[i];
                i ++ ;
            }
            ret += j - i + 1;
        }
        return ret;
    }
};

5月6日:933. 最近的请求次数

题目链接

使用队列来维护之前ping的数据。

class RecentCounter {
private:
	queue<int> q;
	
public:
	RecentCounter() {}
	
	int ping(int t) {
		while (q.size() && q.front() + 3000 < t) q.pop();
		q.push(t);
		return q.size();
	}
};

5月7日:433. 最小基因变化

题目链接

BFS

class Solution {
public:
    int minMutation(string start, string end, vector<string>& bank) {
        unordered_set<string> cnt, visited; // cnt记录bank中的合法序列,visited记录遍历过的序列
        char keys[4] = {'A', 'C', 'G', 'T'};

        for (auto &w : bank)
            cnt.emplace(w);

        if (start == end) return 0;
        if (!cnt.count(end)) return -1;

        queue<string> qu;
        qu.emplace(start);
        visited.emplace(start);

        int step = 1;
        while (qu.size())
        {
            int sz = qu.size();
            for (int i = 0; i < sz; i ++ )
            {
                string curr = qu.front();
                qu.pop();
                for (int j = 0; j < 8; j ++ ) // 修改当前序列的每个字符
                    for (int k = 0; k < 4; k ++ )
                        if (keys[k] != curr[j]) // 要遍历另外三字符
                        {
                            string next = curr;
                            next[j] = keys[k];

                            if (!visited.count(next) && cnt.count(next)) // 如果next没有被遍历过并且next合法
                            {
                                if (next == end)
                                    return step;
                                qu.emplace(next);
                                visited.emplace(next);
                            }
                        }
            }
            step ++ ;
        }

        return -1;
    }
};

更高效的代码:学习一下邻接表

class Solution {
public:
    int minMutation(string start, string end, vector<string>& bank) {
        int m = start.size(), n = bank.size();
        vector<vector<int>> adj(n); // 邻接表,用于存储所有可以仅一步变换就到bank中的元素的序列
        int endIndex = -1;

        for (int i = 0; i < n; i ++ ) // 遍历bank中的每个元素
        {
            if (end == bank[i])
                endIndex = i;
            
            for (int j = i + 1; j < n; j ++ )
            {
                int mutations = 0;
                for (int k = 0; k < m; k ++ )
                {
                    if (bank[i][k] != bank[j][k]) mutations ++ ;
                    if (mutations > 1) break;
                }
                if (mutations == 1)
                {
                    adj[i].emplace_back(j);
                    adj[j].emplace_back(i);
                }
            }
        }

        if (endIndex == -1) return -1;

        queue<int> qu;
        vector<bool> visited(n, false);
        int step = 1;

        for(int i = 0; i < n; i ++ )
        {
            int mutations = 0;
            for (int k = 0; k < m; k ++ )
            {
                if (start[k] != bank[i][k]) mutations ++ ;
                if (mutations > 1) break;
            }

            if (mutations == 1)
            {
                qu.emplace(i);
                visited[i] = true;
            }
        }

        while (qu.size())
        {
            int sz = qu.size();
            for (int i = 0; i < sz; i ++ )
            {
                int curr = qu.front();
                qu.pop();
                
                if (curr == endIndex) return step;

                for (auto & next : adj[curr])
                {
                    if (visited[next]) continue;

                    visited[next] = true;
                    qu.emplace(next);
                }
            }
            step ++ ;
        }

        return -1;
    }
};

5月8日:442. 数组中重复的数据

题目链接

将元素交换到对应的位置

class Solution {
public:
    vector<int> findDuplicates(vector<int>& nums) {
        int n = nums.size();
        for (int i = 0; i < n; i ++ )
            while (nums[i] != nums[nums[i] - 1])
                swap(nums[i], nums[nums[i] - 1]);
        
        vector<int> ans;
        for (int i = 0; i < n; i ++ )
            if (nums[i] - 1 != i)
                ans.push_back(nums[i]);
        
        return ans;
    }
};

使用正负号作为标记

class Solution {
public:
    vector<int> findDuplicates(vector<int>& nums) {
        int n = nums.size();
        vector<int> ans;
        for (int i = 0; i < n; ++i) {
            int x = abs(nums[i]);
            if (nums[x - 1] > 0) {
                nums[x - 1] = -nums[x - 1];
            }
            else {
                ans.push_back(x);
            }
        }
        return ans;
    }
};

5月9日:942. 增减字符串匹配

题目链接

贪心

class Solution {
public:
    vector<int> diStringMatch(string s) {
        int n = s.size();
        int i = 0, j = n;
        vector<int> res;
        
        for (auto c : s)
            if (c == 'D') res.push_back(j -- );
            else res.push_back(i ++ );
        res.push_back(j);

        return res;
    }
};

5月10日:1728. 猫和老鼠 II(难)

题目链接

static const int MOUSE_TURN = 0, CAT_TURN = 1;
static const int UNKNOWN = 0, MOUSE_WIN = 1, CAT_WIN = 2;
static const int MAX_MOVES = 1000;

class Solution {
public: 
    vector<vector<int>> dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    int rows, cols;
    vector<string> grid;
    int catJump, mouseJump;
    int food;
    int degrees[64][64][2];
    int results[64][64][2][2];

    bool canMouseWin(vector<string> grid, int catJump, int mouseJump) {
        this->rows = grid.size();
        this->cols = grid[0].size();
        this->grid = grid;
        this->catJump = catJump;
        this->mouseJump = mouseJump;
        int startMouse = -1, startCat = -1;
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                char c = grid[i][j];
                if (c == 'M') {
                    startMouse = getPos(i, j);
                } else if (c == 'C') {
                    startCat = getPos(i, j);
                } else if (c == 'F') {
                    food = getPos(i, j);
                }
            }
        }
        int total = rows * cols;
        memset(degrees, 0, sizeof(degrees));
        memset(results, 0, sizeof(results));
        queue<tuple<int, int, int>> qu;
        // 计算每个状态的度
        for (int mouse = 0; mouse < total; mouse++) {
            int mouseRow = mouse / cols, mouseCol = mouse % cols;
            if (grid[mouseRow][mouseCol] == '#') {
                continue;
            }
            for (int cat = 0; cat < total; cat++) {
                int catRow = cat / cols, catCol = cat % cols;
                if (grid[catRow][catCol] == '#') {
                    continue;
                }
                degrees[mouse][cat][MOUSE_TURN]++;
                degrees[mouse][cat][CAT_TURN]++;
                for (auto & dir : dirs) {
                    for (int row = mouseRow + dir[0], col = mouseCol + dir[1], jump = 1; row >= 0 && row < rows && col >= 0 && col < cols && grid[row][col] != '#' && jump <= mouseJump; row += dir[0], col += dir[1], jump++) {
                        int nextMouse = getPos(row, col), nextCat = getPos(catRow, catCol);
                        degrees[nextMouse][nextCat][MOUSE_TURN]++;
                    }
                    for (int row = catRow + dir[0], col = catCol + dir[1], jump = 1; row >= 0 && row < rows && col >= 0 && col < cols && grid[row][col] != '#' && jump <= catJump; row += dir[0], col += dir[1], jump++) {
                        int nextMouse = getPos(mouseRow, mouseCol), nextCat = getPos(row, col);
                        degrees[nextMouse][nextCat][CAT_TURN]++;
                    }
                }
            }
        }
        // 猫和老鼠在同一个单元格,猫获胜
        for (int pos = 0; pos < total; pos++) {
            int row = pos / cols, col = pos % cols;
            if (grid[row][col] == '#') {
                continue;
            }
            results[pos][pos][MOUSE_TURN][0] = CAT_WIN;
            results[pos][pos][MOUSE_TURN][1] = 0;
            results[pos][pos][CAT_TURN][0] = CAT_WIN;
            results[pos][pos][CAT_TURN][1] = 0;
            qu.emplace(pos, pos, MOUSE_TURN);
            qu.emplace(pos, pos, CAT_TURN);
        }
        // 猫和食物在同一个单元格,猫获胜
        for (int mouse = 0; mouse < total; mouse++) {
            int mouseRow = mouse / cols, mouseCol = mouse % cols;
            if (grid[mouseRow][mouseCol] == '#' || mouse == food) {
                continue;
            }
            results[mouse][food][MOUSE_TURN][0] = CAT_WIN;
            results[mouse][food][MOUSE_TURN][1] = 0;
            results[mouse][food][CAT_TURN][0] = CAT_WIN;
            results[mouse][food][CAT_TURN][1] = 0;
            qu.emplace(mouse, food, MOUSE_TURN);
            qu.emplace(mouse, food, CAT_TURN);
        }
        // 老鼠和食物在同一个单元格且猫和食物不在同一个单元格,老鼠获胜
        for (int cat = 0; cat < total; cat++) {
            int catRow = cat / cols, catCol = cat % cols;
            if (grid[catRow][catCol] == '#' || cat == food) {
                continue;
            }
            results[food][cat][MOUSE_TURN][0] = MOUSE_WIN;
            results[food][cat][MOUSE_TURN][1] = 0;
            results[food][cat][CAT_TURN][0] = MOUSE_WIN;
            results[food][cat][CAT_TURN][1] = 0;
            qu.emplace(food, cat, MOUSE_TURN);
            qu.emplace(food, cat, CAT_TURN);
        }
        // 拓扑排序
        while (!qu.empty()) {
            auto [mouse, cat, turn] = qu.front();
            qu.pop();
            int result = results[mouse][cat][turn][0];
            int moves = results[mouse][cat][turn][1];
            vector<tuple<int, int, int>> prevStates = getPrevStates(mouse, cat, turn);
            for (auto [prevMouse, prevCat, prevTurn] : prevStates) {
                if (results[prevMouse][prevCat][prevTurn][0] == UNKNOWN) {
                    bool canWin = (result == MOUSE_WIN && prevTurn == MOUSE_TURN) || (result == CAT_WIN && prevTurn == CAT_TURN);
                    if (canWin) {
                        results[prevMouse][prevCat][prevTurn][0] = result;
                        results[prevMouse][prevCat][prevTurn][1] = moves + 1;
                        qu.emplace(prevMouse, prevCat, prevTurn);
                    } else {
                        degrees[prevMouse][prevCat][prevTurn]--;
                        if (degrees[prevMouse][prevCat][prevTurn] == 0) {
                            int loseResult = prevTurn == MOUSE_TURN ? CAT_WIN : MOUSE_WIN;
                            results[prevMouse][prevCat][prevTurn][0] = loseResult;
                            results[prevMouse][prevCat][prevTurn][1] = moves + 1;
                            qu.emplace(prevMouse, prevCat, prevTurn);
                        }
                    }
                }
            }
        }
        return results[startMouse][startCat][MOUSE_TURN][0] == MOUSE_WIN && results[startMouse][startCat][MOUSE_TURN][1] <= MAX_MOVES;
    }
    
    vector<tuple<int, int, int>> getPrevStates(int mouse, int cat, int turn) {
        vector<tuple<int, int, int>> prevStates;
        int mouseRow = mouse / cols, mouseCol = mouse % cols;
        int catRow = cat / cols, catCol = cat % cols;
        int prevTurn = turn == MOUSE_TURN ? CAT_TURN : MOUSE_TURN;
        int maxJump = prevTurn == MOUSE_TURN ? mouseJump : catJump;
        int startRow = prevTurn == MOUSE_TURN ? mouseRow : catRow;
        int startCol = prevTurn == MOUSE_TURN ? mouseCol : catCol;
        prevStates.emplace_back(mouse, cat, prevTurn);
        for (auto & dir : dirs) {
            for (int i = startRow + dir[0], j = startCol + dir[1], jump = 1; i >= 0 && i < rows && j >= 0 && j < cols && grid[i][j] != '#' && jump <= maxJump; i += dir[0], j += dir[1], jump++) {
                int prevMouseRow = prevTurn == MOUSE_TURN ? i : mouseRow;
                int prevMouseCol = prevTurn == MOUSE_TURN ? j : mouseCol;
                int prevCatRow = prevTurn == MOUSE_TURN ? catRow : i;
                int prevCatCol = prevTurn == MOUSE_TURN ? catCol : j;
                int prevMouse = getPos(prevMouseRow, prevMouseCol);
                int prevCat = getPos(prevCatRow, prevCatCol);
                prevStates.emplace_back(prevMouse, prevCat, prevTurn);
            }
        }
        return prevStates;
    }

    int getPos(int row, int col) {
        return row * cols + col;
    }
};

5月11日:449. 序列化和反序列化二叉搜索树

题目链接

class Codec {
public:

    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        string res;
        vector<int> arr;
        postOrder(root, arr);
        if (arr.size() == 0) return res;
        for (int i = 0; i < arr.size() - 1; i ++ )
            res.append(to_string(arr[i]) + ",");
        res.append(to_string(arr.back()));
        return res;
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        if (data.size() == 0) return nullptr;
        vector<string> arr = split(data, ',');
        stack<int> st;
        for (auto &str : arr)
            st.emplace(stoi(str));
        return construct(INT_MIN, INT_MAX, st);
    }

    vector<string> split(const string &str, char dec)
    {
        int pos = 0, start = 0;
        vector<string> res;
        while (pos < str.size())
        {
            while (pos < str.size() && str[pos] == dec)
                pos ++ ;
            start = pos;
            while (pos < str.size() && str[pos] != dec)
                pos ++ ;
            if (start < str.size())
                res.emplace_back(str.substr(start, pos - start));
        }
        return res;
    }

    void postOrder(TreeNode *root, vector<int> &arr)
    {
        if (root == nullptr) return;
        postOrder(root->left, arr);
        postOrder(root->right, arr);
        arr.emplace_back(root->val);
    }

    TreeNode* construct(int lower, int upper, stack<int>& st)
    {
        if (st.size() == 0 || st.top() < lower || st.top() > upper)
            return nullptr;
        int val = st.top();
        st.pop();
        TreeNode* root = new TreeNode(val);
        root->right = construct(val, upper, st);
        root->left = construct(lower, val, st);
        return root;
    }
};

5月12日:944. 删列造序

题目链接

class Solution {
public:
    int minDeletionSize(vector<string>& strs) {
        int row = strs.size();
        int col = strs[0].size();
        int ans = 0;
        for (int j = 0; j < col; ++j) {
            for (int i = 1; i < row; ++i) {
                if (strs[i - 1][j] > strs[i][j]) {
                    ans++;
                    break;
                }
            }
        }
        return ans;
    }
};

5月13日:面试题 01.05. 一次编辑

题目链接

class Solution {
public:
    bool oneEditAway(string first, string second) {
        int len1 = first.size(), len2 = second.size();
        if (abs(len1 - len2) > 1) return false;
        if (len1 < len2) swap(first, second);
        for (int i = 0, j = 0, diff = 0; i < first.size(); i ++ , j ++ )
        {
            if (first[i] != second[j])
            {
                if ( ++ diff > 1) return false;
                if (len1 != len2) j -- ; // 当diff=1的时候,j的位置不变,i跳过当前一个不同的字符
            }
        }
        return true;
    }
};

5月18日:668. 乘法表中第k小的数 (二分

题目链接

class Solution {
public:
    int findKthNumber(int m, int n, int k) {
        int left = 1, right = m * n;
        while (left < right)
        {
            int x = left + (right - left) / 2;
            int count = x / n * n;
            for (int i = x / n + 1; i <= m; i ++ )
                count += x / i;
            if (count >= k)
                right = x;
            else 
                left = x + 1;
        }
        return left;
    }
};

5月18日:462. 最少移动次数使数组元素相等 II

题目链接

class Solution {
public:
    int minMoves2(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        int n = nums.size(), res = 0, x = nums[nums.size() / 2];
        for (int i = 0; i < n; i ++ )
            res += abs(nums[i] - x);
        return res;
    }
};

5月19日:436. 寻找右区间

题目链接

class Solution {
public:
    vector<int> findRightInterval(vector<vector<int>>& intervals) {
        int n = intervals.size();
        unordered_map<int, int> startLen;
        for (int i = 0; i < n; i ++ )
            startLen[intervals[i][0]] = i;
        
        sort(intervals.begin(), intervals.end());
        
        vector<int> res(n);
        for(int i = 0; i < n; i ++ )
            {
                int x = intervals[i][1];
                int l = 0, r = n - 1;
                while (l < r)
                {
                    int mid = l + (r - l) / 2;
                    if (intervals[mid][0] >= x) r = mid;
                    else l = mid + 1;
                }
                
                if (intervals[l][0] >= x)
                    res[startLen[intervals[i][0]]] = startLen[intervals[l][0]];
                else res[startLen[intervals[i][0]]] = -1;
            }
        
        return res;
    }
};

5月20日:436. 寻找右区间

题目链接

class Solution {
public:
    vector<int> findRightInterval(vector<vector<int>>& intervals) {
        int n = intervals.size();
        unordered_map<int, int> startLen;
        for (int i = 0; i < n; i ++ )
            startLen[intervals[i][0]] = i;
        
        sort(intervals.begin(), intervals.end());
        
        vector<int> res(n);
        for(int i = 0; i < n; i ++ )
            {
                int x = intervals[i][1];
                int l = 0, r = n - 1;
                while (l < r)
                {
                    int mid = l + (r - l) / 2;
                    if (intervals[mid][0] >= x) r = mid;
                    else l = mid + 1;
                }
                
                if (intervals[l][0] >= x)
                    res[startLen[intervals[i][0]]] = startLen[intervals[l][0]];
                else res[startLen[intervals[i][0]]] = -1;
            }
        
        return res;
    }
};

5月21日:961. 在长度 2N 的数组中找出重复 N 次的元素

题目链接

class Solution {
public:
    int repeatedNTimes(vector<int>& nums) {
        unordered_set<int> st;
        for (auto c : nums)
        {
            if (!st.count(c)) 
                st.insert(c);
            else 
                return c;
        }
        return -1;
    }
};

5月22日:464. 我能赢吗 (状态压缩+DFS)

题目链接

class Solution {
public:
    unordered_map<int, bool> memo;

    bool canIWin(int maxChoosableInteger, int desiredTotal) {
        if ((1 + maxChoosableInteger) * (maxChoosableInteger) / 2 < desiredTotal)
            return false;
        return dfs(maxChoosableInteger, 0, desiredTotal, 0);
    }

    bool dfs(int maxChoosableInteger, int usedNumbers, int desiredTotal, int currentTotal)
    {
        if (!memo.count(usedNumbers))
        {
            bool res = false;
            for (int i = 0; i < maxChoosableInteger; i ++ )
            {
                if (((usedNumbers >> i) & 1) == 0)
                {
                    if (i + 1 + currentTotal >= desiredTotal)
                    {
                        res = true;
                        break;
                    }
                    if (!dfs(maxChoosableInteger, usedNumbers | (1 << i), desiredTotal, currentTotal + i + 1))
                    {
                        res = true;
                        break;
                    }
                }
            }
            memo[usedNumbers] = res;
        }
        return memo[usedNumbers];
    }
};

5月23日:675. 为高尔夫比赛砍树

题目链接

class Solution {
public:
    int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

    int bfs(vector<vector<int>>& forest, int sx, int sy, int tx, int ty) {
        if (sx == tx && sy == ty) {
            return 0;
        }

        int row = forest.size();
        int col = forest[0].size();
        int step = 0;
        queue<pair<int, int>> qu;
        vector<vector<bool>> visited(row, vector<bool>(col, false));         
        qu.emplace(sx, sy);
        visited[sx][sy] = true;
        while (!qu.empty()) {
            step++;
            int sz = qu.size();
            for (int i = 0; i < sz; ++i) {
                auto [cx, cy] = qu.front();
                qu.pop();
                for (int j = 0; j < 4; ++j) {
                    int nx = cx + dirs[j][0];
                    int ny = cy + dirs[j][1];
                    if (nx >= 0 && nx < row && ny >= 0 && ny < col) {
                        if (!visited[nx][ny] && forest[nx][ny] > 0) {
                            if (nx == tx && ny == ty) {
                                return step;
                            }
                            qu.emplace(nx, ny);
                            visited[nx][ny] = true;
                        }
                    }
                }
            }
        }
        return -1;
    }

    int cutOffTree(vector<vector<int>>& forest) {
        vector<pair<int, int>> trees;
        int row = forest.size();
        int col = forest[0].size();
        for (int i = 0; i < row; ++i) {
            for (int j = 0; j < col; ++j) {
                if (forest[i][j] > 1) {
                    trees.emplace_back(i, j);
                }
            }
        }
        sort(trees.begin(), trees.end(), [&](const pair<int, int> & a, const pair<int, int> & b) {
            return forest[a.first][a.second] < forest[b.first][b.second];
        });

        int cx = 0;
        int cy = 0;
        int ans = 0;
        for (int i = 0; i < trees.size(); ++i) {
            int steps = bfs(forest, cx, cy, trees[i].first, trees[i].second);
            if (steps == -1) {
                return -1;
            }
            ans += steps;
            cx = trees[i].first;
            cy = trees[i].second;
        }
        return ans;
    }
};

5月24日:965. 单值二叉树

题目链接

class Solution {
public:
    bool isUnivalTree(TreeNode* root) {
        if (!root) return true;
        if (root->left)
            if (root->val != root->left->val || !isUnivalTree(root->left))
                return false;
        if (root->right)
            if (root->val != root->right->val || !isUnivalTree(root->right))
                return false;
        return true;
    }
};

5月25日:467. 环绕字符串中唯一的子字符串

题目链接

class Solution {
public:
    int findSubstringInWraproundString(string p) {
        vector<int> dp(26);
        int k = 0;
        for (int i = 0; i < p.length(); ++i) {
            if (i && (p[i] - p[i - 1] + 26) % 26 == 1) { // 字符之差为 1 或 -25
                ++k;
            } else {
                k = 1;
            }
            dp[p[i] - 'a'] = max(dp[p[i] - 'a'], k);
        }
        return accumulate(dp.begin(), dp.end(), 0);
    }
};

5月26日:699. 掉落的方块

题目链接

class Solution {
public:
    vector<int> fallingSquares(vector<vector<int>>& positions) {
        int n = positions.size();
        vector<int> heights(n);
        for (int i = 0; i < n; i++) {
            int left1 = positions[i][0], right1 = positions[i][0] + positions[i][1] - 1;
            heights[i] = positions[i][1];
            for (int j = 0; j < i; j++) {
                int left2 = positions[j][0], right2 = positions[j][0] + positions[j][1] - 1;
                if (right1 >= left2 && right2 >= left1) {
                    heights[i] = max(heights[i], heights[j] + positions[i][1]);
                }
            }
        }
        for (int i = 1; i < n; i++) {
            heights[i] = max(heights[i], heights[i - 1]);
        }
        return heights;
    }
};

5月27日:面试题 17.11. 单词距离

题目链接

class Solution {
public:
    int findClosest(vector<string>& words, string word1, string word2) {
        int minv = words.size();
        int a = -1, b = -1;
        for (int i = 0; i < words.size(); i ++ )
        {
            if (words[i] == word1)
                a = i;
            if (words[i] == word2)
                b = i;
            if (a >= 0 && b >= 0)
                minv = min(minv, abs(a - b));
        }

        return minv;
    }
};

5月28日:1021. 删除最外层的括号

题目链接

// 计数
class Solution {
public:
    string removeOuterParentheses(string s) {
        int level = 0;
        string res;
        for (auto c : s)
        {
            if (c == ')') level -- ;
            if (level) res.push_back(c);
            if (c == '(') level ++ ;
        }
        return res;
    }
};

// 栈
class Solution {
public:
    string removeOuterParentheses(string s) {
        stack<char> st;
        string res;      
        for (auto c : s)
        {
            if (c == ')') st.pop();
            if (!st.empty()) res.push_back(c);
            if (c == '(') st.push(c);
        }
        return res;
    }
};

5月29日:468. 验证IP地址

题目链接

class Solution {
public:
    bool is_IPV4(string s)
    {
        int cnt = 0;
        for (int i = 0; i < s.size(); )
        {
            int j = i;
            while (j < s.size() && s[j] != '.') j ++ ;
            if (j == s.size() - 1 && s[j] == '.') return false;
            string str = s.substr(i, j - i);
            cnt ++ ;

            if (str.size() > 1 && str[0] == '0') return false;

            if (!str.size() || str.size() > 3) return false;

            for (int i = 0; i < str.size(); i ++ )
                if (!isdigit(str[i])) return false;

            if (atoi(str.c_str()) > 255) return false;
            
            i = j + 1;
        }

        if (cnt != 4) return false;

        return true;
    }

    bool is_IPV6(string s)
    {
        int cnt = 0;
        for (int i = 0; i < s.size(); )
        {
            int j = i;
            while (j < s.size() && s[j] != ':') j ++ ;
            if (j == s.size() - 1 && s[j] == ':') return false;
            string str = s.substr(i, j - i);
            cnt ++ ;
            
            if (str.size() > 4 || str.size() < 1) return false;
            for (int k = 0; k < str.size(); k ++ )
                if (!isdigit(str[k]))
                    if (str[k] < 'A' || str[k] > 'F' && str[k] < 'a' || str[k] > 'f')
                        return false;
            
            i = j + 1;
        }

        if (cnt != 8) return false;

        return true;
    }

    string validIPAddress(string queryIP) {
        bool flag = true;
        for (int i = 0; i < queryIP.size(); i ++ )        
            if (queryIP[i] == '.')
            {
                flag = false;
                break;
            }

        if (!flag) 
        {    
            if (is_IPV4(queryIP))
                return "IPv4";
        }
        else 
        {
            if (is_IPV6(queryIP))
                return "IPv6";
        }

        return "Neither";
    }
};

5月30日:1022. 从根到叶的二进制数之和

题目链接

递归:

class Solution {
public:
    int sum = 0;
    int res = 0;
    void dfs(TreeNode* root)
    {
        if (root == nullptr) return;
        sum = sum * 2 + root->val;
        if (root->left == nullptr && root->right == nullptr)
            res += sum;

        dfs(root->left);

        dfs(root->right);

        sum = (sum - root->val) / 2;
    }

    int sumRootToLeaf(TreeNode* root) {
        dfs(root);
        return res;
    }
};

迭代:

class Solution {
public:
    int sumRootToLeaf(TreeNode* root) {
        stack<TreeNode*> st;
        int val = 0, ret = 0;
        TreeNode* prev = nullptr;
        while (root != nullptr || !st.empty())
        {
            while (root != nullptr)
            {
                val = (val << 1) | root->val;
                st.push(root);
                root =  root->left;
            }

            root = st.top();
            if (root->right == nullptr || root->right == prev)
            {
                if (root->left == nullptr && root->right == nullptr)
                    ret += val;
                val >>= 1;
                st.pop();
                prev = root;
                root = nullptr;
            }
            else 
                root = root->right;
        }
        return ret;
    }
};

5月31日:剑指 Offer II 114. 外星文字典

题目链接

class Solution {
public:
    unordered_map<char, vector<char>> edges; // 每个点:对应的边
    unordered_map<char, int> indegrees; // 点的入度
    bool valid = true;

    string alienOrder(vector<string>& words) {
        int length = words.size();

        // 建立点
        for (auto word : words)
        {
            int wordLength = word.size();
            for (int j = 0; j < wordLength; j ++ )
            {
                char c = word[j];
                if (!edges.count(c))
                    edges[c] = vector<char>();
            }
        }

        // 建立边
        for (int i = 1; i < length && valid; i ++ )
            addEdge(words[i - 1], words[i]);

        if (!valid) return "";

        // topsort
        queue<char> qu;

        // 插入入度为0的点
        for (auto c : edges)
            if (!indegrees.count(c.first))
                qu.push(c.first);

        string order;
        while (!qu.empty())
        {
            char u = qu.front(); qu.pop();
            order.push_back(u);
            for (char v : edges[u])
            {
                indegrees[v] -- ;
                if (indegrees[v] == 0)
                    qu.push(v);
            }
        }

        return order.size() == edges.size() ? order : "";
    }

    // 建图
    void addEdge(string before, string after)
    {
        int length1 = before.size(), length2 = after.size();
        int length = min(length1, length2);
        int index = 0;
        while (index < length)
        {
            char c1 = before[index], c2 = after[index];
            if (c1 != c2)
            {
                edges[c1].push_back(c2);
                indegrees[c2] ++ ;
                break;
            }
            index ++ ;
        }

        if (index == length && length1 > length2)
            valid = false;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
20226的Python编程题讲解是针对Python编程的3级题目进行的。Python编程的3级题目主要是在掌握基础语法和常用函数的基础上进行深入应用和综合运用。讲解内容将涵盖以下几个方面。 第一部分是基础语法和数据类型的复习。包括控制流程语句(if语句、循环语句等)、数据类型(字符串、列表、字典等)以及常用操作符和函数的使用。通过对基础语法和数据类型的复习,能够帮助学生巩固基础知识,为高级应用打下坚实的基础。 第二部分是函数和模块的进阶应用。讲解如何定义和调用函数,以及如何使用内置函数和自定义函数解决复杂的问题。同时,介绍如何创建和使用模块,将程序组织为模块化的结构,提高代码的可重用性和可维护性。 第三部分是文件操作和异常处理。讲解如何读写文件、创建目录、遍历文件目录等文件操作技巧。同时,引入异常处理的概念,讲解如何捕获异常和处理异常,增强程序的健壮性和可靠性。 第四部分是面向对象编程的基础知识。讲解类和对象的概念,如何定义类、创建对象,以及如何使用类来实现封装、继承和多态等面向对象的特性。 通过对这些内容的讲解,学生可以进一步提高自己的Python编程水平,掌握更加复杂的编程技巧和方法,为实际项目的开发和应用奠定基础。同时,通过实际编程练习,学生还可以提升解决问题的能力和创新思维。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值