zoukankan      html  css  js  c++  java
  • Daliy Algorithm (dp,树)-- day 84

    Nothing to fear


    种一棵树最好的时间是十年前,其次是现在!

    那些你早出晚归付出的刻苦努力,你不想训练,当你觉的太累了但还是要咬牙坚持的时候,那就是在追逐梦想,不要在意终点有什么,要享受路途的过程,或许你不能成就梦想,但一定会有更伟大的事情随之而来。 mamba out~

    2020.5.22


    人一我十,人十我百,追逐青春的梦想,怀着自信的心,永不言弃!

    LG-P1827 American Heritage

    给出二叉树的先序和中序遍历
    要求求出后序遍历
    我们知道根据先序遍历和另外一种遍历我们
    可以建立以可二叉树,但是应该存在一种更简单的
    办法使得不用建树也能够成功得到序列

    首先我们都知道:

    1. 先序遍历的第一个结点一定是根节点
    2. 后序遍历的最后一个结点一定是根节点

    我们只需要在中序遍历中找到该根节点
    该节点的左边是左子树,右边是右子树
    递归即可

    
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    using namespace std;
    const int N = 100;
    string a , b;
    int n;
    
    // 根据先序求后后续遍历 k = i - p;
    void postorder(int x,int y,int p,int q)
    {
        printf("此时  后序区间为[%d, %d],中序区间[%d, %d]
    ",x , y , p , q);
        if(x > y || p > q)return;
        int i = a.find(b[x]); // 在中序遍历中找到当前先序区间中的第一个
        printf("此时 i = %d 
    ",i);
        int k = i - p;
        postorder(x + 1, x + k, p , i - 1);
        postorder(x + k + 1, y, i + 1,  q);
        cout << b[x];
    }
    
    // 根据后续求先序 k = p - i    
    void preorder(int x,int y,int p,int q)
    {
        //printf("此时  后序区间为[%d, %d],中序区间[%d, %d]
    ",x , y , p , q);
        if(x > y || p > q)return;
        int i = a.find(b[y]); // 在中序遍历中找到当前先序区间中的第一个
        //printf("此时 i = %d
    ",i);
        cout << b[y];
        int k = q - i;
        preorder(x , y - k - 1, p , i - 1);
        preorder(y - k, y - 1,i + 1,  q);
    }   
    int main()
    {
        cin >> a >> b;
        n = a.size() - 1;
        preorder(0,n,0,n);
        return 0;
    }
    
    
    

    LC-494. 目标和

    思路,引用评论区大佬的分析:

    1. 都是类似给你元素和目标,从元素中选取组合达到目标,我觉得这样的问题,都可以归类到背包问题里。
    2. dp[i][j]表示到第i个字符和为j的方法数。
      dp[i][j] = dp[i - 1][j - nums[i]] + dp[i - 1][j + nums[i]]
      dp[i - 1][j - nums[i]] 表示这次是+时的方法数,
      dp[i - 1][j + nums[i]] 表示这次是-时的方法数。
      如果我们j正序遍历,把dp数组初始化为0.
      则上面公式可以转化为:dp[i][j] == 0(计算前)
      dp[i][j] = dp[i][j] + dp[i - 1][j - nums[i]]
      dp[i][j] = dp[i][j] + dp[i - 1][j + nums[i]] ==>
      遍历j时,我们利用上一次dp[i- 1][x]的计算结果,可以每次更新两个dp[i][x]的结果:
      dp[i][j + nums[i]] = dp[i][j + nums[i]] + dp[i - 1][j]; 此时dp[i][j + nums[i]] = 0
      dp[i][j - nums[i]] = dp[i][j - nums[i]] + dp[i - 1][j]; 此时dp[i][j - nums[i]] = 0 =>
      编程如下形式:
      dp[i][j + nums[i]] += dp[i - 1][j]
      dp[i][j - nums[i]] += dp[i - 1][j]
      这样,每次遍历j时,我们不计算dp[i][j]的值,而是利用dp[i - 1][j]的值,更新两个相关dp节点的值,会加速计算。
    class Solution {
    public:
        int findTargetSumWays(vector<int>& nums, int S) {
            int n = nums.size();
            vector<vector<int>> f(n, vector<int>(n + 2001));
            int k = 1000;
            //f[i][j] 表示前i个数字和位j的方案数
            //f[i][j] = f[i-1][j-nums[i]] + f[i-1][j+nums[i]]
            // 通过变形
            f[0][k+nums[0]] = 1;f[0][k-nums[0]] += 1;
            for(int i = 1;i < n ;i ++)
            {
                for(int j = -k;j <= k ;j ++)
                {
                    if(f[i-1][j+k] > 0) // 实际上由剪枝的作用判断前 i - 1个阶段是否构成该解
                    {
                        f[i][j+k-nums[i]] += f[i-1][j+k];
                        f[i][j+k+nums[i]] += f[i-1][j+k];
                    }
                }
            }
            // 注意S > 1000 的情况乱 是不可能出现的所以直接返回0即可
            return S > 1000  ? 0 : f[n-1][S+k];
        }
    };
    
  • 相关阅读:
    JavaScript初探 三 (学习js数组)
    JavaScript初探 二 (了解数据)
    JavaScript初探 一(认识JavaScript)
    2019暑假学习督促安排
    【C#】让工具栏ToolStrip能触发焦点控件的Leave、Validating、DataError等事件以验证数据
    【C#】回调方法不通过object参数获得委托实例
    【SQL】找出行数与自增标识值不相等的表(即有缺行)
    【SQL】统计所有表的行数
    【SQL】靠谱的TRIM函数,附赠过程一枚
    【C#】在窗体中水平居中的控件,到了XP下不居中的解决办法
  • 原文地址:https://www.cnblogs.com/wlw-x/p/12940299.html
Copyright © 2011-2022 走看看