2021-06-08二叉树路径问题

https://leetcode-cn.com/problems/longest-univalue-path/solution/yi-pian-wen-zhang-jie-jue-suo-you-er-cha-94j7/

 

Leetcode114

解题的关键是:左子树的最下最右的节点,是右子树的父节点.

为什么一个先序遍历,我用后序?

  • 回溯算法!!
  • 从右到左的进行排序!
  • last真的只记录这个顺序的上一个
  • 因为left==nullptr,必定会有丢失!
    TreeNode* last = nullptr;
    void flatten(TreeNode* root) {
        if (root == nullptr) return;
        flatten(root->right);
        flatten(root->left);
        root->right = last;
        root->left = nullptr;
        last = root;
    }

 

430.

class Solution {
    private Node ans;
    private Node cur;

    public Node flatten(Node head) {
        if(head == null){
            return null;
        }
        dfs(head);
        return ans;
    }
    //看成二叉树的前序遍历
    private void dfs(Node node){
        if(node==null){
            return;
        }
        //相当于前序遍历的主体,把遍历到的当前节点放入新的链表里
        if(cur==null){
            ans = new Node();
            ans.val = node.val;
            cur = ans;
        }else{
            Node newNode = new Node();
            newNode.val = node.val;
            cur.next = newNode;
            newNode.prev = cur;
            cur = newNode;
        }
        //优先迭代子节点,再迭代下一个节点
        dfs(node.child);
        dfs(node.next);
    }
}

  •  不要被有无null给欺骗了??
  • 每一次都新建一个node
  • 这个node后面接,前面接什么都要
  • cur保存断的那个!
  • child在前,那个next在后
class Solution {
public:
Node* ans;
Node* cur;
    Node* flatten(Node* head) {
        if(head==NULL) return head;
        dfs(head);
        return ans;
    }

    void dfs(Node* node){
        if(node==NULL) return;
        if(ans==NULL){
            ans = new Node;
            ans->val = node->val;
            cur = ans;
        }else{
            Node* tmp = new Node;
            tmp->val = node->val;
            tmp->prev = cur;
            cur->next = tmp;
            cur = tmp;
        }
        dfs(node->child);
        dfs(node->next);
    }
};

 

124.

  • 不解为何最后return的那个,如果比0小,是相当于这条支路不作选择嘛?
  •  
class Solution {
    int result = Integer.MIN_VALUE;
    public int maxPathSum(TreeNode root) {
        dfs(root);
        return result;
    }

    // 函数功能:返回当前节点能为父亲提供的贡献,需要结合上面的图来看!
    private int dfs(TreeNode root) {
        // 如果当前节点为叶子节点,那么对父亲贡献为 0
        if(root == null) return 0;
        // 如果不是叶子节点,计算当前节点的左右孩子对自身的贡献left和right
        int left = dfs(root.left);
        int right = dfs(root.right);
        // 更新最大值,就是当前节点的val 加上左右节点的贡献。
        result = Math.max(result, root.val + left + right);
        // 计算当前节点能为父亲提供的最大贡献,必须是把 val 加上!
        int max = Math.max(root.val + left, root.val + right);
        // 如果贡献小于0的话,直接返回0即可!
        return max < 0 ? 0 : max;
    }
}

//我的
class Solution {
public:
int res = INT_MIN;
    int maxPathSum(TreeNode* root) {
        dfs(root);
        return res;
    }

    int dfs(TreeNode* root){
        if(root==nullptr) return 0;
        int left = dfs(root->left);
        int right = dfs(root->right);
        int mmax = max(left+ root->val , right+root->val);
        res = max(res, left+right+root->val);
        return mmax>0? mmax:0;
    }
};

112.

该种解法总有不到十个通过不了??

class Solution {
public:
bool res = false;
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root==nullptr) return false;
        dfs(root, targetSum, 0);
        return res;
    }

    void dfs(TreeNode* root,int targetSum, int sum){
        if(root==nullptr){
            if(sum==targetSum) res= true;
            return;
        } 
        dfs(root->left, targetSum, sum+root->val);
        dfs(root->right, targetSum, sum+root->val);
    }
};
  • 可以用-法,不必一直加一个!
  •  return的是||, 就可以左边右边任意一个是true,就会被传送出来为true!
  • && targetSum-root->val==0

     

class Solution {
    public boolean hasPathSum(TreeNode root, int sum) {
        if (root == null) {
            return false;
        }
        if (root.left == null && root.right == null) {
            return sum - root.val == 0;
        }
        return hasPathSum(root.left, sum - root.val)
                || hasPathSum(root.right, sum - root.val);
    }
}


class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root==nullptr) return false;
        if(root->left==nullptr && root->right==nullptr && targetSum-root->val==0) return true;
        return hasPathSum(root->left, targetSum - root->val) || hasPathSum(root->right, targetSum-root->val);
    }
};

113.

这种办法要重复两次的计算!!!什么时候跳出循环,会多进入一层的循环,于是答案左右两个,会重了翻倍

class Solution {
public:
vector<vector<int>> ans;
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        dfs(root, targetSum, {});
        return ans;
    }

    void dfs(TreeNode* root, int targetSum, vector<int> path){
        if(root == nullptr){
            if(targetSum==0) ans.push_back(path);
            return;
        } 
        path.push_back(root->val);
        targetSum = targetSum-root->val;
        dfs(root->left, targetSum, path);
        dfs(root->right, targetSum, path);
    }
};

//为何出错??

class Solution {
public:
vector<vector<int>> ans;
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        dfs(root, targetSum, {});
        return ans;
    }

    void dfs(TreeNode* root, int targetSum, vector<int> path){
        if(root == nullptr){
            return;
        } 
        path.push_back(root->val);
        targetSum = targetSum-root->val;
        if(root->left==nullptr && root->right==nullptr && targetSum==0){
            ans.push_back(path);
        }
        dfs(root->left, targetSum, path);
        dfs(root->right, targetSum, path);
    }
};

437.双重递归

不要以为是递归就不是顺序执行了!!

  • 出发的头节点摇摆不定,第一重递归就是头节点的确定
  • 第二重递归是左右出发去找合适的支流,一找到就退出!
class Solution {
public:
int ans;
    int pathSum(TreeNode* root, int targetSum) {
        if(root==nullptr) return 0;
        dfs(root, targetSum);
        pathSum(root->left, targetSum);
        pathSum(root->right, targetSum);
        return ans;
    }

    void dfs(TreeNode* root, int targetSum){
        if(root==nullptr) return;
        targetSum -= root->val;
        if(targetSum==0) ans++;
        dfs(root->left, targetSum);
        dfs(root->right, targetSum);
    }
};

 

687.

int longestUnivaluePath(TreeNode *root)
{
    if (!root)
        return 0;
    longestPath(root);
    return res;
}

int longestPath(TreeNode *root)
{
    if (!root)
        return 0;
    int left = longestPath(root->left), right = longestPath(root->right);
    // 如果存在左子节点和根节点同值,更新左最长路径;否则左最长路径为0
    if (root->left && root->val == root->left->val)
        left++;
    else
        left = 0;
    if (root->right && root->val == root->right->val)
        right++;
    else
        right = 0;
    res = max(res, left + right);
    return max(left, right);
}
class Solution {
public:
int res;
    int longestUnivaluePath(TreeNode* root) {
        
        backtracking(root);
        return res;
    }

    int backtracking(TreeNode* root){
        if(root==nullptr) return 0;
        int left = backtracking(root->left);
        int right = backtracking(root->right);
        if(root->left && root->left->val == root->val){
            left++;
        }else{
            left = 0;
        }
        if(root->right && root->right->val == root->val){
            right++;
        }else{
            right =0;
        }
        res = max(res, left+right);
        return max(left, right); //毕竟一次只能是走一边的,不可能同时两边都走, 故一个根节点只能对应其中之一
    }
};

988

  • 按照字典序的排序就可以!sort解决

vector<string> path;
string smallestFromLeaf(TreeNode *root)
{
    dfs(root, "");
    sort(path.begin(), path.end()); //升序排序
    return path[0];
}

void dfs(TreeNode *root, string s)
{
    if (!root)
        return;
    s += 'a' + root->val;
    if (!root->left && !root->right)
    {
        reverse(s.begin(), s.end()); //题目要求从根节点到叶节点,因此反转
        path.push_back(s);
        return;
    }
    dfs(root->left, s);
    dfs(root->right, s);
}

//我的,计算极其慢!
class Solution {
public:
vector<string> path;
    string smallestFromLeaf(TreeNode* root) {
        dfs(root, "");
        sort(path.begin(), path.end());
        return path[0];
    }

    void dfs(TreeNode* root, string s){
        if(root==NULL){
            return;
        } 
        s += root->val + 'a';
        if(root->left==NULL && root->right==NULL){
            reverse(s.begin(), s.end());
            path.push_back(s);
            return;
        }
        dfs(root->left, s);
        dfs(root->right, s);
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值