zoukankan      html  css  js  c++  java
  • 字节校园打卡记录

    字节校园打卡记录

    目录

    8.19

    3. 无重复字符的最长子串

    • 双指针构成一个滑动窗口
    • 哈希表记录每个元素的出现位置
    // go
    func max(a int, b int) int {
        if a < b {
            return b
        } else {
            return a
        }
    }
    
    func lengthOfLongestSubstring(s string) int {
        mp := make(map[byte]int)
        l, r, ans := 0, 0, 0
        for r < len(s) {
            val, ok := mp[s[r]]
            if !ok {
                mp[s[r]] = r
            } else {
                // mp[s[r]] 表示上一个 s[r] 出现的位置,如果 mp[s[r]] > l,要把 l 移到 mp[s[r]] 之后
                if val >= l {
                    l = val + 1
                }
                mp[s[r]] = r
            }
            ans = max(ans, r-l+1)
            r++
        }
        return ans
    }
    

    25. K 个一组翻转链表

    • 维护四个指针 pre, head, tail, next
    • 找到待反转链表的头尾
    • 做一次普通反转链表,返回新的头尾
    • 串联
    // cpp
    #define PLL pair< ListNode *, ListNode * >
    class Solution {
    public:
        PLL getNewHeadTail(ListNode *head, ListNode *tail)
        {
            ListNode *pre = tail->next, *cur = head, *ed = tail->next;
            while (cur != ed) {
                ListNode *temp = cur->next;
                cur->next = pre;
                pre = cur, cur = temp;
            }
            return {tail, head};
        }
        ListNode *reverseKGroup(ListNode *head, int k)
        {
            ListNode *dummy = new ListNode(0, head), *pre = dummy;
            while (head) {
                ListNode *tail = pre;
                for (int i = 0; i < k; ++i) {
                    tail = tail->next;
                    if (!tail) return dummy->next;
                }
                ListNode *nxt = tail->next;
                PLL temp = getNewHeadTail(head, tail);
                head = temp.first, tail = temp.second;
                pre->next = head, tail->next = nxt;
                pre = tail, head = nxt;
            }
            return dummy->next;
        }
    };
    

    20. 有效的括号

    // cpp
    class Solution {
    public:
        bool isValid(string s) {
            stack<int> sta;
            for (auto &i: s) {
                if (i == '(' || i == '[' || i == '{') sta.push(i);
                else {
                    if (sta.empty()) return 0;
                    if (i == ')' && sta.top() != '(') return 0;
                    if (i == ']' && sta.top() != '[') return 0;
                    if (i == '}' && sta.top() != '{') return 0;
                    sta.pop();
                }
            }
            return sta.empty();
        }
    };
    

    8.20

    1. 两数之和

    • 哈希
    • 或者排序后双指针 meet in the middle
    // go
    func twoSum(nums []int, target int) []int {
        mp := make(map[int]int)
        for i, v := range nums {
            mp[v] = i
        }
        ans := []int{}
        for i, v := range nums {
            if pos, ok := mp[target-v]; ok && pos > i {
                ans = []int{i, pos}
                break
            }
        }
        return ans
    }
    

    15. 三数之和

    • 排序
    • 枚举第一个数字,接下来两个指针 meet in the middle
    • 用一些去重剪枝技巧
    // go
    func threeSum(nums []int) [][]int {
        n := len(nums)
        sort.Ints(nums)
        ans := [][]int{}
        for i := 0; i < n; i++ {
            if nums[i] > 0 { // 剪枝
                break
            }
            if i > 0 && nums[i] == nums[i - 1] { // 去重,可能的解已经存在了
                continue;
            }
            k := n - 1
            for j := i + 1; j < n; j++ {
                if j > i + 1 && nums[j] == nums[j - 1] { // 去重,同上
                    continue
                }
                for k > j && nums[i] + nums[j] + nums[k] > 0 {
                    k--
                }
                if k == j {
                    break
                }
                if nums[i] + nums[j] + nums[k] == 0 {
                    ans = append(ans, []int{nums[i], nums[j], nums[k]})
                }
            }
        }
        return ans
    }
    

    54. 螺旋矩阵

    • dfs
    // go
    func spiralOrder(matrix [][]int) []int {
        m, n := len(matrix), len(matrix[0])
        ans := make([]int, m * n)
        vis := make([][]bool, m)
        for i := 0; i < len(matrix); i++ {
            vis[i] = make([]bool, n)
        }
        dfs(matrix, vis, ans, m, n, 0, 0, 0, 0)
        return ans
    }
    func check(m, n, x, y int, vis[][]bool) bool {
        return x >= 0 && x < m && y >= 0 && y < n && vis[x][y] == false
    }
    func dfs(matrix [][]int, vis [][]bool, ans []int, m, n, x, y, dir, cnt int) {
        if vis[x][y] {
            return
        }
        ans[cnt], cnt, vis[x][y] = matrix[x][y], cnt + 1, true
        DX := []int{0, 1, 0, -1}
        DY := []int{1, 0, -1, 0}
        var tx, ty int
        if check(m, n, x + DX[dir], y + DY[dir], vis) { // 继续顺着这个方向
            tx, ty = x + DX[dir], y + DY[dir]
        } else if check(m, n, x + DX[(dir + 1) % 4], y + DY[(dir + 1) % 4], vis) {  // 换下一个方向
            tx, ty, dir = x + DX[(dir + 1) % 4], y + DY[(dir + 1) % 4], (dir + 1) % 4
        }
        dfs(matrix, vis, ans, m, n, tx, ty, dir, cnt)
    }
    

    8.21

    33. 搜索旋转排序数组

    • 无聊的八股文,没兴趣写二分
    // cpp
    class Solution {
    public:
        int search(vector<int>& nums, int t) {
            for (int i = 0; i < nums.size(); ++i)
                if (nums[i] == t) return i;
            return -1;
        }
    };
    

    21. 合并两个有序链表

    • 归并排序的子步骤
    // go
    func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
        head := &ListNode {
            Val: 0,
            Next: nil,
        }
        pre := head
        for l1 != nil || l2 != nil {
            if l1 == nil || l1 != nil && l2 != nil && l1.Val > l2.Val {
                head.Next = l2
                l2 = l2.Next
            } else {
                head.Next = l1
                l1 = l1.Next
            }
            head = head.Next
        }
        return pre.Next
    }
    

    31. 下一个排列

    • 逆序遍历,找到第一个 nums[i] < nums[i + 1] 的位置 p1
    • [p1 + 1, n) 里面找到第一个比 nums[p1] 大的位置 p2
    • 逆转 [p1 + 1, n)
    // cpp
    class Solution {
    public:
        void nextPermutation(vector<int>& nums) {
            next_permutation(nums.begin(),  nums.end());
        }
    };
    
    // cpp
    class Solution {
    public:
        void nextPermutation(vector<int>& nums) {
            int n = nums.size();
            int pos = -1;
            for (int i = n - 2; i >= 0; --i) {
                if (nums[i] < nums[i + 1]) {pos = i; break;}
            }
            if (pos != -1) {
                int p = n - 1;
                while (p > pos && nums[p] <= nums[pos]) p--;
                swap(nums[pos], nums[p]);
            }
            reverse(nums.begin() + pos + 1, nums.end());
        }
    };
    

    8.22

    42. 接雨水

    • 对于每个位置 i,找到他左边和右边最高的位置 p1, p2,则这个位置的贡献为 min(h[p1], h[p2]) - h[i]
    • 累加贡献
    // go
    func trap(h []int) int {
        lmax := make([]int, len(h))
        rmax := make([]int, len(h))
        for i := 0; i < len(h); i++ {
            if i == 0 {
                lmax[i] = h[i];
            } else {
                lmax[i] = max(lmax[i - 1], h[i])
            }
        }
        for i := len(h) - 1; i >= 0; i-- {
            if i == len(h) - 1 {
                rmax[i] = h[i]
            } else {
                rmax[i] = max(rmax[i + 1], h[i])
            }
        }
        ans := 0
        for i := 1; i < len(h) - 1; i++ {
            ans += min(lmax[i], rmax[i]) - h[i]
        }
        return ans
    }
    
    func max(a, b int) int {
        if a < b {
            return b
        } else {
            return a
        }
    }
    func min(a, b int) int {
        if a < b {
            return a
        } else {
            return b
        }
    }
    

    53. 最大子序和

    • 动态规划的思想
    // go
    func maxSubArray(nums []int) int {
        sum, ans := 0, -100001
        for _, v := range(nums) {
            sum = max(sum + v, v)
            ans = max(ans, sum)
        }
        return ans
    }
    
    func max(a, b int) int {
        if a < b {
            return b
        } else {
            return a
        }
    }
    

    88. 合并两个有序数组

    • 没兴趣写 in place
    // go
    func merge(nums1 []int, m int, nums2 []int, n int)  {
        temp := make([]int, m + n)
        i, j, k := 0, 0, 0
        for i < m || j < n {
            if (i == m || i < m && j < n && nums1[i] > nums2[j]) {
                temp[k] = nums2[j]
                k++
                j++
            } else {
                temp[k] = nums1[i]
                k++
                i++
            }
        }
        for i, v := range(temp) {
            nums1[i] = v
        }
    }
    
    • in place 的补上了
    • 从后往前归并,大的数据会被填在后面,前面的数据直接覆盖即可
    // cpp
    class Solution {
    public:
        void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
            int a = m - 1, b = n - 1, c = m + n - 1;
            while (c >= 0) {
                if (a >= 0 && b >= 0) {
                    if (nums1[a] > nums2[b]) nums1[c--] = nums1[a--];
                    else nums1[c--] = nums2[b--];  
                }
                else {
                    if (a >= 0) nums1[c--] = nums1[a--];
                    else if (b >= 0) nums1[c--] = nums2[b--];
                }
            }
        }
    };
    

    8.23

    102. 二叉树的层序遍历

    • 把一层放入队列来 bfs
    // cpp
    class Solution {
    public:
        vector<vector<int>> levelOrder(TreeNode* root) {
            vector<vector<int>> ans;
            if (!root) return ans;
            queue<TreeNode *> q;
            q.push(root);
            while (!q.empty()) {
                int sz = q.size();
                vector<int> level;
                for (int i = 1; i <= sz; ++i) {
                    TreeNode *temp = q.front(); q.pop();
                    level.push_back(temp->val);
                    if (temp->left) q.push(temp->left);
                    if (temp->right) q.push(temp->right);
                }
                ans.push_back(level);
            }
            return ans;
        }
    };
    

    103. 二叉树的锯齿形层序遍历

    • 用双端队列来维护节点
    • 从右往左遍历先放右儿子,从左往右遍历先放左儿子
    // cpp
    class Solution {
    public:
        vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
            vector<vector<int>> ans;
            if (!root) return ans;
            deque<TreeNode *> q;
            q.push_back(root);
            int cnt = 0;
            while (!q.empty()) {
                int sz = q.size();
                vector<int> level;
                if (cnt == 0) {
                    for (int i = 1; i <= sz; ++i) { // 从左往右遍历,先放左儿子
                        TreeNode *temp = q.front(); q.pop_front();
                        level.push_back(temp->val);
                        if (temp->left) q.push_back(temp->left);
                        if (temp->right) q.push_back(temp->right);
                    }
                }
                else {
                    for (int i = 1; i <= sz; ++i) { // 从右往左遍历,先放右儿子
                        TreeNode *temp = q.back(); q.pop_back();
                        level.push_back(temp->val);
                        if (temp->right) q.push_front(temp->right);
                        if (temp->left) q.push_front(temp->left);
                    }
                }
                cnt = (cnt + 1) % 2;
                ans.push_back(level);
            }
            return ans;
        }
    };
    

    105. 从前序与中序遍历序列构造二叉树

    • 前序结构为 [root] [left] [right]
    • 中序结构为 [left] [root] [right]
    • 在中序中找到根的位置 pos1,就可以快速定位前序中左子树的右边界 pos2
    • 可以用哈希预处理中序里面根的位置
    // cpp
    class Solution {
    public:
        unordered_map<int, int> mp;
        void preSolve(vector<int> &inorder) {
            for (int i = 0; i < inorder.size(); ++i) {
                mp[inorder[i]] = i;
            }
        }
        TreeNode* dfs(vector<int>& preorder, vector<int>& inorder, int pl, int pr, int il, int ir) {
            if (pl >= pr) return nullptr;
            TreeNode *root = new TreeNode(preorder[pl]);
            int pos1 = mp[root->val]; // 利用哈希表 O(1) 计算根在中序遍历中的位置 pos1
            int pos2 = pl + (pos1 - il); // 根据 pos1 计算出左子树的边界位置 pos2
            root->left = dfs(preorder, inorder, pl + 1, pos2 + 1, il, pos1);
            root->right = dfs(preorder, inorder, pos2 + 1, pr, pos1 + 1, ir);
            return root;
        }
        TreeNode* buildTree(vector<int>& p, vector<int>& i) {
            preSolve(i);
            return dfs(p, i, 0, p.size(), 0, i.size());
        }
    };
    /*
    [root] [left] [right]
    [left] [root] [right]
    */
    

    8.24

    121. 买卖股票的最佳时机

    • 对于每一个位置,维护之前的最小值即可
    // go
    func maxProfit(p []int) int {
        mini := 10001
        ans := 0
        for _, v := range(p) {
            mini = min(mini, v)
            ans = max(ans, v - mini)
        }
        return ans
    }
    func max(a, b int) int {
        if a < b {
            return b
        } else {
            return a
        }
    }
    func min(a, b int) int {
        if a < b {
            return a
        } else {
            return b
        }
    }
    

    141. 环形链表

    • 快慢指针追
    // go
    func hasCycle(head *ListNode) bool {
        if head == nil {
            return false
        }
        a, b := head, head.Next
        for a != nil && b != nil && a != b {
            a = a.Next
            b = b.Next
            if b != nil {
                b = b.Next
            } else {
                break
            }
        }
        return a == b
    }
    

    146. LRU 缓存机制

    考虑需要的数据结构

    • 需要左右删除,因此维护一个双向链表 node*
    • 需要快速定位节点位置,因此维护一个哈希表 unordered_map<int, node*>
    • 设置一个 dummy head, dummy tail,避免删除特判情况
    • 每次要根据节点的键来更新,因此双向链表里需要维护 key, val

    考虑需要的方法

    • 每次 put,需要添加到头,容量大了要删除尾巴
    • 每次 get,需要删除一个节点并添加到头
    • 所以需要完善三个方法
    void addHead(node *)
    void del(node *)
    void delTail(node *)
    

    代码

    // cpp
    struct node
    {
        node *left, *right;
        int key, val;
        node(){}
        node(int _key, int _val): key(_key), val(_val), left(nullptr), right(nullptr) {}
    };
    class LRUCache {
    private:
        unordered_map< int, node * > mp;
        node *head, *tail;
        int sz, cap;
    
    public:
        LRUCache(int capacity): cap(capacity), sz(0) {
            head = new node(-1, 0);
            tail = new node(-2, 0);
            head->right = tail;
            tail->left = head;
        }
        void del(node *cur) {
            mp[cur->key] = nullptr;
            node *a = cur->left;
            node *b = cur->right;
            a->right = b;
            b->left = a;
            sz--;
        }
        void delTail() {
            node *a = tail->left;
            del(a);
        }
        void addHead(node *cur) {
            node *a = head->right;
            head->right = cur, cur->left = head;
            cur->right = a, a->left = cur;
            mp[cur->key] = cur;
            sz++;
        }
        int get(int key)
        {
            node *cur = mp[key];
            if (cur) {
                int ans = cur->val;
                del(cur);
                addHead(cur);
                return ans;
            }
            else return -1;
        }
        void put(int key, int value)
        {
            node *temp = mp[key];
            if (temp) {
                temp->val = value;
                del(temp);
                addHead(temp);
            }
            else {
                node *cur = new node(key, value);
                addHead(cur);
                if (sz > cap) delTail();
                mp[key] = cur;
            }
            //debug(head);
        }
        void debug(node *head) {
            cout << "fuck" << ' ' << sz << ' ' << cap << endl;
            while (head) {
                cout << head->key << ' ' << head->val << endl;
                head = head->right;
            }
        }
    };
    

    8.25

    160. 相交链表

    • 两个指针走,走到尽头换一个头开始遍历
    • 相遇或者走到头时两个指针走的路程一定一样
    // go
    func getIntersectionNode(headA, headB *ListNode) *ListNode {
        A, B := headA, headB
        for A != B {
            if A == nil {
                A = headB
            } else {
                A = A.Next
            }
            if B == nil {
                B = headA
            } else {
                B = B.Next
            }
        }
        return A
    }
    

    199. 二叉树的右视图

    • 层序遍历,把一行放入队列,用队列的大小来指导循环次数
    • 把每一行的最后一个数放入列表,最终返回这个列表
    // cpp
    class Solution {
    public:
        vector<int> rightSideView(TreeNode* root) {
            vector<int> ans;
            if (!root) return ans; 
            queue<TreeNode *> q;
            q.push(root);
            while (!q.empty()) {
                int sz = q.size();
                for (int i = 1; i <= sz; ++i) {
                    TreeNode* temp = q.front(); q.pop();
                    if (i == sz) ans.push_back(temp->val);
                    if (temp->left) q.push(temp->left);
                    if (temp->right) q.push(temp->right);
                }
            }
            return ans;
        }
    };
    

    200. 岛屿数量

    • 求联通块个数,可以 bfs,也可以并查集
    // cpp
    const int DX[] = {0, 1, 0, -1};
    const int DY[] = {1, 0, -1, 0};
    class Solution {
    public:
        bool check(int x, int y, vector<vector<char>>& grid, vector<vector<int>>& vis) {
            int m = grid.size();
            int n = grid[0].size();
            return x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && grid[x][y] != '0';
        }
        void bfs(int x, int y, vector<vector<char>>& grid, vector<vector<int>>& vis) {
            queue<pair<int, int>> q;
            q.push(pair<int, int>{x, y});
            vis[x][y] = 1;
            while (!q.empty()) {
                pair<int, int> temp = q.front(); q.pop();
                //cout << temp.first << ' ' << temp.second << endl;
                for (int i = 0; i < 4; ++i) {
                    int tx = temp.first + DX[i];
                    int ty = temp.second + DY[i];
                    if (check(tx, ty, grid, vis)) {
                        q.push(pair<int, int>{tx, ty});
                        vis[tx][ty] = 1;
                    }
                }
            }
        }
        int numIslands(vector<vector<char>>& grid) {
            vector<vector<int>> vis(grid.size(), vector<int>(grid[0].size()));
            int ans = 0;
            for (int i = 0; i < grid.size(); ++i) {
                for (int j = 0; j < grid[0].size(); ++j) {
                    if (!vis[i][j] && grid[i][j] != '0') {
                        bfs(i, j, grid, vis);
                        ans++;
                    }
                }
            }
            return ans;
        }
    };
    

    8.26

    反转链表

    • 经典
    // cpp
    class Solution {
    public:
        ListNode* reverseList(ListNode* head) {
            ListNode *pre = nullptr;
            while (head) {
                ListNode *temp = head->next;
                head->next = pre;
                pre = head;
                head = temp;
            }
            return pre;
        }
    };
    

    8.27

    300. 最长递增子序列

    • (O(nlog n)) 做法
    • 定义 (dp[i]) 表示长度为 (i + 1)(LIS) 最后一位的最小元素
    // cpp
    #define inf 0x3f3f3f3f
    class Solution {
    public:
        int lengthOfLIS(vector<int>& nums) {
            int n = (int)nums.size();
            vector<int> dp(n);
            fill(dp.begin(), dp.end(), inf);
            for (int i = 0; i < n; ++i) {
                *lower_bound(dp.begin(), dp.end(), nums[i]) = nums[i];
            }
            //for (int i = 0; i < n; ++i) cout << i << ' ' << dp[i] << endl;
            return lower_bound(dp.begin(), dp.end(), inf) - dp.begin();
        }
    };
    
    • (O(n^2)) 做法
    // go
    func lengthOfLIS(nums []int) int {
        dp := make([]int, len(nums))
        dp[0] = 1;
        ans := 1
        for i := 1; i < len(nums); i++ {
            dp[i] = 1
            for j := 0; j < i; j++ {
                if nums[j] < nums[i] {
                    dp[i] = max(dp[i], dp[j] + 1)
                }
            }
            ans = max(ans, dp[i])
        }
        return ans
    }
    
    func max(a, b int) int {
        if a < b {
            return b
        } else {
            return a
        }
    }
    

    415. 字符串相加

    • 模拟
    // cpp
    class Solution {
    public:
        string addStrings(string num1, string num2) {
            int i = num1.length() - 1, j = num2.length() - 1, add = 0;
            string ans = "";
            while (i >= 0 || j >= 0 || add != 0) {
                int x = i >= 0 ? num1[i] - '0' : 0;
                int y = j >= 0 ? num2[j] - '0' : 0;
                int result = x + y + add;
                ans += '0' + result % 10;
                add = result / 10;
                i -= 1;
                j -= 1;
            }
            reverse(ans.begin(), ans.end());
            return ans;
        }
    };
    

    23. 合并 K 个升序链表

    • 用优先队列来维护
    • 动态开内存
    // cpp
    struct node {
        ListNode *head;
        int val;
        node() {}
        node(ListNode* _head, int _val):
            head(_head), val(_val) {}
    };
    bool operator < (const node &a, const node &b) {
        return a.val > b.val;
    }
    class Solution {
    public:
        ListNode* mergeKLists(vector<ListNode*>& lists) {
            priority_queue<node> pq;
            for (auto &i: lists) if (i) pq.push(node(i, i->val));
            ListNode *pre = new ListNode();
            ListNode *head = pre;
            while (!pq.empty()) {
                node temp = pq.top(); pq.pop();
                //cout << temp.val << pq.size() << ' ' << endl;
                head->next = new ListNode(temp.val);
                if (temp.head->next) pq.push(node(temp.head->next, temp.head->next->val));
                head = head->next;
            }
            return pre->next;
        }
    };
    

    8.28

    2. 两数相加

    • 模拟
    // go
    func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
        up := 0
        head := &ListNode {
            Val: 0,
            Next: nil,
        }
        pre := head
        for l1 != nil || l2 != nil || up > 0 {
            temp := 0
            if l1 != nil {
                temp += l1.Val
                l1 = l1.Next
            }
            if l2 != nil {
                temp += l2.Val
                l2 = l2.Next
            }
            temp += up
            head.Next = &ListNode {
                Val: temp % 10,
                Next: nil,
            }
            up = temp / 10
            head = head.Next
        }
        return pre.Next
    }
    

    5. 最长回文子串

    • 区间 (dp)
    • 定义 (dp[i][j]) 表示区间 ([i, j]) 是否为回文串
    • 第一层枚举区间长度,第二层枚举区间左端点
    • (dp[i - 1][j + 1])(dp[i][j]) 转移过来
    • 时间复杂度和空间复杂度 (O(n^2))
    // go
    func longestPalindrome(s string) string {
        n := len(s)
        dp := make([][]bool, n)
        for i := 0; i < n; i++ {
            dp[i] = make([]bool, n)
        }
        pos, ans := 0, 1
        for i := 0; i < n; i++ {
            dp[i][i] = true
            if i+1 < n && s[i+1] == s[i] && ans < 2 {
                dp[i][i+1] = true
                pos = i
                ans = 2
            }
        }
        for L := 0; L < n; L++ {
            for i := 0; i < n; i++ {
                if i-1 >= 0 && i+L+1 < n && s[i-1] == s[i+L+1] && dp[i][i+L] && L+3 > ans {
                    dp[i-1][i+L+1] = true
                    pos = i - 1
                    ans = L + 3
                }
            }
        }
        return s[pos : pos+ans]
    }
    

    39. 组合总和

    说几个 dfs 的细节

    • 可重复选,所以选完当前这个,idx 保持不变
    • 可不选当前,所以 idx + 1 后进入下一层
    // go
    func combinationSum(c []int, target int) (ans [][]int) {
        temp := []int{}
        var dfs func(idx, sum int)
        dfs = func(idx, sum int) {
            if idx == len(c) {
                return
            }
            if sum == 0 {
                ans = append(ans, append([]int{}, temp...))
                return
            }
            dfs(idx + 1, sum) // 直接跳过
            if sum - c[idx] >= 0 { // 选择当前
                temp = append(temp, c[idx])
                dfs(idx, sum - c[idx]) // 可重复选择
                temp = temp[:len(temp) - 1]
            }
        }
        dfs(0, target)
        return ans
    }
    

    8.29

    41. 缺失的第一个正数

    • 哈希,复杂度为 (O(n))
    // go
    func firstMissingPositive(nums []int) int {
        mp := make(map[int]int)
        ans := 0
        for i := 0; i < len(nums); i++ {
            mp[nums[i]] = 1
        }
        for i := 1; mp[i] != 0; i++ {
            ans = i    
        }
        return ans + 1
    }
    

    46. 全排列

    • 排序后调用 next_permutation
    // cpp
    class Solution {
    public:
        vector<vector<int>> permute(vector<int>& nums) {
            vector<vector<int>> ans;
            sort(nums.begin(), nums.end());
            bool flag = false;
            do {
                ans.push_back(nums);
                flag = next_permutation(nums.begin(), nums.end());
            } while(flag);
            return ans;
        }
    };
    

    56. 合并区间

    • 按照左端点、右端点升序排序
    • 按顺序逐个合并
    // go
    type interval [][]int
    func (I interval) Len() int {
        return len(I)
    }
    func (I interval) Less(i, j int) bool {
        if I[i][0] == I[j][0] {
            return I[i][1] < I[j][1]
        }
        return I[i][0] < I[j][0]
    }
    func (I interval) Swap(i, j int) {
        I[i], I[j] = I[j], I[i]
    }
    func merge(intervals [][]int) [][]int {
        sort.Sort(interval(intervals))
        ans := make([][]int, 0)
        l, r := intervals[0][0], intervals[0][1]
        for i := 1; i < len(intervals); i++ {
            if intervals[i][0] <= r {
                r = max(r, intervals[i][1])
            } else {
                ans = append(ans, []int{l, r})
                l, r = intervals[i][0], intervals[i][1]
            }
        }
        ans = append(ans, []int{l, r})
        return ans
    }
    func max(a, b int) int {
        if a < b {
            return b
        } else {
            return a
        }
    }
    

    8.30

    69. x 的平方根

    • 二分答案,遇到可行解则保留答案,时间复杂度 (O(log x))
    // go
    func mySqrt(x int) int {
        l, r := 0, x
        ans := 0
        for l <= r { // 二分答案
            mid := (l + r) / 2
            if mid * mid <= x { // 遇到了可行解
                ans = mid
                l = mid + 1
            } else {
                r = mid - 1;
            }
        }
        return ans
    }
    

    70. 爬楼梯

    • 斐波那契,可以优化空间到 (O(1))
    // go
    func climbStairs(n int) int {
        dp := make([]int, n + 1)
        dp[0], dp[1] = 1, 1
        for i := 2; i <= n; i++ {
            dp[i] = dp[i - 1] + dp[i - 2]
        }
        return dp[n]
    }
    

    8.31

    92. 反转链表 II

    • 参考「k 个一组反转链表」
    • 四个指针维护,子问题为反转链表
    // cpp
    class Solution {
    public:
        pair<ListNode*, ListNode*> solve(ListNode *L, ListNode *R) {
            ListNode *pre = new ListNode(0, L), *ed = R->next;
            ListNode *head = L, *tail = pre;
            while (head != ed) {
                ListNode *temp = head->next;
                head->next = pre;
                pre = head;
                head = temp;
            }
            return {pre, tail->next};
        }
        ListNode* reverseBetween(ListNode* head, int l, int r) {
            ListNode *dummy = new ListNode(0, head);
            ListNode *pre = dummy, *tail = dummy;
            ListNode *L = head, *R = head;
            int cnt = 0;
            while (head) {
                cnt++;
                if (cnt < l) {
                    pre = head;
                    L = head->next;
                }
                else if (cnt == r) {
                    R = head;
                    tail = head->next;
                }
                head = head->next;
            }
            pair<ListNode*, ListNode*> temp = solve(L, R);
            pre->next = temp.first;
            temp.second->next = tail;
            return dummy->next;
        }
    };
    

    94. 二叉树的中序遍历

    • 中序遍历
    // cpp
    class Solution {
    public:
        vector<int> dfs_sec;
        void ldr(TreeNode *root) {
            if (!root) return;
            if (root->left) ldr(root->left);
            dfs_sec.push_back(root->val);
            if (root->right) ldr(root->right);
        }
        vector<int> inorderTraversal(TreeNode* root) {
            ldr(root);
            return dfs_sec;
        }
    };
    

    98. 验证二叉搜索树

    • 中序遍历得到中序数组,判断数组是否有序即可
    // cpp
    class Solution {
    public:
        vector<int> dfs_sec;
        void ldr(TreeNode *root) {
            if (!root) return;
            if (root->left) ldr(root->left);
            dfs_sec.push_back(root->val);
            if (root->right) ldr(root->right);
        }
        bool isValidBST(TreeNode* root) {
            ldr(root);
            for (int i = 1; i < dfs_sec.size(); ++i) {
                if (dfs_sec[i] <= dfs_sec[i - 1]) return false;
            }
            return true;
        }
    };
    

    9.1

    101. 对称二叉树

    • 左子树与右子树镜像对称,且左子树与右子树均为对称二叉树
    • 维护两个指针 (p, q),彼此向相反方向各移动一个单位,然后递归求解
    // go
    func check(a, b *TreeNode) bool {
        if a == nil && b == nil  {
            return true
        }
        if a == nil || b == nil {
            return false
        }
        return check(a.Left, b.Right) && check(a.Right, b.Left) && a.Val == b.Val
    }
    func isSymmetric(root *TreeNode) bool {
        return check(root, root)    
    }
    

    112. 路径总和

    • dfs
    // go
    func dfs(root *TreeNode, t, sum int) bool {
        if root == nil {
            return false
        }
        sum += root.Val
        if root.Left == nil && root.Right == nil && sum == t {
            return true
        }
        flag := dfs(root.Left, t, sum) || dfs(root.Right, t, sum)
        return flag
    }
    func hasPathSum(root *TreeNode, t int) bool {
        return dfs(root, t, 0)
    }
    

    113. 路径总和 II

    说几点 go 的语法

    • defer 保证函数执行完之后一定会执行,不管这个函数是异常退出还是正常结束
    • func 是可以作为变量被传递的,定义在该函数之外的变量自然相对于其成为全局变量,可以被使用
    • ans = append([]int{}, temp...) 是为了把一个 tempcopy 添加进 ans,否则 temp 的改变会导致 ans 里的元素也改变
    // go
    func pathSum(root *TreeNode, t int) (ans [][]int) {
        temp := []int{}
        var dfs func(root *TreeNode, sum int)
        dfs = func(root *TreeNode, sum int) {
            if root == nil {
                return
            }
            sum -= root.Val
            temp = append(temp, root.Val)
            defer func() { temp = temp[:len(temp)-1] }()
            if root.Left == nil && root.Right == nil && sum == 0 {
                ans = append(ans, append([]int{}, temp...))
            }
            dfs(root.Left, sum)
            dfs(root.Right, sum)
        }
        dfs(root, t)
        return ans
    }
    

    9.2

    124. 二叉树中的最大路径和

    用树形 dp 的思想,考虑以节点 root 为根最大的路径和,有三种状态可以向上转移

    • 左子树带上 root
    • 右子树带上 root
    • 只有 root

    维护答案的时候,还要计算左右子树带上 root 的情况,虽然这种状态无法向上转移

    // go
    func maxPathSum(root *TreeNode) int {
        ans := -1001
        var dfs func(root *TreeNode) int
        dfs = func(root *TreeNode) int {
            if root == nil {
                return 0
            }
            Left := dfs(root.Left)
            Right := dfs(root.Right)
            temp := max(root.Val, max(Left, Right) + root.Val)
            ans = max(ans, max(temp, root.Val + Left + Right))
            return temp
        }
        ans = max(ans, dfs(root))
        return ans
    }
    
    func max(a, b int) int {
        if a < b {
            return b
        } else {
            return a
        }
    }
    

    129. 求根节点到叶节点数字之和

    • dfs
    // go
    var ans int
    func sumNumbers(root *TreeNode) int {
        pre := 0
        ans = 0
        dfs(root, pre)
        return ans
    }
    
    func dfs(root *TreeNode, val int) {
        if root == nil {
            return
        }
        val = val * 10 + root.Val
        if root.Left != nil {
            dfs(root.Left, val)
        }
        if root.Right != nil {
            dfs(root.Right, val)
        } 
        if root.Left == nil && root.Right == nil {
            ans += val
        }
        val = (val - root.Val) / 10
    }
    

    142. 环形链表 II

    快指针步长为 (2),慢指针为 (1),设环之前的链长 (a),快慢指针相遇处距离环口 (b),剩下的环长 (c)

    当快慢指针相遇时,设快指针走了 (x) 圈,慢指针走了 (y) 圈,考虑速度比,有 (a + x(b + c) + b = 2cdot [a + y(b + c) + b])

    (a + bequiv 0mod (b + c)),从而 (aequiv cmod (b + c))

    因此再设置一个指针从头走,一定可以与慢指针在环口相遇

    // go
    func detectCycle(head *ListNode) *ListNode {
        a, b := head, head
        for b != nil {
            a = a.Next
            if b.Next == nil {
                return nil
            }
            b = b.Next.Next
            if a == b {
                c := head
                for a != c {
                    a, c = a.Next, c.Next
                }
                return c
            }
        }
        return nil
    }
    

    9.3

    143. 重排链表

    • 用快慢指针找到链表中点
    • 快指针步长为 (2),慢指针步长为 (1),这样可以确保快指针到达终点的时候慢指针到达了中点
    • 反转后面一段链表
    • 合并两个链表
    // go
    func reorderList(head *ListNode)  {
        mid := getMid(head)
        b := mid.Next
        mid.Next = nil
        a := revert(b)
        merge(head, a)
    }
    
    // 快慢指针获取链表中点
    func getMid(head *ListNode) *ListNode {
        a, b := head, head
        for b != nil {
            if b.Next == nil {
                break
            }
            b = b.Next.Next
            a = a.Next
        }
        return a
    }
    
    // 反转链表
    func revert(head *ListNode) *ListNode {
        var pre *ListNode
        for head != nil {
            temp := head.Next
            head.Next = pre
            pre = head
            head = temp
        }
        return pre
    }
    
    // 合并链表
    func merge(a, b *ListNode) {
        for a != nil && b != nil {
            c := a.Next
            d := b.Next
            a.Next, b.Next = b, c
            a, b = c, d
        }
    }
    

    155. 最小栈

    • 借用辅助栈,辅助栈栈顶维护主栈中的最小值
    • 这样便可以 (O(1)) 调用主栈中的最小值
    // cpp
    class MinStack {
    public:
        stack<int> sta1, sta2;
        MinStack() {
        }
        
        void push(int val) {
            sta1.push(val);
            sta2.push(min(getMin(), val));
        }
        
        void pop() {
            if (!sta1.empty()) {
                sta1.pop();
                sta2.pop();
            }
        }
        
        int top() {
            return sta1.top();
        }
        
        int getMin() {
            if (!sta2.empty()) return sta2.top();
            else return 2147483647;
        }
    };
    

    232. 用栈实现队列

    • 维护两个栈 (A, B),其中 (A) 维护输入序列,(B) 维护输出序列
    • 每当需要 pop, peek 的时候,将 (A) 的元素全部 push(B) 中去
    • 每个元素只入栈出栈各 (2) 次,因此均摊复杂度为 (O(1))
    // cpp
    class MyQueue {
    public:
        stack<int> sta1, sta2;
        MyQueue() {
    
        }
        void mv() {
            if (sta2.empty()) {
                while (!sta1.empty()) {
                    sta2.push(sta1.top());
                    sta1.pop();
                }
            }
        }
        void push(int x) {
            sta1.push(x);
        }
        
        /** Removes the element from in front of queue and returns that element. */
        int pop() {
            mv();
            int ans = sta2.top(); sta2.pop();
            return ans;
        }
        
        /** Get the front element. */
        int peek() {
            mv();
            return sta2.top();
        }
        
        /** Returns whether the queue is empty. */
        bool empty() {
            return sta1.empty() && sta2.empty();
        }
    };
    
    

    9.4

    剑指 Offer 22. 链表中倒数第k个节点

    // go
    func getKthFromEnd(head *ListNode, k int) *ListNode {
        n := 0
        temp := head
        for temp != nil {
            n++
            temp = temp.Next
        }
        temp = head
        x := n - k + 1
        n = 0
        var ans *ListNode
        for temp != nil {
            n++
            if n == x {
                ans = temp
                break
            }
            temp = temp.Next
        }
        return ans
    }
    

    9.7

    51. N 皇后

    • 回溯
    // go
    func solveNQueens(n int) [][]string {
        ans := [][]string{}
        col := make(map[int]int)
        mp1 := make(map[int]int)
        mp2 := make(map[int]int)
        var dfs func(step, n int, temp []string)
        dfs = func(step, n int, temp []string) {
            if step == n {
                ans = append(ans, append([]string{}, temp...))
                return
            }
            row := make([]byte, n)
            for i := 0; i < n; i++ {
                row[i] = '.'
            }
            for i := 0; i < n; i++ {
                if (col[i] == 0 && mp1[i + step] == 0 && mp2[i - step] == 0) {
                    col[i], mp1[i + step], mp2[i - step] = 1, 1, 1
                    row[i] = 'Q'
                    temp = append(temp, string(row))
                    dfs(step + 1, n, temp)
                    col[i], mp1[i + step], mp2[i - step] = 0, 0, 0
                    row[i] = '.'
                    temp = temp[:len(temp) - 1]
                }
            }
        }
        dfs(0, n, []string{})
        return ans
    }
    

    62. 不同路径

    • dp
    // go
    func uniquePaths(m int, n int) int {
        dp := make([][]int, m)
        for i := 0; i < m; i++ {
            dp[i] = make([]int, n)
        }
        dp[0][0] = 1
        for i := 0; i < m; i++ {
            for j := 0; j < n; j++ {
                if i - 1 >= 0 {
                    dp[i][j] += dp[i - 1][j]
                }
                if j - 1 >= 0 {
                    dp[i][j] += dp[i][j - 1]
                }
            }
        }
        return dp[m - 1][n - 1]
    }
    

    剑指 Offer 09. 用两个栈实现队列

    • 参考上面一样的题目
    // cpp
    class CQueue {
    public:
        stack<int> s1, s2;
        CQueue() {
        }
        
        void appendTail(int value) {
            s1.push(value);
        }
        
        int deleteHead() {
            if (s2.empty()) {
                while (!s1.empty()) s2.push(s1.top()), s1.pop();
            }
            if (s2.empty()) return -1;
            else {
                int x = s2.top(); s2.pop();
                return x;
            }
        }
    };
    

    9.8

    64. 最小路径和

    • 二维动态规划
    // go
    func minPathSum(grid [][]int) int {
        m := len(grid)
        n := len(grid[0])
        dp := make([][]int, m)
        for i := 0; i < m; i++ {
            dp[i] = make([]int, n)
        }
        dp[0][0] = grid[0][0]
        for i := 0; i < m; i++ {
            for j := 0; j < n; j++ {
                if i - 1 >= 0 {
                    dp[i][j] = min(dp[i][j], dp[i - 1][j] + grid[i][j])
                }
                if j - 1 >= 0 {
                    dp[i][j] = min(dp[i][j], dp[i][j - 1] + grid[i][j])
                }
            }
        }
        return dp[m - 1][n - 1]
    }
    
    func min(a, b int) int {
        if a < b {
            return a
        } else {
            return b
        }
    }
    

    72. 编辑距离

    • 字符串下标从 (1) 开始
    • 定义 (dp[i][j]) 表示 (w_1, w_2)(i, j) 个位置,即 w1[1:i], w2[1:i] 的距离,从而进行转移
    #define inf 0x3f3f3f3f
    class Solution {
    public:
        int minDistance(string w1, string w2) {
            if (w1 == "" && w2 == "") return 0;
            else if (w1 == "") return w2.length();
            else if (w2 == "") return w1.length();
            int m = w1.length(), n = w2.length();
            int dp[m + 1][n + 1];
            memset(dp, inf, sizeof(dp));
            for (int i = 0; i <= m; ++i) dp[i][0] = i;
            for (int j = 0; j <= n; ++j) dp[0][j] = j;
            dp[1][1] = (w1[0] != w2[0]);
            for (int i = 1; i <= m; ++i) {
                for (int j = 1; j <= n; ++j) {
                    dp[i][j] = min(dp[i - 1][j - 1] + (w1[i - 1] != w2[j - 1]), min(dp[i - 1][j] + 1, dp[i][j - 1] + 1));
                }
            }
            return dp[m][n];
        }
    };
    

    78. 子集

    • 二进制枚举
    // cpp
    class Solution {
    public:
        vector<vector<int>> subsets(vector<int>& nums) {
            int n = nums.size();
            int N = 1 << n;
            vector<vector<int>> ans;
            for (int i = 0; i < N; ++i) {
                vector<int> temp;
                for (int j = 0; j < n; ++j) {
                    if (i & (1 << j)) temp.push_back(nums[j]);
                }
                ans.push_back(temp);
            }
            return ans;
        }
    };
    
    // go
    func subsets(nums []int) [][]int {
        n := len(nums)
        N := 1 << n
        ans := [][]int{}
        for i := 0; i < N; i++ {
            temp := []int{}
            for j := 0; j < n; j++ {
                if ((i >> j) & 1) == 1 {
                    temp = append(temp, nums[j])
                }
            }
            ans = append(ans, temp)
        }
        return ans
    }
    

    9.9

    79. 单词搜索

    • dfs
    // go
    func exist(board [][]byte, word string) bool {
        DX := []int{1, 0, -1, 0}
        DY := []int{0, -1, 0, 1}
        m, n := len(board), len(board[0])
        vis := make([][]bool, m)
        for i := 0; i < m; i++ {
            vis[i] = make([]bool, n)
        }
        var dfs func(x, y, step int) bool
        dfs = func(x, y, step int) bool {
            if word[step] != board[x][y] {
                return false
            }
            if step == len(word) - 1 {
                return true
            }
            for i := 0; i < 4; i++ {
                tx, ty := x + DX[i], y + DY[i]
                if tx >= 0 && tx < m && ty >= 0 && ty < n && !vis[tx][ty] {
                    vis[tx][ty] = true
                    if dfs(tx, ty, step + 1) {
                        return true
                    }
                    vis[tx][ty] = false
                }
            }
            return false
        }
        for i := 0; i < m; i++ {
            for j := 0; j < n; j++ {
                vis[i][j] = true
                if dfs(i, j, 0) {
                    return true
                }
                vis[i][j] = false
            }
        }
        return false
    }
    

    83. 删除排序链表中的重复元素

    • 设置一个 dummy
    • 维护两个指针,分别指向前一个元素和当前元素
    • 若当前元素和前一个元素相同,则删掉当前元素
    // go
    func deleteDuplicates(head *ListNode) *ListNode {
        pre := &ListNode {
            Val: -101,
            Next: head,
        }
        prev := pre
        for head != nil {
            if head.Val == prev.Val {
                prev.Next = head.Next
            } else {
                prev = prev.Next
            }
            head = head.Next
        }
        return pre.Next
    }
    

    82. 删除排序链表中的重复元素 II

    • 设置两个 dummy
    • 维护三个指针
    // go
    func deleteDuplicates(head *ListNode) *ListNode {
        b := &ListNode {
            Val: -101,
            Next: head,
        }
        a := &ListNode {
            Val: -102,
            Next: b,
        }
        p1, p2 := a, b
        for head != nil {
            if head.Val == p2.Val {
                for head != nil && head.Val == p2.Val {
                    p2.Next = head.Next
                    head = head.Next
                }
                p1.Next = head
                p2 = head
                if head == nil {
                    break
                }
                head = head.Next
            } else {
                p1 = p1.Next
                p2 = p2.Next
                head = head.Next
            }
        }
        return b.Next
    }
    

    9.10

    104. 二叉树的最大深度

    • dfs
    // go
    func maxDepth(root *TreeNode) int {
        var dfs func(root *TreeNode) int
        dfs = func(root *TreeNode) int {
            if root == nil {
                return 0
            }
            return 1 + max(dfs(root.Left), dfs(root.Right))
        }
        return dfs(root)
    }
    func max(a, b int) int {
        if a < b {
            return b
        } else {
            return a
        }
    }
    

    110. 平衡二叉树

    • 记录一下左右子树的高度差即可
    • 如果要判断是不是 BBST,需要记录 dfs 序,然后判断是否有序
    // go
    func isBalanced(root *TreeNode) bool {
        var dfs func(root *TreeNode) (int, bool)
        dfs = func(root *TreeNode) (int, bool) {
            if root == nil {
                return 0, true
            }
            h1, f1 := dfs(root.Left)
            h2, f2 := dfs(root.Right)
            if f1 && f2 && abs(h1 - h2) <= 1 {
                return max(h1, h2) + 1, true
            }
            return max(h1, h2) + 1, false
        }
        _, f := dfs(root)
        return f
    }
    
    func max(a, b int) int {
        if a < b {
            return b
        } else {
            return a
        }
    }
    
    func abs(a int) int {
        if a < 0 {
            return -a
        } else {
            return a
        }
    }
    

    9.11

    114. 二叉树展开为链表

    • 考虑递归
    • 将左子树展开成链表,挂在根的右节点上
    • 再把右子树展开成链表,挂在左子树的末尾的右节点上
    // go
    func flatten(root *TreeNode)  {
        var dfs func(root *TreeNode)
        dfs = func(root *TreeNode) {
            if root == nil {
                return
            }
            dfs(root.Left)
            dfs(root.Right)
            temp := root.Right
            root.Left, root.Right = nil, root.Left
            cur := root
            for cur.Right != nil {
                cur = cur.Right
            }
            cur.Right = temp
        }
        dfs(root)
    }
    

    122. 买卖股票的最佳时机 II

    • 线性 dp,每一天的状态只和前一天有关
    // cpp
    class Solution {
    public:
        int maxProfit(vector<int>& p) {
            int n = p.size();
            int dp[n + 1][2];
            dp[0][0] = 0, dp[0][1] = -p[0];
            int ans = 0;
            for (int i = 1; i < n; ++i) {
                dp[i][0] = max(dp[i - 1][1] + p[i], dp[i - 1][0]);
                dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - p[i]);
            }
            return dp[n - 1][0];
        }
    };
    
    

    139. 单词拆分

    • 定义 (dp[i]) 表示前 (i) 个字符组成的字符串能否由字典拼凑而成
    • 枚举 (j),判断 (j..i) 是否在字典里即可
    // go
    func wordBreak(s string, wordDict []string) bool {
        dp := make([]bool, len(s) + 1)
        mp := make(map[string]bool)
        for _, v := range(wordDict) {
            mp[v] = true
        }
        dp[0] = true
        for i := 1; i <= len(s); i++ {
            for j := 0; j < i; j++ {
                if dp[j] && mp[s[j:i]] {
                    dp[i] = true
                }
            }
        }
        return dp[len(s)]
    }
    

    9.12

    144. 二叉树的前序遍历

    • 前序遍历
    // go
    func preorderTraversal(root *TreeNode) []int {
        ans := []int{}
        var dfs func(root *TreeNode)
        dfs = func(root *TreeNode) {
            if root == nil {
                return
            }
            ans = append(ans, root.Val)
            dfs(root.Left)
            dfs(root.Right)
        }
        dfs(root)
        return ans
    }
    

    148. 排序链表

    • multiset 维护
    // go
    class Solution {
    public:
        ListNode* sortList(ListNode* head) {
            multiset<int> st;
            while (head) st.insert(head->val), head = head->next;
            ListNode *pre = new ListNode(0);
            ListNode *cur = pre;
            for (auto &i: st) cur->next = new ListNode(i), cur = cur->next;
            return pre->next;
        }
    };
    

    9.14

    198. 打家劫舍

    • 动态规划,当前状态与前一天和大前天的状态有关
    // go
    func rob(nums []int) int {
        dp := make([]int, len(nums))
        dp[0] = nums[0]
        for i := 1; i < len(nums); i++ {
            if i == 1 {
                dp[i] = max(dp[i - 1], nums[i]);
            } else {
                dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]);
            }
        }
        return dp[len(nums) - 1];
    }
    
    func max(a, b int) int {
        if a < b {
            return b
        } else {
            return a
        }
    }
    

    209. 长度最小的子数组

    • 滑动窗口 (O(n)) 算法
    // cpp
    class Solution {
    public:
        int minSubArrayLen(int target, vector<int>& a) {
            int l = 0, r = 0, n = a.size(), ans = INT_MAX, sum = 0;
            while (r < n) {
                sum += a[r];
                while (l <= r && sum >= target) {
                    ans = min(ans, r - l + 1);
                    sum -= a[l++];
                }
                r++;
            }
            return ans == INT_MAX ? 0 : ans;
        }
    };
    
    • 维护前缀和,在前缀和上二分
    • 对于当前位置 (i),找到第一个大于等于 s[i - 1] + target 的位置,维护答案
    // cpp
    class Solution {
    public:
        int minSubArrayLen(int target, vector<int>& a) {
            int n = a.size(), ans = INT_MAX, sum = 0;
            int s[n + 1];
            for (int i = 1; i <= n; ++i)
                s[i] = s[i - 1] + a[i - 1];
            for (int i = 1; i <= n; ++i) {
                int temp = s[i - 1] + target;
                int r = lower_bound(s + i, s + 1 + n, temp) - s;
                if (r <= n) ans = min(ans, r - i + 1);
            }
            return ans == INT_MAX ? 0 : ans;
        }
    };
    

    221. 最大正方形

    • 定义 dp[i][j] 表示以 (i, j) 为右下角的全 1 正方形的最大边长
    • 考虑由 dp[i][j - 1], dp[i - 1][j], dp[i - 1][j - 1] 转移而来
    • 画图有助于理解
    // cpp
    class Solution {
    public:
        int maximalSquare(vector<vector<char>>& a) {
            int m = a.size(), n = a[0].size();
            vector<vector<int>> dp(m, vector<int>(n));
            int ans = 0;
            for (int i = 0; i < m; ++i) {
                for (int j = 0; j < n; ++j) {
                    if (a[i][j] == '0') dp[i][j] = 0;
                    else {
                        if (i >= 1 && j >= 1) {
                            dp[i][j] = min(dp[i - 1][j - 1], min(dp[i - 1][j], dp[i][j - 1])) + 1;
                        }
                        else dp[i][j] = 1;
                    }
                    ans = max(ans, dp[i][j]);
                }
            }
            return ans * ans;
        }
    };
    
  • 相关阅读:
    redhat 6.4下PXE+Kickstart无人值守安装操作系统
    ubuntu14.04安装好Hadoo之后接着安装hbase和介绍常用命令
    避坑之Hadoop安装伪分布式(Hadoop3.2.0/Ubuntu14.04 64位)
    kindeditor文件上传设置文件说明为上传文件名(JSP版)
    sqlmap 扫描注入漏洞
    局域网内访问不同网段的主机(转记)
    cmd创建用户开启3389命令
    用python来更改windows开机密码
    代码安全之上传文件
    web渗透(转)
  • 原文地址:https://www.cnblogs.com/ChenyangXu/p/15237539.html
Copyright © 2011-2022 走看看