首页 > 其他分享 >动态规划之子数组系列(下)

动态规划之子数组系列(下)

时间:2024-10-26 10:16:58浏览次数:3  
标签:arr nums int 位置 之子 数组 动态 dp

文章目录

等差数列划分

题目:等差数列划分

在这里插入图片描述
思路

  • 状态表示:dp[i]表示,以i位置为结尾的所有子数组中有多少个等差数列

  • 状态转移方程:在当前位置nums[i]上,若

    • nums[i] - nums[i - 1] == nums[i - 1] - nums[i - 2],此时构成一个新的等差数列,即dp[i] = dp[i - 1] + 1
    • nums[i] - nums[i - 1] != nums[i - 1] - nums[i - 2],此时构不成一个新的等差数列,即dp[i] = 0
  • 初始化:前两个位置的元素无法构成等差数列,因此初始化 dp[0] = dp[1] = 0

  • 填表顺序:从左往右

  • 返回值:返回整个dp 表中的所有值

C++代码

class Solution 
{
public:
    int numberOfArithmeticSlices(vector<int>& nums) 
    {
        int n = nums.size();
        vector<int> dp(n);
        
        int ret = 0;
        for(int i = 2; i < n; i++)
        {
            dp[i] = nums[i] - nums[i - 1] == nums[i - 1] - nums[i - 2] ? dp[i - 1] + 1 : 0;
            ret += dp[i];
        }

        return ret;
    }
};

最长湍流子数组

题目:最长湍流子数组

在这里插入图片描述
思路

  • 状态表示:以i位置结尾的所有子数组最长的湍流数组长度,此时结尾会有两种状态

    • i位置呈现上升趋势,记f[i]
    • i位置呈现下降趋势,记g[i]
  • 状态转移方程:

    • f[i]
      • arr[i] < arr[i - 1]时,说明i位置比i - 1位置小,此时i位置无法呈现上升趋势,无法和前面结合,所以1
      • arr[i] > arr[i - 1]时,说明i位置比i - 1位置大,此时i位置呈现上升趋势,即f[i] = g[i - 1] + 1
      • arr[i] = arr[i - 1]时,无法构成构成湍流数组,所以1
    • g[i]
      • arr[i] < arr[i - 1]时,说明i位置比i - 1位置小,此时i位置呈现下降趋势,即g[i] = f[i - 1] + 1
      • arr[i] > arr[i - 1]时,说明i位置比i - 1位置大,此时i位置无法呈现下降趋势,法和前面结合,所以1
      • arr[i] = arr[i - 1]时,无法构成构成湍流数组,所以1
  • 初始化:每一个元素都能构成湍流数组,所以将fg表都初始化为1

  • 填表顺序:从左往右两个表一起填

  • 返回值: 返回两个数组中的最大值

C++代码

class Solution 
{
public:
    int maxTurbulenceSize(vector<int>& arr) 
    {
        int n = arr.size();
        vector<int> f(n, 1);
        vector<int> g(n, 1);
        int ret = 1;
        for(int i = 1; i < n; i++)
        {
            if(arr[i - 1] > arr[i])
                g[i] = f[i - 1] + 1;
            else if(arr[i - 1] < arr[i])
                f[i] = g[i - 1] + 1;

            ret = max(ret, max(g[i], f[i]));
        }
        return ret;
    }
};

单词拆分

题目:单词拆分

在这里插入图片描述

思路

  • 状态表示:dp[i]表示,区间[0, i]区间内的字符串,能否被字典中的单词拼接而成

  • 状态转移方程:根据最后一个位置的情况来分析,设最后一个单词起始位置为j。这样整个字符串就被划分为[0, j - 1][j, i]两个区间;当两个区间都满足条件时,即成立;

    • 对于[0, j - 1],我们判断dp[j - 1]```的bool```值
    • 对于[j, i],我们判断这个单词是否在字典中,即s.substr(j, j - i + 1)是否在字典中存在
    • 满足上述两者,dp[i] = true;否则dp[i] = false
  • 初始化:添加一个辅助结点,帮助初始化。可以将字符串前面加上一个占位符 s = ' ' + s,这样就没有下标的映射关系的问题了,同时还能处理空串的情况。 dp[0] = true,表示空串能够拼接而成

  • 填表顺序:从左往右

  • 返回值:返回 dp[n]位置的布尔值

C++代码

class Solution 
{
public:
    bool wordBreak(string s, vector<string>& wordDict) 
    {
        unordered_set<string> hash;
        for (string& s : wordDict)
            hash.insert(s);

        int n = s.size();
        vector<bool> dp(n + 1);
        dp[0] = true;
        s = ' ' + s;
        for (int i = 1; i <= n; i++) 
        {
            for (int j = i; j >= 1; j--) 
            {
                if (dp[j - 1] && hash.count(s.substr(j, i - j + 1))) 
                {
                    dp[i] = true;
                    break;
                }
            }
        }
        return dp[n];
    }
};

环绕字符串中唯一的子字符串

题目:环绕字符串中唯一的子字符串

在这里插入图片描述

思路

  • 状态表示:dp[i]表示以 i 位置的元素为结尾的所有子串中,有多少个在 base 中出现过

  • 状态转移方程:

    • 子串的长度等于 1,此时这一个字符会出现在 base
    • 子串的长度大于 1i位置和 i - 1 位置上的字符组合后,出现在 base
    • 如何判断组合字符出现在base
      • s[i - 1] + 1 == s[i],此时为顺序,即a, bg,h
      • s[i - 1] == 'z' && s[i] == 'a',即z,a
      • 此时dp[i] = dp[i - 1]
    • 综上,dp[i] = dp[i - 1] + 1。注意此处+1并非是对于子串长度大于1,而是统计长度等于 1和长度大于 1的总数!
  • 初始化:初始化为1

  • 填表顺序:从左往右

  • 返回值:返回dp表中所有元素的和,但这里需要去重。所以,对于26个字母,我们统计以其为结尾的最大·。创建一个大小为26 的数组,统计所有字符结尾的最大dp

C++代码

class Solution 
{
public:
    int findSubstringInWraproundString(string s) 
    {
        int n = s.size();
        vector<int> dp(n, 1);
        for (int i = 1; i < n; i++)
            if (s[i] - 1 == s[i - 1] || (s[i - 1] == 'z' && s[i] == 'a'))
                dp[i] = dp[i - 1] + 1;

        int hash[26] = {0};
        for (int i = 0; i < n; ++i)
            hash[s[i] - 'a'] = max(hash[s[i] - 'a'], dp[i]);

        int sum = 0;
        for (int& x : hash)
            sum += x;

        return sum;
    }
};

标签:arr,nums,int,位置,之子,数组,动态,dp
From: https://blog.csdn.net/m0_74317866/article/details/143244950

相关文章

  • 数组的实战
    数组的实战练习1:多个字符从两端移动,向中间汇聚。练习2:二分查找练习1:多个字符从两端移动,向中间汇聚。上述题干的描述内容举个例子更好理解:很明显需要两个字符串才能实现,一个字符串为"welcometoC!!!!!!!!!!",另一个字符串为"######################"。因为字符串可......
  • LeetCode|384. 打乱数组(day22)
    作者:MJ昊博客:掘金、CSDN等公众号:程序猿的编程之路今天是昊的算法之路第22天,今天分享的是LeetCode第384题打乱数组的解题思路。这是一道中等难度的题目,要求我们实现一个算法,使得数组支持随机打乱和重置为初始顺序的功能,并且每种排列出现的概率应当相等。题目描述简要......
  • 动态语言有哪些
    在开头段落,请允许我一句言归正传地回答这个问题:动态语言主要有Python、JavaScript、Ruby、Perl、PHP和Groovy等。这类语言的主要特点是它们在运行期间能够改变其结构,如新的函数、对象、甚至代码可以被引入,已有的函数可以被删除或其他结构上的改变。这使得动态语言在写代码时具有......
  • 数据结构 ——— C语言实现数组栈
    目录栈的概念以及示意图链式栈和数组栈链式栈:数组栈:数组栈的结构实现数组栈的准备工作实现数组栈初始化数组栈入栈(尾插)出栈(尾删)访问栈顶数据判断栈是否为空栈数据的总数访问栈的所有数据释放栈Stack.h的所有代码Stack.c的所有代码栈的概念以及示意图栈......
  • 动态规划入门指北
    P1359租用游艇思路首先设出\(dp\)数组:\(dp_i\)表示走到第\(i\)个点时的最小花费。于是乎,建一个反图,对于每一个\(i\)找到能与其相连的最小路程。得到转移方程:\[$dp_i=min(dp_i,dp_j+mp_{j,i});$\]时间复杂度为\(O(n^2)\)。ACcode#include<bits/stdc++.h>usingna......
  • CPP vector动态数组的基本用法
    #include<iostream>#include<vector>#include<algorithm>usingnamespacestd;intmain()#defineintlonglong//不能放在主函数之前,因为主函数的返回类型必须是int{ vector<int>v={0,0,0,0}; v.push_back(1); v.push_back(2); v.push_back(2); v.push_back(3......
  • 面试华为遇到了经典动态规划题 - 怎么用go、C++进行编程解决
    华为的知名很大程度上源自于在经历过被美国的制裁和打压后不仅撑住了,而且还做出了相对于自己来说技术进步程度很大的芯片​。这是一个不小的成绩​。从个人的角度上来说,华为是最难进的一家大公司之一,它的面试标准很严格​。这不仅是筛选人才,在某种程度上来说也是由于求职市场......
  • 动态规划中的自顶向下和自底向上是什么意思
    动态规划中,自顶向下是一种解决问题的方法,通常与递归结合使用,在自顶向下的动态规划中,问题被划分为子问题,然后递归地解决这些子问题。自底向上是另一种动态规划的方法,通常使用迭代而非递归,在自底向上的动态规划中,问题的解决顺序从最小规模的子问题开始,逐步构建到原始问题。1.自......
  • 动态规划之简单多状态 dp 问题(下)
    文章目录买卖股票的最佳时机买卖股票的最佳时机含手续费买卖股票的最佳时机III买卖股票的最佳时机IV买卖股票的最佳时机题目:买卖股票的最佳时机思路状态表示:dp[i]表示第i天结束后,处于某个状态的最大利润,我们可以细分为,处于“买入”、“可交易”、“”三种状......
  • 【动态绘图】python 动态柱形图 动态折线图 bar_chart_race sjvisualizer
    本文主要介绍如何使用Python的bar_chart_race和sjvisualizer模块绘制动态柱形图和动态折线图。关于sjvisualizer包使用详细可见【动态绘图】上。一、实验环境1.1操作系统及Python环境本实验的所使用的操作系统为Windows1064位,Python版本为Python3.12.4,Python编译器......