[Leetcode] 113, 53, 124

本文解析了三道经典算法题目:路径总和II(113)、最大子数组和(53)及二叉树最大路径和(124)。通过递归、动态规划等方法给出了清晰的解题思路及C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

113. Path Sum II

Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum.

For example:
Given the below binary tree and sum = 22,
              5
             / \
            4   8
           /   / \
          11  13  4
         /  \    / \
        7    2  5   1

return

[
   [5,4,11,2],
   [5,8,4,5]
]

Solution: 直接递归求解。

Code(1): return的方式传递vector。

/**
 * 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:
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        vector<vector<int>> ans;
        if(root==NULL) return ans;
        if(root->left==NULL && root->right==NULL){
            if(root->val==sum){
                vector<int> v;
                v.push_back(root->val);
                ans.push_back(v);
            }
            return ans;
        }
        vector<vector<int>> vleft = pathSum(root->left, sum-root->val);
        vector<vector<int>> vright = pathSum(root->right, sum-root->val);
        ans.insert(ans.end(), vleft.begin(), vleft.end());
        ans.insert(ans.end(), vright.begin(), vright.end());
        for(int i=0; i<ans.size(); i++){
            ans[i].insert(ans[i].begin(), root->val);
        }
        return ans;
    }
};

Code(2): 使用引用(&)传递vecotr。注意,使用引用传递ans时,要注意使用一个数组cur来记录到从根节点到前节点路径,而不能将数据直接记录到ans中,因为是使用了深搜,因此在搜索右子树时,左子树的结果已经存入ans数组,这会导致结果出错。

/**
 * 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:
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        vector<vector<int>> ans;
        vector<int> cur;
        pathSum(root, sum, cur, ans);
        return ans;
    }
private:
    void pathSum(TreeNode* root, int sum, vector<int>& cur, vector<vector<int>>& ans){
        if(root==NULL) return;
        cur.push_back(root->val);
        if(root->left==NULL && root->right==NULL){
            if(root->val==sum){
                ans.push_back(cur);
            }
        }else{
            pathSum(root->left, sum-root->val, cur, ans);
            pathSum(root->right, sum-root->val, cur, ans);
        }
        cur.pop_back();
    }
};

53. Maximum Subarray

Find the contiguous subarray within an array (containing at least one number) which has the largest sum.

For example, given the array [-2,1,-3,4,-1,2,1,-5,4],
the contiguous subarray [4,-1,2,1] has the largest sum = 6.

More practice:

If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

Solution(1): 动态规划,解释摘自《leetcode详解》。


Code:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int f = nums[0];
        int maxVal = f;
        for(int i=1; i<nums.size(); i++){
            f = max(nums[i], f+nums[i]);
            if(f>maxVal) maxVal = f;
        }
        return maxVal;
    }
};

Solution(2): 处理后枚举,连续子序列的和等于两个前缀和之差,复杂度O(n^2)。将这种算法稍作处理后可得到O(n)的解,Code部分给出O(n)的写法。

Code:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int MIN = 0; 
        int MAX = nums[0]; 
        int total = nums[0];
        for(int i=1; i<nums.size(); i++){
            MAX = max(MAX, nums[i]); 
            MIN = min(MIN, total);
            MAX = max(MAX, nums[i]+total-MIN); 
            total += nums[i];
        }
        return MAX;
    }
};

Solution(3): 分治法,将数组分成两段,分别求最大,然后归并(即比较左半段、右半段、和中间节点向两边遍历得到的最大和,取这三个数的最大值)。时间复杂度为O(nlogn)。

Code:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        return maxSubArray(nums.begin(), nums.end());
    }
private:
    int maxSubArray(vector<int>::iterator begin, vector<int>::iterator end){
        if(begin==end) return INT_MIN;
        vector<int>::iterator mid = begin + (end-begin)/2;
        int maxSide = maxSubArray(begin, mid);
        maxSide = max(maxSubArray(mid+1, end),maxSide);
        int maxMid = *mid;
        int cur = *mid;
        for(auto i=mid-1; i-begin>=0; i--){
            cur += *i;
            if(cur>maxMid) maxMid = cur;
        }
        cur = maxMid;
        for(auto i=mid+1; i!=end; i++){
            cur += *i;
            if(cur>maxMid) maxMid = cur;
        }
        return max(maxMid, maxSide);
    }
};



124. Binary Tree Maximum Path Sum

Given a binary tree, find the maximum path sum.

For this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The path must contain at least one node and does not need to go through the root.

For example:
Given the below binary tree,

       1
      / \
     2   3

Return 6.

Solution: 最大连续子序列和(53)的变体题,同样可以使用动态规划的思想。假设f[x]为包含根节点(x)的最大连续子序列和(注意,只返回一个方向上的和即left->root或者right->root),则可得递推公式f[root] =f[root]+max(f[root->left],0)+max(f[root->right,0),得到递推公式后,递归求解即可。

Code:

/**
 * 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:
    int maxPathSum(TreeNode* root) {
        maxSumWithRoot(root);
        return maxSum;
    }
private:
    int maxSum = INT_MIN;
    int maxSumWithRoot(TreeNode* root){
        //返回值是从root出发(包括root)到叶子节点的路径上最大的和(root->...)
        if(root==NULL) return INT_MIN;
        int maxval = root->val;
        int l = maxSumWithRoot(root->left);
        int r = maxSumWithRoot(root->right);
        if(l>0) maxval += l;
        if(r>0) maxval += r;
        maxSum = max(maxSum, maxval);
        return max(r,l)>0 ? root->val+max(r,l) : root->val;
    }
};



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值