草庐IT

【再谈动态规划】

Tom·猫 2023-04-21 原文

动态规划

前缀最值

121. 买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

示例 1:

输入:[7,1,5,3,6,4]
输出:5 解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 =6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

链接: 买卖股票的最佳时机

要求最大利润,也就是最大值和最小值的差值,我们可以进行暴力解法,
1.枚举第i天作为买入点
2.循环遍历左开右闭区间(i,n],寻找一个最大值作为卖出点
3.卖出点价格减去卖出点价格就是以第i天为买入点的最大利润
4.最后保留最大的最大利润返回

可以看到,时间复杂度O(n)=n^2;
当数据量最够大时,肯定超出时间限制

所以 我们选择使用动态规划解题
按照动态规划解题步骤:

1.设计状态
2.写出状态转移方程
3.设定初始状态
4.执行状态转移
5.返回最终的解

解题思路:
求出前缀最小值数组 premin[]
遍历一遍prices数组,在用prices[i]-premin[i-1]
找到两数组相减的最大值
为所求值

时间复杂度O(n)=n
根据前两课的训练,一个最小值数组对于我们毫无难度

premin[i]=min(premin[i-1],prices[i])

代码:

int max(int a,int b)
{
    return a>b?a:b;
}
int min(int a,int b)
{
    return a<b?a:b;
}

int maxProfit(int* prices, int pricesSize){
 
    int premin[pricesSize];
    for(int i=0;i<pricesSize;i++)
    {
        if(i==0)
        {
            premin[i]=prices[i];
        }
        else
        {
            premin[i]=min(premin[i-1],prices[i]);
        }
    }
    int ans=0;
    for(int i=1;i<pricesSize;i++)
    {
        ans=max(ans,prices[i]-premin[i-1]);
    }
return ans;
}

后缀最值

1299. 将每个元素替换为右侧最大元素

给你一个数组 arr ,请你将每个元素用它右边最大的元素替换,如果是最后一个元素,用 -1 替换。

完成所有替换操作后,请你返回这个数组。

示例 1:

输入:arr = [17,18,5,4,6,1] 输出:[18,6,6,6,1,-1] 解释:

  • 下标 0 的元素 --> 右侧最大元素是下标 1 的元素 (18)
  • 下标 1 的元素 --> 右侧最大元素是下标 4 的元素 (6)
  • 下标 2 的元素 --> 右侧最大元素是下标 4 的元素 (6)
  • 下标 3 的元素 --> 右侧最大元素是下标 4 的元素 (6)
  • 下标 4 的元素 --> 右侧最大元素是下标 5 的元素 (1)
  • 下标 5 的元素 --> 右侧没有其他元素,替换为 -1 示例 2:

输入:arr = [400]
输出:[-1]
解释:下标 0 的元素右侧没有其他元素。

根据题意,题解:

1.求出后缀最大值数组postmax
2.按照题意malloc一个ans数组
3.再将postmax数组中的值往ans数组中挪动
4.最后返回即可

状态转移方程:postmax[i]=max(postmax[i+1],arr[i])

代码:

 int max(int a,int b)
{
    return a>b?a:b;
}
int min(int a,int b)
{
    return a<b?a:b;
}


int* replaceElements(int* arr, int arrSize, int* returnSize){
    *returnSize=arrSize;
    int *ans=(int *)malloc(sizeof(int)*arrSize);

    int postmax[arrSize];
    for(int i=arrSize-1;i>=0;i--)
    {
        if(i==arrSize-1)
        {
            postmax[i]=arr[i];
        }
        else
        {
            postmax[i]=max(postmax[i+1],arr[i]);
        }
    }
    for(int i=0;i<arrSize;i++)
    {
        if(i==arrSize-1)
        ans[i]=-1;
        else
        ans[i]=postmax[i+1];
    }
    return ans;
}

前缀最值变形

1014. 最佳观光组合

给你一个正整数数组 values,其中 values[i] 表示第 i 个观光景点的评分,并且两个景点 i 和 j 之间的 距离 为 j - i。

一对景点(i < j)组成的观光组合的得分为 values[i] + values[j] + i - j ,也就是景点的评分之和 减去 它们两者之间的距离。

返回一对观光景点能取得的最高分。

示例 1:

输入:values = [8,1,5,2,6]
输出:11
解释:i = 0, j = 2, values[i] + values[j] + i - j = 8 + 5 + 0 - 2 = 11
示例 2:

输入:values = [1,2]
输出:2

链接: 最佳观光组合

思路:
1.由题意得 得分= values[i] + values[j] + i - j
2.可以分解为(values[i]+i)+(values[j]-j)
3.由因为 i<j 我们可以去求出 values[i]+i 的前缀最大值数组
4.然后 遍历数组values,设定一个初始值 ans=values[0]+values[1]+0-1;
5.且状态转移方程为 ans=max(ans,premax[j-1]+values[j]-j)
5.可以求出ans的最大值

代码:

  int max(int a,int b)
{
    return a>b?a:b;
}
int maxScoreSightseeingPair(int* values, int valuesSize){
   
    int premax[valuesSize];
    premax[0]=values[0];
    for(int i=1;i<valuesSize;i++)
    {
        premax[i]=max(premax[i-1],values[i]+i);
    }
    int ans=values[0]+values[1]+0-1;
    for(int j=1;j<valuesSize;j++)
    {
        ans=max(ans,premax[j-1]+values[j]-j);
    }
    return ans;
}

前缀+后缀 最值

42. 接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组[0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。

示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

这是一道leetcode的一道困难题,但只是一个纸老虎,练习了前几道题,掌握好解题方法,其实很简单。
根据前几题我们知道了求前缀最值数组后缀最值数组
前缀最值数组:

void  Premax(int *num,int sz,int *premax ){
       for(int i=0;i<sz;i++)
       {
           if(i==0)
           {  premax[i]=num[i];}
           else
           {
               premax[i]=max(premax[i-1],num[i]);
           }
       }
}

后缀最值数组:

void Postmax(int *num,int sz,int *postmax)
{
    for(int i=sz-1;i>=0;i--)
    {
        if(i==sz-1)
        {
            postmax[i]=num[i];
        }
        else
        {
            postmax[i]=max(postmax[i+1],num[i]);
        }
    }
}

解题思路:
1.要求接住的所有雨水sum
2.只要将 每根柱子上的雨水数量 加起来即可
3.求出前缀最大值数组和后缀最大值数组
4.当定位到 i柱子的时候,i柱子上的雨水数量
5.等于其左右两边柱子的高度的最大值中的较小值-自身柱子的高度
6.状态转移方程为 sum+=(min(premax[i],postmax[i])-height[i]);

代码如下:

int max(int a,int b)
{
    return a>b?a:b;
}
int min(int a,int b)
{
    return a<b?a:b;
}
void  Premax(int *num,int sz,int *premax ){
       for(int i=0;i<sz;i++)
       {
           if(i==0)
           {  premax[i]=num[i];}
           else
           {
               premax[i]=max(premax[i-1],num[i]);
           }
       }
}
void Postmax(int *num,int sz,int *postmax)
{
    for(int i=sz-1;i>=0;i--)
    {
        if(i==sz-1)
        {
            postmax[i]=num[i];
        }
        else
        {
            postmax[i]=max(postmax[i+1],num[i]);
        }
    }
}

int trap(int* height, int heightSize){
    int premax[heightSize];
    int postmax[heightSize];

    Postmax(height,heightSize,postmax);
    Premax(height,heightSize,premax);

    int sum=0;
    for(int i=0;i<heightSize;i++)
    {
        sum+=(min(premax[i],postmax[i])-height[i]);
    }
return sum;
}

这道leetcode的困难题就完成了,是不是纸老虎呢

结语

本期是动态规划的最后一期博客,动态规划的题还有很多,博主只是带大家简单的介绍了一下动态规划,还有待大家一起努力。

我是Tom-猫
如果觉得有帮助的话,记得
一键三连哦ヾ(≧▽≦*)o。

有关【再谈动态规划】的更多相关文章

  1. ruby - 在 Ruby 中动态创建数组 - 2

    有没有办法在Ruby中动态创建数组?例如,假设我想遍历用户输入的书籍数组:books=gets.chomp用户输入:"TheGreatGatsby,CrimeandPunishment,Dracula,Fahrenheit451,PrideandPrejudice,SenseandSensibility,Slaughterhouse-Five,TheAdventuresofHuckleberryFinn"我把它变成一个数组:books_array=books.split(",")现在,对于用户输入的每一本书,我想用Ruby创建一个数组。伪代码来做到这一点:x=0books_array.

  2. ruby - 是否可以将 IRB 提示配置为动态更改? - 2

    我想在IRB中浏览文件系统并让提示更改以反射(reflect)当前工作目录,但我不知道如何在每个命令后进行提示更新。最终,我想在日常工作中更多地使用IRB,让bash溜走。我在我的.irbrc中试过这个:require'fileutils'includeFileUtilsIRB.conf[:PROMPT][:CUSTOM]={:PROMPT_N=>"\e[1m:\e[m",:PROMPT_I=>"\e[1m#{pwd}>\e[m",:PROMPT_S=>"FOO",:PROMPT_C=>"\e[1m#{pwd}>\e[m",:RETURN=>""}IRB.conf[:PROMPT_MO

  3. ruby-on-rails - carrierwave:在序列化动态属性上安装 uploader - 2

    首先,我使用的是rails3.1.3和来自master的carrierwavegithub仓库的分支。我使用after_init钩子(Hook)来确定基于属性的字段页面模型实例并为这些字段定义属性访问器将值存储在序列化哈希中(希望它清楚我是什么谈论)。这是我正在做的事情的精简版:classPage省略mount_uploader命令让我可以访问我想要的属性。但是当我安装uploader时出现错误消息说“nil类的未定义新方法”我在源代码中读到有方法read_uploader和扩展模块中的write_uploader。我如何必须覆盖这些来制作mount_uploader命令使用我的“虚拟

  4. ruby - 在 Ruby 中动态生成多维数组 - 2

    我正在尝试动态构建一个多维数组。我想要的基本上是这样的(为简单起见写出来):b=0test=[[]]test[b]这给了我错误:NoMethodError:undefinedmethod`test=[[],[],[]]而且它工作正常,但在我的实际使用中,我不会事先知道需要多少个数组。有一个更好的方法吗?谢谢 最佳答案 不需要像您正在使用的索引变量。只需将每个数组附加到您的test数组:irb>test=[]=>[]irb>test[["a","b","c"]]irb>test[["a","b","c"],["d","e","f"]]

  5. ruby-on-rails - 使用 gmaps4rails 动态加载谷歌地图标记 - 2

    如何只加载map边界内的标记gmaps4rails?当然,在平移和/或缩放后加载新的。与此直接相关的是,如何获取map的当前边界和缩放级别? 最佳答案 我是这样做的,我只在用户完成平移或缩放后替换标记,如果您需要不同的行为,请使用不同的事件监听器:在你看来(index.html.erb):{"zoom"=>15,"auto_adjust"=>false,"detect_location"=>true,"center_on_user"=>true}},false,true)%>在View的底部添加:functiongmaps4rail

  6. ruby - 动态方法链? - 2

    如何在对象上调用方法名称的嵌套哈希?例如,给定以下哈希:hash={:a=>{:b=>{:c=>:d}}}我想创建一个方法,给定上面的散列,执行以下操作:object.send(:a).send(:b).send(:c).send(:d)我的想法是我需要从一个未知的关联中获取一个特定的属性(这个方法不知道,但程序员知道)。我希望能够指定一个方法链来以嵌套哈希的形式检索该属性。例如:hash={:manufacturer=>{:addresses=>{:first=>:postal_code}}}car.execute_method_hash(hash)=>90210

  7. ruby - 如何使用 method_missing 动态声明方法? - 2

    我有一个ruby​​程序,我想接受用户创建的方法,并使用该名称创建一个新方法。我试过这个:defmethod_missing(meth,*args,&block)name=meth.to_sclass我收到以下错误:`define_method':interningemptystring(ArgumentError)in'method_missing'有什么想法吗?谢谢。编辑:我以不同的方式让它工作,但我仍然很好奇如何以这种方式做到这一点。这是我的代码:defmethod_missing(meth,*args,&block)Adder.class_evaldodefine_method

  8. ruby - 动态扩展现有方法或覆盖 ruby​​ 中的发送方法 - 2

    假设我们有A、B、C类。Adefself.inherited(sub)#metaprogramminggoeshere#takeclassthathasjustinheritedclassA#andforfooclassesinjectprepare_foo()as#firstlineofmethodthenrunrestofthecodeenddefprepare_foo#=>prepare_foo()neededhere#somecodeendendBprepare_foo()neededhere#somecodeendend如您所见,我正在尝试将foo_prepare()调用注入

  9. ruby - 使用 jbuilder 创建具有动态哈希键的 JSON - 2

    这里我想输出带有动态组名的json而不是单词组@tickets.eachdo|group,v|json.group{json.array!vdo|ticket|json.partial!'tickets/ticket',ticket:ticketend}end@ticket是这样的散列{a:[....],b:[.....]}我想要这样的输出{a:[.....],b:[....]} 最佳答案 感谢@AntarrByrd,这个问题有类似的答案:JBuilderdynamickeysformodelattributes使用上面的逻辑我已经

  10. ruby - 在 Rakefile 中动态生成 Rake 测试任务(基于现有的测试文件) - 2

    我正在根据Rakefile中的现有测试文件动态生成测试任务。假设您有各种以模式命名的单元测试文件test_.rb.所以我正在做的是创建一个以“测试”命名空间内的文件名命名的任务。使用下面的代码,我可以用raketest:调用所有测试require'rake/testtask'task:default=>'test:all'namespace:testdodesc"Runalltests"Rake::TestTask.new(:all)do|t|t.test_files=FileList['test_*.rb']endFileList['test_*.rb'].eachdo|task|n

随机推荐