【动态规划】【数组】1416. 恢复数组

简介: 【动态规划】【数组】1416. 恢复数组

作者推荐

【深度优先搜索】【树】【图论】2973. 树中每个节点放置的金币数目

本文涉及知识点

动态规划汇总

LeetCode1416. 恢复数组

某个程序本来应该输出一个整数数组。但是这个程序忘记输出空格了以致输出了一个数字字符串,我们所知道的信息只有:数组中所有整数都在 [1, k] 之间,且数组中的数字都没有前导 0 。

给你字符串 s 和整数 k 。可能会有多种不同的数组恢复结果。

按照上述程序,请你返回所有可能输出字符串 s 的数组方案数。

由于数组方案数可能会很大,请你返回它对 10^9 + 7 取余 后的结果。

示例 1:

输入:s = “1000”, k = 10000

输出:1

解释:唯一一种可能的数组方案是 [1000]

示例 2:

输入:s = “1000”, k = 10

输出:0

解释:不存在任何数组方案满足所有整数都 >= 1 且 <= 10 同时输出结果为 s 。

示例 3:

输入:s = “1317”, k = 2000

输出:8

解释:可行的数组方案为 [1317],[131,7],[13,17],[1,317],[13,1,7],[1,31,7],[1,3,17],[1,3,1,7]

示例 4:

输入:s = “2020”, k = 30

输出:1

解释:唯一可能的数组方案是 [20,20] 。 [2020] 不是可行的数组方案,原因是 2020 > 30 。 [2,020] 也不是可行的数组方案,因为 020 含有前导 0 。

示例 5:

输入:s = “1234567890”, k = 90

输出:34

提示:

1 <= s.length <= 105.

s 只包含数字且不包含前导 0 。

1 <= k <= 109.

动态规划

n= s.length。

动态规划的状态表示

dp[i] 表示前i个字符的方案数,vLen[i]表示 s[i,i+vLen[i])是合法数字[1,k]且不喊前导0,vLen[i]如果有多个合法值,取最大值。

动态规划的转移方程

通过dp[i]更新后置状态 j = 1 v L e n [ i ] \Large_{j=1}^{vLen[i]}j=1vLen[i]dp[i+j] += dp[i]

动态规划的初始值

dp[0]为1,其它为0

动态规划的填表顺序

i从小到大

动态规划的返回值

dp.back()

代码

核心代码

template<int MOD = 1000000007>
class C1097Int
{
public:
  C1097Int(long long llData = 0) :m_iData(llData% MOD)
  {
  }
  C1097Int  operator+(const C1097Int& o)const
  {
    return C1097Int(((long long)m_iData + o.m_iData) % MOD);
  }
  C1097Int& operator+=(const C1097Int& o)
  {
    m_iData = ((long long)m_iData + o.m_iData) % MOD;
    return *this;
  }
  C1097Int& operator-=(const C1097Int& o)
  {
    m_iData = (m_iData + MOD - o.m_iData) % MOD;
    return *this;
  }
  C1097Int  operator-(const C1097Int& o)
  {
    return C1097Int((m_iData + MOD - o.m_iData) % MOD);
  }
  C1097Int  operator*(const C1097Int& o)const
  {
    return((long long)m_iData * o.m_iData) % MOD;
  }
  C1097Int& operator*=(const C1097Int& o)
  {
    m_iData = ((long long)m_iData * o.m_iData) % MOD;
    return *this;
  }
  bool operator<(const C1097Int& o)const
  {
    return m_iData < o.m_iData;
  }
  C1097Int pow(long long n)const
  {
    C1097Int iRet = 1, iCur = *this;
    while (n)
    {
      if (n & 1)
      {
        iRet *= iCur;
      }
      iCur *= iCur;
      n >>= 1;
    }
    return iRet;
  }
  C1097Int PowNegative1()const
  {
    return pow(MOD - 2);
  }
  int ToInt()const
  {
    return m_iData;
  }
private:
  int m_iData = 0;;
};
class Solution {
public:
  int numberOfArrays(string s, int k) {
    m_c = s.length();
    vector<C1097Int<> > dp(m_c + 1);
    dp[0] = 1;
    for (int i = 0; i < m_c; i++)
    {
      if ('0' == s[i])
      {
        continue;
      }
      long long num = 0, len = 0;
      for (; i + len < m_c; len++)
      {
        num = num * 10 + s[i + len] - '0';
        if (num > k)
        {
          break;
        }
      }
      for (int j = 1; j <= len; j++)
      {
        dp[i + j] += dp[i];
      }
    }
    return dp.back().ToInt();
  }
  int m_c;
};

测试用例

template<class T>
void Assert(const T& t1, const T& t2)
{
  assert(t1 == t2);
}
template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
  if (v1.size() != v2.size())
  {
    assert(false);
    return;
  }
  for (int i = 0; i < v1.size(); i++)
  {
    Assert(v1[i], v2[i]);
  }
}
int main()
{ 
  string s;
  int k;
  {
    Solution sln;
    s = "1000", k = 10000;
    auto res = sln.numberOfArrays(s, k);
    Assert(1, res);
  }
  {
    Solution sln;
    s = "1000", k = 10;
    auto res = sln.numberOfArrays(s, k);
    Assert(0, res);
  }
  {
    Solution sln;
    s = "1317", k = 2000;
    auto res = sln.numberOfArrays(s, k);
    Assert(8, res);
  }
  {
    Solution sln;
    s = "2020", k = 30;
    auto res = sln.numberOfArrays(s, k);
    Assert(1, res);
  }
  {
    Solution sln;
    s = "1234567890", k = 90;
    auto res = sln.numberOfArrays(s, k);
    Assert(34, res);
  }
}

2023年2月

class C1097Int

{

public:

C1097Int(int iData = 0) :m_iData(iData)

{

}

C1097Int operator+(const C1097Int& o)const

{

return C1097Int((m_iData + o.m_iData) % s_iMod);

}

C1097Int& operator+=(const C1097Int& o)

{

m_iData = (m_iData + o.m_iData) % s_iMod;

return this;
}
C1097Int operator
(const C1097Int& o)const

{

return((long long)m_iData o.m_iData) % s_iMod;
}
C1097Int& operator
=(const C1097Int& o)

{

m_iData =((long long)m_iData *o.m_iData) % s_iMod;

return *this;

}

int ToInt()const

{

return m_iData;

}

private:

int m_iData = 0;;

static const int s_iMod = 1000000007;

};

int operator+(int iData, const C1097Int& int1097)

{

int iRet = int1097.operator+(C1097Int(iData)).ToInt();

return iRet;

}

int& operator+=(int& iData, const C1097Int& int1097)

{

iData = int1097.operator+(C1097Int(iData)).ToInt();

return iData;

}

class Solution {

public:

int numberOfArrays(string s, int k) {

const int iKLen = std::to_string(k).length();

vector pre(iKLen + 1);

vector preValue(iKLen + 1);

pre[0] = 1;

for (const auto& ch : s)

{

int iValue = ch - ‘0’;

vector dp(iKLen + 1);

if (‘0’ != ch)

{

dp[1] += std::accumulate(pre.begin(),pre.end(),0);

}

for (int i = 1; i < iKLen; i++)

{

long long iNewValue = preValue[i] * 10 + iValue;

if (iNewValue > k)

{

continue;

}

dp[i + 1] += pre[i];

}

pre.swap(dp);

for (int i = iKLen; i >= 1; i–)

{

preValue[i] = preValue[i - 1] * 10 + iValue;;

}

}

return std::accumulate(pre.begin(), pre.end(), 0);

}

};



相关文章
|
8月前
|
设计模式 算法 Java
【数据结构和算法】删掉一个元素以后全为 1 的最长子数组
这是力扣的 1493 题,难度为中等,解题方案有很多种,本文讲解我认为最奇妙的一种。又又又是一道滑动窗口的典型例题,可以帮助我们巩固滑动窗口算法。这道题很活灵活现,需要加深对题意的变相理解。给你一个二进制数组nums,你需要从中删掉一个元素。 请你在删掉元素的结果数组中,返回最长的且只包含 1 的非空子数组的长度。 如果不存在这样的子数组,请返回 0 。
116 1
|
8月前
【Leetcode 2645】构造有效字符串的最小插入数 —— 动态规划
状态定义:`d[i]`为将前 i 个字符拼凑成若干个 abc 所需要的最小插入数。状态转移方程: 如果` word[i]>word[i−1]`,那么`word[i]`可以和`word[i−1]`在同一组 abc 中,`d[i]=d[i−1]−1` ;否则`word[i]`单独存在于一组 abc 中,`d[i]=d[i−1]+2`
|
算法 容器
算法:双指针解决数组划分和数组分块问题
算法:双指针解决数组划分和数组分块问题
|
8月前
|
算法 测试技术 C#
二分查找:LeetCode2035:将数组分成两个数组并最小化数组和的差
二分查找:LeetCode2035:将数组分成两个数组并最小化数组和的差
|
3月前
|
C++
数组元素移除(暴力求解)
一种原地移除数组中特定值元素的暴力求解方法,并通过C++代码示例展示了如何实现这一操作。
40 0
|
8月前
|
算法 JavaScript 前端开发
贪心算法】按要求补齐数组
贪心算法】按要求补齐数组
28 0
|
8月前
|
算法 测试技术 C#
【动态规划】【数论】【区间合并】3041. 修改数组后最大化数组中的连续元素数目
【动态规划】【数论】【区间合并】3041. 修改数组后最大化数组中的连续元素数目
|
8月前
leetcode2967. 使数组成为等数数组的最小代价
leetcode2967. 使数组成为等数数组的最小代价
60 0
|
8月前
|
存储 算法 Java
数据结构和算法面试题:给定一个整数数组 nums,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
数据结构和算法面试题:给定一个整数数组 nums,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
99 0
|
8月前
【每日一题Day157】LC1574删除最短的子数组使剩余数组有序 | 双指针 + 二分查找
【每日一题Day157】LC1574删除最短的子数组使剩余数组有序 | 双指针 + 二分查找
52 0

热门文章

最新文章