2786. 访问数组中的位置使分数最大

        这并不是一个难题,但是我确实在做题中得到了一些启发,所以记录一下

先讲一讲这个题目的做法:

        首先不难想到这是一个dp问题,(由 i 可以跳到 j ) 而且应该不难, 要不然就不是medium了,doge 那么,暴力的dp就是:

        dp[j] = max (dp[i] + nums  OR dp[j] = dp[i] + nums - x) , i<j, 前面表示nums[i] nums[j] 是同奇偶,后面是nums[i] 和 nums[j]不同奇偶,  时间复杂度是O(n^2),对于 1e5的数据会超时

         那么我们肯定是要优化的,如果做过那个最大数组元素连乘积,就会想到这就是一个dp+分类, 也就是说我们维护一下 上一个是奇数的最大值 上一个是偶数的最大值, (btw, 最大数组元素连乘积 就是维护一下 最大连乘积(正数) 和 最小连乘积(负数))

        后面就没有什么需要赘述的了,还是要看一下数据量和返回值类型 选择long long

        上代码: (我的代码,可以通过)

class Solution {
public:
    long long maxScore(vector<int>& nums, int x) { //审题一开始在0  初始化有问题
        long long lastOddMax=nums[0]%2?nums[0]:-x,lastEvenMax=nums[0]%2?-x:nums[0];
        for(int i=1;i<nums.size();i++){
            int num=nums[i];
            if(num%2){// odd
                lastOddMax=max({lastOddMax,lastOddMax+num,lastEvenMax+num-x});
            }else{//     even
                lastEvenMax=max({lastEvenMax,lastEvenMax+num,lastOddMax+num-x});
            }
        } 
        return max(lastEvenMax,lastOddMax);
    }
};

some thoughts:

        1. 第一次提交的时候,是没有通过的,经过检验发现是题目要求一开始必须在0出发,而我的代码是不要求从0出发的,也就是初始化有问题,这里说一下,既然题目要求了第一次必须从下标0开始 所以就需要赋值成一个nums[0],一个-x,   类似的如果不要求第一个从哪里开始只是要求在奇偶性改变的时候 -x ,就应该赋值成一个nums[0],一个0,可以想一想为什么,这对于想通dp / dfs的初值设置是很有好处的

        2. 第二个事情就是我定义的dp实际上表示的是 从奇数跳转过来的最大值从偶数跳转过来的最大值, 他每次都是和自己比较了一下大小的,所以最后直接返回就是了,但是这是这个题目特殊的子问题的分割方式决定的,更常见的dp是dp[i]表示一定取到nums[i]下的最优值,之后用一个循环外的变量拿到最大值, 代码应该是像这样: 这里的lastOddMax,lastEvenMax就不必和自己比较了

for(...){

        if(num%2){

                lastOddMax=max(lastOddMax+num,lastEvenMax+num-x);

                ans=max(lastOddMax,ans);

        }else{

               lastEvenMax=max(lastEvenMax+num,lastOddMax+num-x);

                ans=max(lastEvenMax,ans);

        }

}

重头戏来了:

做题顺序:
1. first        读一下题目,有一个大致的印象,是哪一个类别的(字符串,图,树),该类别一般都有什么算法

2. second  看一看数据量,O(n) O(nlogn) ... O(n^2) O(n^3)

3. third       如果感觉做过类似的题目, 那就往上面靠, 仿写  
                  没有类似的题目,想一想一些通用的思想,  dp, 贪心, sort, 递归/dfs, 二分法
    3.1 使用dp 就要想好定义, 最好能写出来i,j的含义, 同时也可以看看分类(a) [:i][:j]
                   (b)dp[i]表示选择nums[i]最优     (c) num[i]另起炉灶

    3.2 贪心  不用严格证明正确性,能够贪心一下简化一点思维就很好了,常见的可以是 sort + 贪心,                       反悔贪心: 针对于需要等待积累 让量变引起质变的题目,  循环外记录ans

    3.3 sort 可以看成是一种数据预处理or一种代价不大的贪心,  要求题目的选择是 非连续且不要求                     相对位置,针对多目标最值或者多元素结构体,可以先固定一维最好或者最差,减少思维量

    3.4 dfs/递归  对于树/图的一种普适法, 尤其对树有奇效,可以大大简化思维量,类似归纳法,只需要                     边界条件(即n=0,n=1), 递推式,(f(n)=g(f(n-1)...f(1))) 使用记忆化后可以降低时间复杂度

    3.5 二分法 针对于暴力超时,但是nlogn能过, 使用二分有个条件,就是ans左右两边一定是左边全0                     右边全1或者左边全1右边全0,ans是第一个0或者第一个1

4. 优化时空 使用特殊的数据结构

        unordered_map / map 用时间换空间                   -> multimap / val取vector

        unordered_set  / set    插入删除logn,       会去重 -> multiset(不去重)

        单调栈 单调队列

做题原则:

        1. 不管方法好坏或者时空复杂度, 第一步要做的是解出来这个题, 只有先做出来,然后再去想时空的优化,在掌握了常见算法之后, 大部分优化都是数据结构的调整, 也有一些是思路的调整,这个就说明你的第一步定位没有定位好, 也是我们要通过刷题学习积累的feel.

        2. 对于新的算法,特殊的数据结构,这个没有做出来是正常的,也不必花费时间死想,正确的姿势应该是-> 搞懂这个题, 搞懂这个模板, 刷五六道类似题目, 过一段时间回顾, 之后就自然掌握了,下一次他就应该进入你的知识库了

  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值