lt-动态规划

动态规划的重点是:1)找状态转移方程;2)计算边界情况。

切入点:具体要用什么数据结构记录,该数据结构一般是数组或者数组变形,那么数组的每个元素代表什么,元素和元素之间具有什么联系。

推荐刷:5、45、1014、91;

70:a[n] = a[n-1]+a[n-2];  a[1] = 1,a[2] = 2;

98:a[n] = max(a[n-2] + nums[n],a[n-1]),即每次计算都尽量把原来较大的部分保留。

120:

arr[i][0] = arr[i-1][0]+triangle[i][0];

arr[i][j] = min(arr[i-1][j-1],arr[i-1][j]) + triangle[i][j];

arr[i][i] = arr[i-1][i-1] + triangle[i][i];

746:状态转移方程中a[i]代表跳到第i个位置目前所需花费的最小cost。因此,a[0]=a[1]=1;a[i]=min(a[i-2]+cost[i-2] ,a[i-1]+cost[i-1]),最终结果找a[n],n=cost.size()

213:198的变形。队列拆分成两个数组即可。0~n-1和1~n。转移方程:a[i]=max(a[i-2]+nums[i],a[i-1);边界:a[0] = nums[0],a[1]=max(nums[0],nums[1]) 

55:每个nums[i]代表从第i个 位置开始,可以往后走若干个位置。用一个数组array代表每个下标的可达与否,从前往后遍历nums数组,依次记录每个位置的可达位置。位置不可达时return。

 45:这个是55的变形。55在意的是能不能到,因此array[i]存储1和0就可。而45在意的是最小,因此array[i]存储步数。

array[1:size - 1] = -1,array[0] = 0.

for i in nums

        t = nums[i]

        for k from i+1 to t+i &&k <size

              if array[k] = -1       

                        array[k] = array[i]+1

                else array[k] = min(array[k],array[i]+1)

return array[size-1]   

1014:拆成两部分,result= value[i]+i和value[j]-j

数组记录:以j为终点的result最大值;同时记录到j为止,max(value[i]+i)(i∈[0,j])

即递推公式为:        result = max (result,maxnu + value[j] - j)

                                maxnu = max(maxnu,value[j]+j)

初始值:maxnu = value[0]

740:用数组记录每个nums[i]有多少个。而后,问题转化为打家劫舍198

状态转移方程为array[i] = max{array[i-1],array[i-2]+array[i]*i};初始数组每个元素记录i有若干个,结束时数组每个元素记录当前位置最多得到多少点数。

152:仍然采用max(array[i-1],array[i-1]*nums[i]),但考虑到有负数,应该简化成:

if(nums[i] < 0)        swap(maxnum,minnum);

result = max(maxnum,minnum)

maxnum = max(maxnum,maxnu*nums[i])

minnum  = min(minnnum, minnum*nums[i])

即,每次遇到负数,max和min将有交换,小的变大,大的变小。

 是152的变形;

if(number = 0)        positive=0,negative = 0

else if(number < 0)        swap(positive,negative);negative++; if(positive>0)        positive++;

else        positive++;if(negative>0)negative++;

 lt5是一道非常经典的动态规划算法。用数组array记录index为i~j的子字符串是否为回文数组。

即        array[i][i]  = 1………………………(1)

           array[i][j] = array[i+1][j-1] &(s[i] = s[j])……(2)

而回文字符串应该是从小到大,即从length = 1 到length = size, 即如果一个子串是非回文串,那其更长的字符串也不会是回文串

       array[i][i] = 1

        for i = 0 to n

                for LEN = 2 to n

                        j = i + LEN - 1

                        if(s[i]=s[j])        

                                if LEN <= 3        array[i][j] = 1

                                else array[i][j] = array[i+1][j-1]

                        else array[i][j] = 0

                        record MAX_LEN

        return substr(i,MAX_LEN)

array[0] = 1,array[1] = 1;

s[i]的方程为:

        if(s[i]!='0') array[i+1] += array[i] 

        if(s[i-1] !='0'&s[i-1]*10+s[i]<=26)        array[i+1]+=array[i-1]

动态规划里, array存储到目前index为止,有若干种存储方式。

1:用动态规划,找max不重叠子区间

        sort(nums)//根据区间起点从小到大排序

        for(i = 1 : n)

                for(j = 0 : i)

                        if(nums[j][1]<nums[i][0])

                                f[i] = max(f[i],f[j]+1)

        return n - f[n-1]

2:用贪心 

        sort(nums)//根据区间终点从小到大排序

        for auto e : nums

                 if(e[0]>end)//如果当前区间已经有覆盖,就result++

                        result++;        

                else

                        end = e[1]

        return result;//

 array[i][j]=array[i-1][j]+array[i][j-1]

注意由于只能右或者下,因此对这个二维数组实现的方法是:先写完边界情况(横纵轴只要1个为0就值为1),然后再按常规循环遍历。

a++;

                if(a> array[i]) array[i] = a;

array[i]代表:以i作为终点的序列,有多少个递增的。

array[i] = max(array[j]) + 1        …… (j < i,当nums[i]>nums[j]时)                

            = 1                                ……(当nums[i]是目前最小值)

 O(n2)算法        for(i = 0 : nums_size)

                                 for(j = 0 : i)

                                        if(nums[i]>nums[j])

                                                if(num[j]+1>nums[i])        nums[i] = max(nums[j]+1,nums[i]);

                    

数组array[amout+1],每个index代表硬币和为index最少需要多少个硬币,0代表硬币组无法组合出当前结果。

for(auto i:coins)        array[i] = 1;

for(j = min(coins) : amount)

        if(array[j] != 0)

              for(auto i :coins)

                        if(i + j <= amount) 

                                temp=array[j]+1  

                                if(array[i+j]==0)

                                         array[i+j]=temp

                                else        array[i+j] = min(array[i+j],array[j]+1);

return array[amout] == 0? -1 : array[i+j];

 (583是1143的变形)

和标准答案给的解法略微不同

array[i][j]代表到text1[i]和到text2[j]为止,有多长的公共子序列

边界:即i = 0 || j = 0时,array[i][j] = array[i-1][0] | text1[i]==test2[j];//也可能是array[0][j-1]

 for(i = 1: len1)

        for(j  = 1:len2)

                if(text1[i]==text2[j])        array[i][j] = array[i-1][j-1]

                else        array[i][j] = max(array[i-1][j],array[i][j-1])

 if(text1[i-1] == text2[j-1])        array[i][j] = min(array[i-1][j-1],array[i-1][j]+1,array[i][j-1]+1);

else        array[i][j] = 1+min(array[i-1][j-1],array[i-1][j],array[i][j-1]);        

lt34:

dp记录只允许k个节点不相邻时,可获得的最大价值

dp[i] = max(dp[i],dp[i]+dp[i - j - 1]+root->val),而求解dp需要用到dfs

 先判断不可能的情况:例如数组和为奇数、数组的最大值>sum/2、数组长度<2。

 这里的array[i][j]代表,0~i的index,值为j是否可以取得到。

array[i][j] = array[i-1][j] | array[i-1][j-nums[i]];

 968有点难以理解,对每个节点r,有3种状态:

1、a状态:如果r必须放摄像头,cover整颗树需要的摄像头数目

2、b状态:无论r是否放摄像头,cover整棵树需要的摄像头数目

3、c状态:cover r的左右子树需要的摄像头数目,无论r是否能被覆盖

定义status {a,b,c}为root的状态,左右孩子的状态分别为{la,lb,lc}和{ra,rb,rc}的状态

a = lc + rc + 1;//左子树覆盖+右子树覆盖+r本身覆盖

b = min(a,min(la+rc,lc+ra))

c = min(a,lb+rb)

 status dfs(TreeNode* root)

        if(!root)        return [INT_MAX,0,0]

       auto [la,lb,lc] = dfs(root->left)

       auto [ra,rb,rc] = dfs(root->right)

       int a = lc+rc+1

       int b = min(a,min(la+rc,lc+ra))

       int c = min(a,lb+rb)

        return [a,b,c]

 array[size][size][2]

其中array[i][i][0]代表当前value为0的条件是否为真;

for (i=0;i<size;i+=2)        array[i][i][0]=tmp - (s[i]-'0'),array[i][i][1] = tmp-(s[i]-'1')

for(int step=0;step < size; step += 2)

        for(int i = 0; i + step<  size;i+=2)

                for(int j = i+1; j < i+step;j+=2)//j指的是&|^这些符号,以j点间隔开

                        left0 = array[i][j-1][0],left1 = array[i][j-1][1]

                        right0 = array[j+1][i+step][0],right1 = array[j+1][i+step][1]

                        if(j == '&')

                                array[i][i+step][0] = left0*right0+left1*right0+left0*right1;

                                array[i][i+step][1] = let1*right1;

                        else if(j == '|)

                                array[i][i+step][0] = left0*right0

                                array[i][i+step][1] = left0*right1+left1*right0+left1*right1

                        else if (j == '^')

                                array[i][i+step][0] = left0*right0+left1*right1;

                                array[i][i+step][1] = left1*right0+left0*right1

return array[0][size-1][result]

                

转移方程:

        if matrix[i][j] == 1        temp[i][j] = 0

        else         temp[i][j] = temp[i-1][j] + temp[i][j-1]

        注意边界情况:如果第一行或者第一列中有石头,则第这个位置之后的这行or这列的位置的temp值为0                 

lt264:丑数

很容易想到用一个数组存放之前的所有丑数,但要注意用三个指针记录当前取2、3、5的值的位置。

动态方程:value  = min(array[p2] * 2,array[p3] * 3,array[p5] * 5);       

                  if (array[pi]*i == array.end() ) pi++; 

 

                  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值