Leetcode problem-solving ideas analysis (33) 235-241

  1. The nearest common ancestor
    of a binary search tree Given a binary search tree, find the nearest common ancestor of two specified nodes in the tree.

A very simple problem, recursive solution: for a binary search tree, left subtree<root<right subtree, it can be judged whether two nodes are located on two sides or the same side. If it is on both sides, the root is the nearest common ancestor, otherwise continue to search

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */

class Solution {
    
    
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    
    
        if (root->val == p->val || root->val == q->val)
        {
    
    
            return root;
        }
        if ((root->val > p->val && root->val < q->val)
        || (root->val < p->val && root->val > q->val))
        {
    
    
            return root;
        }

        if (root->val > p->val && root->val > q->val)
        {
    
    
            return lowestCommonAncestor(root->left, p, q);
        }
        else
        {
    
    
            return lowestCommonAncestor(root->right, p, q);
        }
    }
};
  1. The nearest common ancestor
    of a binary tree Given a binary tree, find the nearest common ancestor of two specified nodes in the tree.

This question is slightly more troublesome compared to the previous question, because there is no feature of a binary search tree. Therefore, when going to recursion, you need to start from the bottom. If it is satisfied that there is a node on the left subtree and the right subtree of a certain root, the root node is returned. Otherwise, one of the two nodes must be a common ancestor.

class Solution {
    
    
public:
    TreeNode* ans;
    bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) {
    
    
        if (root == nullptr) return false;
        bool lson = dfs(root->left, p, q);
        bool rson = dfs(root->right, p, q);
        if ((lson && rson) || ((root->val == p->val || root->val == q->val) && (lson || rson))) {
    
    
            ans = root;
        } 
        return lson || rson || (root->val == p->val || root->val == q->val);
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    
    
        dfs(root, p, q);
        return ans;
    }
};

Another approach is to record the parent node of each node, and then find the common root node for the two nodes

class Solution {
    
    
public:
    unordered_map<int, TreeNode*> fa;
    unordered_map<int, bool> vis;
    void dfs(TreeNode* root){
    
    
        if (root->left != nullptr) {
    
    
            fa[root->left->val] = root;
            dfs(root->left);
        }
        if (root->right != nullptr) {
    
    
            fa[root->right->val] = root;
            dfs(root->right);
        }
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    
    
        fa[root->val] = nullptr;
        dfs(root);
        while (p != nullptr) {
    
    
            vis[p->val] = true;
            p = fa[p->val];
        }
        while (q != nullptr) {
    
    
            if (vis[q->val]) return q;
            q = fa[q->val];
        }
        return nullptr;
    }
};

  1. Deleting a node in a linked list
    Please write a function to delete a given (non-end) node in a linked list, and you will only be given the requested node to be deleted.

The interesting part of this question is that the singly linked list does not know how the previous node deletes the node. The method is to assign the current node to the next node and delete the next node.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    
    
public:
    void deleteNode(ListNode* node) {
    
    

        if (node == NULL)
            return;

        if (node->next == NULL)
        {
    
    
            node = NULL;
            return;
        }

        ListNode *tmp = node->next;
        node->val = node->next->val;
        node->next = node->next->next;
        delete tmp;
        return;
    }
};
  1. The product of arrays other than itself
    gives you an integer array nums of length n, where n> 1, returns the output array output, where output[i] is equal to the product of the remaining elements in nums except nums[i].

The solution to this problem restricts the inability to use division, so you can change your mind: use two arrays to store the product of the left element and the product of the right element at the current position, and then multiply the two. It can be simplified further: use the output array to store the left element first, and then dynamically obtain the right element and directly multiply the assignment.

class Solution {
    
    
public:
    vector<int> productExceptSelf(vector<int>& nums) {
    
    
        int length = nums.size();
        vector<int> answer(length);

        // answer[i] 表示索引 i 左侧所有元素的乘积
        // 因为索引为 '0' 的元素左侧没有元素, 所以 answer[0] = 1
        answer[0] = 1;
        for (int i = 1; i < length; i++) {
    
    
            answer[i] = nums[i - 1] * answer[i - 1];
        }

        // R 为右侧所有元素的乘积
        // 刚开始右边没有元素,所以 R = 1
        int R = 1;
        for (int i = length - 1; i >= 0; i--) {
    
    
            // 对于索引 i,左边的乘积为 answer[i],右边的乘积为 R
            answer[i] = answer[i] * R;
            // R 需要包含右边所有的乘积,所以计算下一个结果时需要将当前值乘到 R 上
            R *= nums[i];
        }
        return answer;
    }
};


  1. Maximum sliding window value
    Given an array nums, a sliding window of size k moves from the leftmost side of the array to the rightmost side of the array. You can only see the k numbers in the sliding window. The sliding window only moves one position to the right at a time.
    Returns the maximum value in the sliding window.

Use the queue to save the window. The front end of the variable (that is, window.front()) is the subscript of the maximum value of this traversal. When we encounter a new number, we will add the new number to the end of the double-item queue (also It is the window.back()) comparison. If the end is smaller than the new number, the end is thrown away until the end of the queue is larger than the new number or the queue is empty. The approach is a bit like using the stack for bracket matching.

class Solution {
    
    
public:
	vector<int> maxSlidingWindow(vector<int>& nums, int k) {
    
    
        if (k == 0) return {
    
    };
		vector<int> res;
		deque<size_t> window;
		/*Init K integers in the list*/
		for (size_t i = 0; i < k; i++) {
    
    
			while (!window.empty()  && nums[i] > nums[window.back()]) {
    
    
				window.pop_back();
			}
			window.push_back(i);
		}
		res.push_back(nums[window.front()]);
		/*End of initialization*/
		for (size_t i = k; i < nums.size(); i++) {
    
    
			if (!window.empty() && window.front() <= i - k) {
    
    
				window.pop_front();
			}
			while (!window.empty() && nums[i] > nums[window.back()]) {
    
    
				window.pop_back();
			}
			window.push_back(i);
			res.push_back(nums[window.front()]);
		}
		return res;
	}
};


  1. Search two-dimensional matrix 2
    Write an efficient algorithm to search for a target value target in the mxn matrix matrix. The matrix has the following characteristics:
    the elements of each row are arranged in ascending order from left to right.
    The elements of each column are arranged in ascending order from top to bottom.

This question is a typical binary search, but because it has been sorted, in addition to binary search, it can also be completed by the principle of diagonal lines: starting from the upper right corner or the lower left corner, move the rows and columns according to the size rules until you find or out of bounds

class Solution {
    
    
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
    
    
        if(matrix.size() == 0||matrix[0].size() == 0)
        {
    
    
            return  false;
        }
        int  curx = matrix.size()-1,cury = 0;
        while(curx >= 0 &&cury < matrix[0].size())
        {
    
    
            if(target > matrix[curx][cury])
            {
    
    
                cury++;
            }
            else  if(target < matrix[curx][cury])
            {
    
    
                curx--;
            }
            else
            {
    
    
                return  true;
            }
        }
        return  false;
    }
};


  1. Design precedence for operation expressions
    Given a string containing numbers and operators, add parentheses to the expression, and change the operation precedence to find different results. You need to give the result of all possible combinations. Valid operators include +,-and *.

This question can use the divide and conquer algorithm to disassemble the expression into parts separated by coincidence, and then find different solutions in order. Another approach is to treat it as a dynamic programming solution: use two lists, one for all numbers and one for all operators. dp[i][j] represents all the solutions of the expression in the range of the i-th to the j-th number (counting from 0).

class Solution {
    
    
public:
    vector<int> diffWaysToCompute(string input) {
    
    
        int index = 0;
        int num = 0;
        while(index < input.size() && isdigit(input[index]))
            num = num * 10 + input[index++] - '0';
        if(index == input.size()){
    
    
            hash[input] = {
    
    num};
            return {
    
    num};
        }
        vector<int> ans;
        for(int i = 0; i < input.size(); i++){
    
    
            if(isOp(input[i])){
    
    
                string s1 = input.substr(0,i);
                string s2 = input.substr(i);
                vector<int> result1, result2;
                if(!hash.count(s1))
                    result1 = diffWaysToCompute(input.substr(0,i));
                else
                    result1 = hash[s1];
                if(!hash.count(s2))
                    result2 = diffWaysToCompute(input.substr(i+1));
                else
                    result2 = hash[s2];
                for(int r1 : result1){
    
    
                    for(int r2 : result2){
    
    
                        ans.push_back(calculate(r1,input[i],r2));
                    }
                }
            }
        }
        hash[input] = ans;
        return ans;
    }

    bool isOp(const char& c){
    
    
        return c == '+' || c == '-' || c == '*';
    }

    int calculate(const int& num1, const char& op, const int& num2){
    
    
        if(op == '+')
            return num1 + num2;
        else if(op == '-')
            return num1 - num2;
        else
            return num1 * num2;
    }
private:
    unordered_map<string,vector<int>> hash;
};


Guess you like

Origin blog.csdn.net/u013354486/article/details/107226044