LeetCode-4

LeetCode-4

继续窜稀释刷题

237 删除链表中的节点

刷题时间:2021-11-02

这题我是真的没有想到,居然这么简单。

大意了,居然还有优化的空间,要删除原来的空间,尿了。

class Solution {
   public:
    void deleteNode(ListNode* node) {
        node->val = node->next->val;
        ListNode* next = node->next;
        node->next = node->next->next;
        delete (next);
    }
};

141 环形链表

刷题时间:2021-11-02

空间O(n)

class Solution {
   public:
    bool hasCycle(ListNode* head) {
        ListNode* ptr = head;
        unordered_set<ListNode*> set;
        while (ptr != nullptr) {
            if (set.count(ptr)) {
                return true;
            }
            set.insert(ptr);
            ptr = ptr->next;
        }
        return false;
    }
};

进阶,自己想的方法,空间O(1),而且时间也很快。

class Solution {
   public:
    bool hasCycle(ListNode* head) {
        ListNode* ptr = head;

        while (ptr != nullptr) {
            if (ptr->val == 1000000) {
                return true;
            }
            ptr->val = 1000000;
            ptr = ptr->next;
        }
        return false;
    }
};

官方的O(1)是快慢指针,时间居然和我上面的持平了,空间居然用的还更少,牛牛牛。

快慢指针如果有环的,迟早会追上的。

class Solution {
public:
    bool hasCycle(ListNode* head) {
        if (head == nullptr || head->next == nullptr) {
            return false;
        }
        ListNode* slow = head;
        ListNode* fast = head->next;
        while (slow != fast) {
            if (fast == nullptr || fast->next == nullptr) {
                return false;
            }
            slow = slow->next;
            fast = fast->next->next;
        }
        return true;
    }
};

21 合并两个有序链表

一般般的写法,迭代法

class Solution {
   public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* l3 = new ListNode(-1);
        ListNode* res = l3;
        while (l1 != nullptr && l2 != nullptr) {
            if (l1->val > l2->val) {
                l3->next = l2;
                l2 = l2->next;
            } else {
                l3->next = l1;
                l1 = l1->next;
            }
            l3 = l3->next;
        }
        // if (l1 != nullptr) {
        //     l3->next = l1;
        // }
        // if (l2 != nullptr) {
        //     l3->next = l2;
        // }
        // 或者直接精简成下面这种写法
        l3->next = l1 == nullptr ? l2 : l1;

        return res->next;
    }
};

居然还有递归法,这我是没想到的,我靠,这个还快一点

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if (l1 == nullptr) {
            return l2;
        } else if (l2 == nullptr) {
            return l1;
        } else if (l1->val < l2->val) {
            l1->next = mergeTwoLists(l1->next, l2);
            return l1;
        } else {
            l2->next = mergeTwoLists(l1, l2->next);
            return l2;
        }
    }
};

203 移除链表元素

简单

class Solution {
   public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* prev = new ListNode(-1);
        prev->next = head;
        ListNode* cur = prev;
        while (cur != nullptr && cur->next != nullptr) {
            if (cur->next->val == val) {
                cur->next = cur->next->next;
            } else {
                cur = cur->next;
            }
        }
        return prev->next;
    }
};

为什么老是有递归????舒服了,这次事件相同,内存消耗还大一点。

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        if (head == nullptr) {
            return head;
        }
        head->next = removeElements(head->next, val);
        return head->val == val ? head->next : head;
    }
};

js版本

var removeElements = function (head, val) {
    const prev = new ListNode(-1, head);
    let cur = prev;
    while (cur != null && cur.next != null) {
        if (cur.next.val == val) {
            cur.next = cur.next.next;
        } else {
            cur = cur.next;
        }
    }
    return prev.next;
};

617 合并二叉树

没想到出来,我遇到二叉树就喜欢迭代,但二叉树最简单的方式还是递归,可惜了。

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        if (t1 == nullptr) {
            return t2;
        }
        if (t2 == nullptr) {
            return t1;
        }
        auto merged = new TreeNode(t1->val + t2->val);
        merged->left = mergeTrees(t1->left, t2->left);
        merged->right = mergeTrees(t1->right, t2->right);
        return merged;
    }
};

广度优先搜索的就不写了,太长太臭了。

116 填充每个节点的下一个右侧节点指针

我直接抄袭以前抄袭的代码,多重抄袭术

class Solution {
	public:
		Node* connect(Node* root) {
			if (!root) return nullptr;
			if(root->left==nullptr&&root->right==nullptr) {
				return root;
			}
			if (root->left)
				root->left->next = root->right;
			if(root->next)
				root->right->next=root->next->left;
			connect(root->left);
			connect(root->right);
			return root;
		}
};

更喜欢迭代法,符合题意

class Solution {
   public:
    Node* connect(Node* root) {
        if (root == nullptr) {
            return root;
        }
        queue<Node*> Q;
        Q.push(root);
        while (!Q.empty()) {
            int size = Q.size();
            for (int i = 0; i < size; i++) {
                Node* node = Q.front();
                Q.pop();
                if (i < size - 1) {
                    node->next = Q.front();
                }
                if (node->left != nullptr) {
                    Q.push(node->left);
                }
                if (node->right != nullptr) {
                    Q.push(node->right);
                }
            }
        }
        return root;
    }
};

js版本迭代,舒服了

var connect = function (root) {
    if (!root) return null;
    const que = [];
    que.push(root);
    while (que.length) {
        const length = que.length;
        let tmp = que.shift();
        if (tmp.left) que.push(tmp.left);
        if (tmp.right) que.push(tmp.right);
        for (let i = 1; i < length; i++) {
            let tmp2 = que.shift();
            tmp.next = tmp2;
            tmp = tmp2;
            if (tmp.left) que.push(tmp.left);
            if (tmp.right) que.push(tmp.right);
        }
    }
    return root;
};

206 反转链表

刷题时间:2021-11-03

就这个方法最简单了,非常的不错。迭代简单

class Solution {
   public:
    ListNode* reverseList(ListNode* head) {
        ListNode* prev = nullptr;
        ListNode* curr = head;
        while (curr) {
            ListNode* next = curr->next;
            curr->next = prev;
            prev = curr;
            curr = next;
        }
        return prev;
    }
};

还有递归的方法

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if (!head || !head->next) {
            return head;
        }
        ListNode* newHead = reverseList(head->next);
        head->next->next = head;
        head->next = nullptr;
        return newHead;
    }
};

js版本

var reverseList = function (head) {
    let prev = null;
    let curr = head;
    while (curr) {
        let next = curr.next;
        curr.next = prev;
        prev = curr;
        curr = next;
    }
    return prev;
};

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

刷题时间:2021-11-03

简单好吧

class Solution {
   public:
    ListNode* deleteDuplicates(ListNode* head) {
        if (!head) {
            return head;
        }
        ListNode* cur = head;
        while (cur->next) {
            if (cur->next->val == cur->val) {
                ListNode* tmp = cur->next;
                cur->next = cur->next->next;
                delete tmp;
            } else {
                cur = cur->next;
            }
        }
        return head;
    }
};

542 01 矩阵

烦死了,难得想用深度优先来写,居然不行,行不通,我真的草了,只能用广度优先。

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

   public:
    vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
        int m = matrix.size(), n = matrix[0].size();
        vector<vector<int>> dist(m, vector<int>(n));
        vector<vector<int>> seen(m, vector<int>(n));
        queue<pair<int, int>> q;
        // 将所有的 0 添加进初始队列中
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (matrix[i][j] == 0) {
                    q.emplace(i, j);
                    seen[i][j] = 1;
                }
            }
        }

        // 广度优先搜索
        while (!q.empty()) {
            auto [i, j] = q.front();
            q.pop();
            for (int d = 0; d < 4; ++d) {
                int ni = i + dirs[d][0];
                int nj = j + dirs[d][1];
                if (ni >= 0 && ni < m && nj >= 0 && nj < n && !seen[ni][nj]) {
                    dist[ni][nj] = dist[i][j] + 1;
                    q.emplace(ni, nj);
                    seen[ni][nj] = 1;
                }
            }
        }

        return dist;
    }
};

还有个动态规划,不看了,这个比较难。

994 腐烂的橘子

艹,没想到情况这么多,利用上一道题的写法。

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

   public:
    int orangesRotting(vector<vector<int>>& grid) {
        int m = grid.size();
        int n = grid[0].size();
        vector<vector<int>> dist(m, vector<int>(n));
        queue<pair<int, int>> q;
        int t1 = 0, t2 = 0, t3 = 0;
        // 将所有的 0 添加进初始队列中
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == 2) {
                    q.emplace(i, j);
                    t1++;
                } else if (grid[i][j] == 1) {
                    t3++;
                }
            }
        }

        if (t1 == 0) {
            if (t3) {
                return -1;
            }
            return 0;
        }
        int res = 0;
        while (!q.empty()) {
            auto [i, j] = q.front();
            q.pop();
            t1--;
            for (int d = 0; d < 4; ++d) {
                int ni = i + dirs[d][0];
                int nj = j + dirs[d][1];
                if (ni >= 0 && ni < m && nj >= 0 && nj < n &&
                    grid[ni][nj] == 1) {
                    grid[ni][nj] = 2;
                    q.emplace(ni, nj);
                    t2++;
                }
            }
            if (t1 == 0) {
                res++;
                t1 = t2;
                t2 = 0;
            }
        }
        for (int a = 0; a < m; a++) {
            for (int b = 0; b < n; b++) {
                if (grid[a][b] == 1) {
                    return -1;
                }
            }
        }
        return res - 1;
    }
};

找了一个优化我的算法的,我给忘了queue也能取size了。

class Solution {
public:
    int orangesRotting(vector<vector<int>>& grid) {
        int row = grid.size();
        int col = grid[0].size();
        queue<pair<int,int>> rot;
        vector<int> dx = {0,0,-1,1};
        vector<int> dy = {1,-1,0,0};
        int min = 0;
        for(int i = 0;i < row;i++){
            for(int j = 0;j < col;j++){
                if(grid[i][j] == 2){
                    rot.push({i,j});
                }
            }
        }
        while(!rot.empty()){
            int num = rot.size();
            for(int n = 0;n < num;n ++){
                pair<int,int> fir = rot.front();
                rot.pop();
                for(int i = 0;i < 4;i++){
                int tmp_x = fir.first + dx[i];
                int tmp_y = fir.second + dy[i];
                if(tmp_x>=0&&tmp_x<row&&tmp_y>=0&&tmp_y<col&&grid[tmp_x][tmp_y]==1){
                    grid[tmp_x][tmp_y] = 2;
                    rot.push({tmp_x,tmp_y});
                    }
                }
            }
            if(!rot.empty())
            min++;
        }
        for(int i = 0;i < row;i++){
            for(int j = 0;j < col;j++){
                if(grid[i][j] == 1){
                    return -1;
                }
            }
        }
        return min;
    }
};

42 接雨水

日,暴力法,一定要记住暴力法先。最耻辱的事情就是连暴力法都不会。可惜超时了,过不了。

class Solution {
   public:
    int trap(vector<int>& height) {
        int ans = 0;
        int size = height.size();
        for (int i = 1; i < size - 1; i++) {
            int max_left = 0, max_right = 0;
            for (int j = i; j >= 0; j--) {
                max_left = max(max_left, height[j]);
            }
            for (int j = i; j < size; j++) {
                max_right = max(max_right, height[j]);
            }
            ans += min(max_left, max_right) - height[i];
        }
        return ans;
    }
};

动态规划法,这个挺好理解,先遍历一遍,存储每个点左边和右边。这个方法也一定要记住!!

class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        if (n == 0) {
            return 0;
        }
        vector<int> leftMax(n);
        leftMax[0] = height[0];
        for (int i = 1; i < n; ++i) {
            leftMax[i] = max(leftMax[i - 1], height[i]);
        }

        vector<int> rightMax(n);
        rightMax[n - 1] = height[n - 1];
        for (int i = n - 2; i >= 0; --i) {
            rightMax[i] = max(rightMax[i + 1], height[i]);
        }

        int ans = 0;
        for (int i = 0; i < n; ++i) {
            ans += min(leftMax[i], rightMax[i]) - height[i];
        }
        return ans;
    }
};

双指针 妙蛙种子都没这么妙好吧

如果左边比右边小,那么说明只能会被左边所限制,那么就去找左边的最大值。

class Solution {
public:
    int trap(vector<int>& height) {
        int ans = 0;
        int left = 0, right = height.size() - 1;
        int leftMax = 0, rightMax = 0;
        while (left < right) {
            leftMax = max(leftMax, height[left]);
            rightMax = max(rightMax, height[right]);
            if (height[left] < height[right]) {
                ans += leftMax - height[left];
                ++left;
            } else {
                ans += rightMax - height[right];
                --right;
            }
        }
        return ans;
    }
};

407 接雨水 II

https://www.cnblogs.com/grandyang/p/5928987.html

大概能看得懂,但是我自己写肯定写不出来,优先队列就不会。

class Solution {
   public:
    int trapRainWater(vector<vector<int>>& heightMap) {
        if (heightMap.empty()) return 0;
        int m = heightMap.size(), n = heightMap[0].size(), res = 0,
            mx = INT_MIN;
        // 最小堆
        priority_queue<pair<int, int>, vector<pair<int, int>>,
                       greater<pair<int, int>>> q;
        vector<vector<bool>> visited(m, vector<bool>(n, false));
        vector<vector<int>> dir{{0, -1}, {-1, 0}, {0, 1}, {1, 0}};
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (i == 0 || i == m - 1 || j == 0 || j == n - 1) {
                    q.push({heightMap[i][j], i * n + j});
                    visited[i][j] = true;
                }
            }
        }
        while (!q.empty()) {
            auto t = q.top();
            q.pop();
            int h = t.first, r = t.second / n, c = t.second % n;
            // 最低的海平面
            mx = max(mx, h);
            for (int i = 0; i < dir.size(); ++i) {
                int x = r + dir[i][0], y = c + dir[i][1];
                if (x < 0 || x >= m || y < 0 || y >= n || visited[x][y])
                    continue;
                visited[x][y] = true;
                if (heightMap[x][y] < mx) res += mx - heightMap[x][y];
                q.push({heightMap[x][y], x * n + y});
            }
        }
        return res;
    }
};

367 有效的完全平方数

刷题时间:2021-11-04

最朴实无法的做法

class Solution {
   public:
    bool isPerfectSquare(int num) {
        int n = sqrt(num);
        return n * n == num;
    }
};

暴力法和二分法不说了。还有个牛顿迭代法

class Solution {
public:
    bool isPerfectSquare(int num) {
        double x0 = num;
        while (true) {
            double x1 = (x0 + num / x0) / 2;
            if (x0 - x1 < 1e-6) {
                break;
            }
            x0 = x1;
        }
        int x = (int) x0;
        return x * x == num;
    }
};

20 有效的括号

一次性过,空间和时间都拉满。

class Solution {
   public:
    bool isValid(string s) {
        stack<char> sta;
        for (char ch : s) {
            if (ch == '(' || ch == '[' || ch == '{') {
                sta.push(ch);
            } else {
                if (sta.empty()) {
                    return false;
                } else {
                    char tmp = sta.top();
                    switch (ch) {
                        case ')':
                            if (tmp == '(') {
                                sta.pop();
                            } else {
                                return false;
                            }
                            break;
                        case ']':
                            if (tmp == '[') {
                                sta.pop();
                            } else {
                                return false;
                            }
                            break;
                        case '}':
                            if (tmp == '{') {
                                sta.pop();
                            } else {
                                return false;
                            }
                            break;
                        default:
                            break;
                    }
                }
            }
        }
        if (sta.empty()) {
            return true;
        }
        return false;
    }
};

js版本,小技巧,如果左括号匹配,那么就添加右括号,这样子就不用再去匹配了,牛逼方法。

var isValid = function (s) {
    let st = [];
    for (let ch of s) {
        if (ch == '(') st.push(')');
        else if (ch == '[') st.push(']');
        else if (ch == '{') st.push('}');
        else if (st.length == 0 || st[st.length - 1] != ch) return false;
        else st.pop();
    }
    return st.length == 0;
};

232 用栈实现队列

这个均摊的思想很棒啊,每次出摊的时候,才将in的传到out里面,有货的话直接用,没货的话拉一批货。

class MyQueue {
   private:
    stack<int> inStack, outStack;

    void in2out() {
        while (!inStack.empty()) {
            outStack.push(inStack.top());
            inStack.pop();
        }
    }

   public:
    MyQueue() {}

    void push(int x) { inStack.push(x); }

    int pop() {
        if (outStack.empty()) {
            in2out();
        }
        int x = outStack.top();
        outStack.pop();
        return x;
    }

    int peek() {
        if (outStack.empty()) {
            in2out();
        }
        return outStack.top();
    }

    bool empty() { return inStack.empty() && outStack.empty(); }
};

js版本

var MyQueue = function () {
    this.inStack = [];
    this.outStack = [];
};

/**
 * @param {number} x
 * @return {void}
 */
MyQueue.prototype.push = function (x) {
    this.inStack.push(x);
};

/**
 * @return {number}
 */
MyQueue.prototype.pop = function () {
    if (this.outStack.length == 0) {
        while (this.inStack.length != 0) {
            this.outStack.push(this.inStack.pop());
        }
    }
    return this.outStack.pop();
};

/**
 * @return {number}
 */
MyQueue.prototype.peek = function () {
    if (this.outStack.length == 0) {
        while (this.inStack.length != 0) {
            this.outStack.push(this.inStack.pop());
        }
    }
    return this.outStack[this.outStack.length - 1];
};

/**
 * @return {boolean}
 */
MyQueue.prototype.empty = function () {
    return this.inStack.length == 0 && this.outStack.length == 0;
};

1218 最长定差子序列

刷题时间:2021-11-05

动态规划,算是比较简单的一道动态规划。

class Solution {
   public:
    int longestSubsequence(vector<int> &arr, int difference) {
        int ans = 0;
        int dp[40001]{0};
        for (int num : arr) {
            dp[num + 20000] = dp[num + 20000 - difference] + 1;
            ans = max(ans, dp[num + 20000]);
        }
        return ans;
    }
};

144 二叉树的前序遍历

递归,自己写的,空间有点拉,因为老是返回一个vector

class Solution {
   public:
    vector<int> res;
    vector<int> preorderTraversal(TreeNode *root) {
        if (root) {
            res.push_back(root->val);
            preorderTraversal(root->left);
            preorderTraversal(root->right);
        }
        return res;
    }
};

还是推崇下面这个递归

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

    vector<int> preorderTraversal(TreeNode *root) {
        vector<int> res;
        preorder(root, res);
        return res;
    }
};

迭代的方法,非自己写的,之后可能要自己写一遍

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> res;
        if (root == nullptr) {
            return res;
        }

        stack<TreeNode*> stk;
        TreeNode* node = root;
        while (!stk.empty() || node != nullptr) {
            while (node != nullptr) {
                res.emplace_back(node->val);
                stk.emplace(node);
                node = node->left;
            }
            node = stk.top();
            stk.pop();
            node = node->right;
        }
        return res;
    }
};

Morris遍历

参考:https://zhuanlan.zhihu.com/p/101321696

其实没什么道理,就是硬记

class Solution {
   public:
    vector<int> preorderTraversal(TreeNode *root) {
        vector<int> res;
        if (!root) {
            return res;
        }
        TreeNode *p1 = root, *p2 = nullptr;
        while (p1) {
            p2 = p1->left;
            if (p2) {
                while (p2->right && p2->right != p1) {
                    p2 = p2->right;
                }
                if (!p2->right) {
                    res.emplace_back(p1->val);
                    p2->right = p1;
                    p1 = p1->left;
                } else {
                    p2->right = nullptr;
                    p1 = p1->right;
                }
            } else {
                res.emplace_back(p1->val);
                p1 = p1->right;
            }
        }
        return res;
    }
};

js递归

var preorderTraversal = function (root) {
    const res = [];
    const dfs = (node) => {
        if (node === null) return;
        res.push(node.val);
        dfs(node.left);
        dfs(node.right);
    };
    dfs(root);
    return res;
};

js迭代,压栈的顺序先右再左,因为左边的先出来。

var preorderTraversal = function (root) {
    const res = [];
    if (root == null) return [];
    const stk = [];
    stk.push(root);
    while (stk.length != 0) {
        let tmp = stk.pop();
        res.push(tmp.val);
        if (tmp.right) stk.push(tmp.right);
        if (tmp.left) stk.push(tmp.left);
    }
    return res;
};

94 二叉树的中序遍历

递归

class Solution {
   public:
    void inorder(TreeNode *root, vector<int> &res) {
        if (!root) {
            return;
        }
        inorder(root->left, res);
        res.emplace_back(root->val);
        inorder(root->right, res);
    }
    vector<int> inorderTraversal(TreeNode *root) {
        vector<int> res;
        inorder(root, res);
        return res;
    }
};

迭代

class Solution {
   public:
    vector<int> inorderTraversal(TreeNode *root) {
        vector<int> res;
        if (!root) {
            return res;
        }
        stack<TreeNode *> stk;

        TreeNode *node = root;
        while (!stk.empty() || node) {
            while (node) {
                stk.emplace(node);
                node = node->left;
            }
            node = stk.top();
            res.emplace_back(node->val);
            stk.pop();
            node = node->right;
        }
        return res;
    }
};

Morris

class Solution {
   public:
    vector<int> inorderTraversal(TreeNode *root) {
        vector<int> res;
        if (!root) {
            return res;
        }
        TreeNode *p1 = root, *p2 = nullptr;
        while (p1) {
            p2 = p1->left;
            if (p2) {
                while (p2->right && p2->right != p1) {
                    p2 = p2->right;
                }
                if (!p2->right) {
                    p2->right = p1;
                    p1 = p1->left;
                } else {
                    res.emplace_back(p1->val);
                    p2->right = nullptr;
                    p1 = p1->right;
                }
            } else {
                res.emplace_back(p1->val);
                p1 = p1->right;
            }
        }
        return res;
    }
};

js递归

 var inorderTraversal = function(root) {
    const res = [];
    const dfs = (node) => {
        if (node === null) return;
        dfs(node.left);
        res.push(node.val);
        dfs(node.right);
    };
    dfs(root);
    return res;
};

js迭代

var inorderTraversal = function (root) {
    const res = [];
    if (root == null) return [];
    const stk = [];
    while (stk.length != 0 || root) {
        while (root) {
            stk.push(root);
            root = root.left;
        }
        let tmp = stk.pop();
        res.push(tmp.val);
        root = tmp.right;
    }
    return res;
};

145 二叉树的后序遍历

递归简单

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

    vector<int> postorderTraversal(TreeNode *root) {
        vector<int> res;
        postorder(root, res);
        return res;
    }
};

后序迭代需要复习,要不然弄不会。

class Solution {
   public:
    vector<int> postorderTraversal(TreeNode *root) {
        vector<int> res;
        if (!root) {
            return res;
        }
        stack<TreeNode *> stk;
        TreeNode *prev = nullptr;

        TreeNode *node = root;
        while (!stk.empty() || node) {
            while (node) {
                stk.emplace(node);
                node = node->left;
            }
            node = stk.top();
            stk.pop();
            if (node->right == nullptr || node->right == prev) {
                res.emplace_back(node->val);
                prev = node;
                node = nullptr;
            } else {
                stk.emplace(node);
                node = node->right;
            }
        }
        return res;
    }
};

这个Morris遍历方法硬背一下就行了,后序真的是最麻烦的

class Solution {
   public:
    void addPath(vector<int> &vec, TreeNode *node) {
        int count = 0;
        while (node != nullptr) {
            ++count;
            vec.emplace_back(node->val);
            node = node->right;
        }
        reverse(vec.end() - count, vec.end());
    }

    vector<int> postorderTraversal(TreeNode *root) {
        vector<int> res;
        if (!root) {
            return res;
        }
        TreeNode *p1 = root, *p2 = nullptr;
        while (p1) {
            p2 = p1->left;
            if (p2) {
                while (p2->right && p2->right != p1) {
                    p2 = p2->right;
                }
                if (!p2->right) {
                    p2->right = p1;
                    p1 = p1->left;
                } else {
                    p2->right = nullptr;
                    p1 = p1->right;
                }
            } else {
                p1 = p1->right;
            }
        }
        return res;
    }
};

js递归

var postorderTraversal = function (root) {
    const res = [];
    const dfs = (node) => {
        if (node === null) return;
        dfs(node.left);
        dfs(node.right);
        res.push(node.val);
    };
    dfs(root);
    return res;
};

js迭代,中右左,然后翻转,这种方法有点trick

var postorderTraversal = function (root) {
    const res = [];
    if (root == null) return [];
    const stk = [];
    stk.push(root);
    while (stk.length != 0) {
        let tmp = stk.pop();
        res.push(tmp.val);
        if (tmp.left) stk.push(tmp.left);
        if (tmp.right) stk.push(tmp.right);
    }
    return res.reverse();
};

正常思维的迭代,但还是非常的难以理解

var postorderTraversal = function (root) {
    const res = [];
    if (root == null) return [];
    const stk = [];
    let prev = null;
    while (stk.length != 0 || root) {
        // 1.遍历到最左子节点
        while (root) {
            stk.push(root);
            root = root.left;
        }
        root = stk.pop();
        // 2.遍历最左子节点的右子树(右子树存在 && 未访问过)
        if (root.right && root.right != prev) {
            // 重复压栈以记录当前路径分叉节点
            stk.push(root);
            root = root.right;
        } else {
            // 后序:填充vec在node->left和node->right后面
            // 注意:此时node的左右子树应均已完成访问
            res.push(root.val);
            // 避免重复访问右子树[记录当前节点便于下一步对比]
            prev = root;
            // 避免重复访问左子树[设空节点]
            root = nullptr;
        }
    }
    return res;
};

77 组合

这种题目的解法就是要有恢复和不恢复两种状态。这样子才能枚举完所有的。

class Solution {
   public:
    vector<int> res;
    vector<vector<int>> ans;
    vector<vector<int>> combine(int n, int k) {
        dfs(1, n, k);
        return ans;
    }
    void dfs(int cur, int n, int k) {
        if (res.size() + n - cur + 1 < k) {
            return;
        }
        if (res.size() == k) {
            ans.emplace_back(res);
            return;
        }
        res.emplace_back(cur);
        dfs(cur + 1, n, k);
        res.pop_back();
        dfs(cur + 1, n, k);
    }
};

字典法

784 字母大小写全排列

自己参考77组合的经验,不用for循环,那么就会有两个dfs来操作,一个变化前,一个变化后。

class Solution {
   public:
    vector<string> letterCasePermutation(string s) {
        vector<string> res;
        dfs(res, 0, s);
        return res;
    }
    void dfs(vector<string> &res, int i, string s) {
        if (i > s.length() - 1) {
            res.emplace_back(s);
            return;
        }
        dfs(res, i + 1, s);
        if (s[i] <= 'z' && s[i] >= 'a') {
            s[i] = s[i] + 'A' - 'a';
        } else if (s[i] <= 'Z' && s[i] >= 'A') {
            s[i] = s[i] - ('A' - 'a');
        } else {
            return;
        }
        dfs(res, i + 1, s);
    }
};

for循环的思想就是有点搞的。反正有点难想

class Solution {
   public:
    vector<string> letterCasePermutation(string s) {
        vector<string> res;
        dfs(res, 0, s);
        return res;
    }
    void dfs(vector<string> &res, int cur, string s) {
         for (int i = cur; i < s.length(); i++) {
            if (s[i] <= 'z' && s[i] >= 'a') {
                dfs(res, i + 1, s);
                s[i] = s[i] + 'A' - 'a';
            } else if (s[i] <= 'Z' && s[i] >= 'A') {
                dfs(res, i + 1, s);
                s[i] = s[i] - ('A' - 'a');
            }
        }
        res.emplace_back(s);
    }
};

迭代的思想,有点像二叉树的BFS的思路,批处理

class Solution {
   public:
    vector<string> letterCasePermutation(string s) {
        deque<string> res;
        res.emplace_back(s);
        for (int i = 0; i < s.length(); i++) {
            if (isdigit(s[i])) continue;
            for (int j = res.size(); j > 0; --j) {
                auto sub = res.front();
                res.pop_front();
                res.emplace_back(sub);
                sub[i] ^= (1 << 5);
                res.emplace_back(sub);
            }
        }
        return vector<string>(res.begin(), res.end());
    }
};

还有一种是掩码的方法,这里就不臊皮了。

这题的思路可以参考这题 https://leetcode-cn.com/problems/letter-case-permutation/solution/3chong-hui-su-jie-fa-by-fengziluo-oirf/

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇