牛客竞赛每日俩题 - Day7

目录

经典01背包问题

二叉树遍历与构造(考研重点)


经典01背包问题

求正数数组的最小不可组成和_百度笔试题_牛客网

参考大佬题解:

动态规划:01背包问题(无物品价值),思想相同,题目最终要求有些变化

min为最轻物品的重量,sum为所有物品总重量

假设有一个能装入容量为C(C在[min,sum]间取值)的背包和n件重量分别为w1,w2,…,wn的物品,能否从n件物品中挑选若干件恰好装满背包,要求输出不满足条件的最小容量。
以数组{3,2,5}为例,dp初始化全为0
接下来进行逆序分析:

(逆序是因为同一件物品只能放一次)
(因为分情况时容量要减去当前物品重量,所以高容量的值要用低容量来更新,可能造成重复放入)
(举个例子,判断3是否放入时,如果是顺序的话dp[3]=dp[3]+3放了一次3,之后dp[6]=dp[3]+3又放了一次,就重复了)

判断某一物品能否放入时直接忽略容量小于该物品质量的情况

先判断3是否放入
对于容量为3及以上的都选择放入,对应dp值更新为3

再判断2是否放入
对于容量为5及以上的都选择放入,加上3,对应dp值更新为5
对于容量为3、4的如果放入后剩余容量不够放其他物品,比较3后选择较大值,对应dp值仍为3
容量为2的选择放入,对应dp值更新为2

最后判断5是否放入
对于容量为10的选择放入,加上5,dp值更新为3
对于容量为9的选择放入,加上3, dp值更新为8
对于容量为8的选择放入,加上3, dp值更新为8
对于容量为7的选择放入,加上2, dp值更新为7
对于容量为6的选择放入,dp值更新为5
对于容量为5的选择放入,dp值更新为5

在前i个状态下的最值的前提下,考虑第i个值是否使用,从而把前i个状态的最值求出来,这就是动态规划的思想

思路总结:

  1. j表示背包空间大小,逆序更新是因为要用小的背包更新大的
  2. 核心:如果当前背包承重<放入物品最大承重,则更新dp[j] < dp[j - arr[i]] + arr[i],dp[j - arr[i]]表示背包不放arr[i]时的最大重量
  3. 最后当承重为n时,放入的重量不为n则认为是最大不可求和

class Solution {
public:
    int getFirstUnFormedNum(vector<int> arr, int len) {
        int sum = 0, min = arr[0];
        for (int i = 0; i < len; ++i)
        {
            sum += arr[i];
            if (arr[i] < min)
                min = arr[i];
        }
        vector<int> dp(sum + 1, 0);
        for (int i = 0; i < len; ++i)
        {
            //j:背包空间大小
            //dp[j]:背包最大承重
            for (int j = sum; j >= arr[i]; --j)
            {
                //dp[j-arr[i]]意思是背包承重为j时,
                //如果已经放置了arr[i]的重量后还能放置的最大重量
                if (dp[j - arr[i]] + arr[i] > dp[j])
                    dp[j] = dp[j - arr[i]] + arr[i];
            }
        }
        //最后当承重为n时,放入的重量不为n则认为是最大不可求和
        for (int i = min; i <= sum; ++i)
        {
            if (i != dp[i])
                return i;
        }
        return sum + 1;
    }
};




二叉树遍历与构造(考研重点)

重建二叉树_牛客题霸_牛客网

 

核心思想:

  • 根据root节点,将中序vector划分成vin_leftvin_right两部分中序子序列
  • 根据中序子序列长度,将前序vector划分成pre_left, pre_right对应的前序子序列
  • root->left递归生成
  • root->right递归生成

具体做法:

  • step 1:先根据前序遍历第一个点建立根节点。
  • step 2:然后遍历中序遍历找到根节点在数组中的位置。
  • step 3:再按照子树的节点数将两个遍历的序列分割成子数组,将子数组送入函数建立子树。
  • step 4:直到子树的序列长度为0,结束递归。

 

 

 难点:

对于dfs的pre_strat和pre_end,如上图所示,我们拿左子树left举例

  1. pre_start==preStart+1;(对应前序的元素2)
  2. pre_end==preStrat+(中序根节点 i 左边的所有元素)==preStart+(i-vinStart);(对应前序的元素7)

 其余确定范围的方式同理

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:

    TreeNode* dfs(vector<int> pre,int preStart,int preEnd,vector<int> vin,int vinStart,int vinEnd)
    {
        if(preStart>preEnd||vinStart>vinEnd) return nullptr;
        TreeNode* root=new TreeNode(pre[preStart]);
        for(auto i=vinStart;i<=vinEnd;i++)
        {
            if(vin[i]==pre[preStart])
            {
                root->left=dfs(pre,preStart+1,preStart+i-vinStart,vin,vinStart,i-1);
                root->right=dfs(pre,preStart+i-vinStart+1,preEnd,vin,i+1,vinEnd);
                break;
            }
        }
        return root;
    }

    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        if(pre.empty()||vin.empty()) return nullptr;
        return dfs(pre,0,pre.size()-1,vin,0,vin.size()-1);
    }
};

 

 

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小黄同学LL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值