【动态规划】【子序列除重】【C++算法】1987不同的好子序列数目

简介: 【动态规划】【子序列除重】【C++算法】1987不同的好子序列数目

作者推荐

【动态规划】【状态压缩】【2次选择】【广度搜索】1494. 并行课程 II

本文涉及知识点

动态规划汇总

LeetCode1987:不同的好子序列数目

给你一个二进制字符串 binary 。 binary 的一个 子序列 如果是 非空 的且没有 前导 0 (除非数字是 “0” 本身),那么它就是一个 好 的子序列。

请你找到 binary 不同好子序列 的数目。

比方说,如果 binary = “001” ,那么所有 好 子序列为 [“0”, “0”, “1”] ,所以 不同 的好子序列为 “0” 和 “1” 。 注意,子序列 “00” ,“01” 和 “001” 不是好的,因为它们有前导 0 。

请你返回 binary 中 不同好子序列 的数目。由于答案可能很大,请将它对 109 + 7 取余 后返回。

一个 子序列 指的是从原数组中删除若干个(可以一个也不删除)元素后,不改变剩余元素顺序得到的序列。

示例 1:

输入:binary = “001”

输出:2

解释:好的二进制子序列为 [“0”, “0”, “1”] 。

不同的好子序列为 “0” 和 “1” 。

示例 2:

输入:binary = “11”

输出:2

解释:好的二进制子序列为 [“1”, “1”, “11”] 。

不同的好子序列为 “1” 和 “11” 。

示例 3:

输入:binary = “101”

输出:5

解释:好的二进制子序列为 [“1”, “0”, “1”, “10”, “11”, “101”] 。

不同的好子序列为 “0” ,“1” ,“10” ,“11” 和 “101” 。

提示:

1 <= binary.length <= 105

binary 只含有 ‘0’ 和 ‘1’ 。

动态规划

除0外,不存在以0开始的子序列。如果存在0,则必定存在子序列{0}。以下的分析排除{0}。

排除{0}后任意合法子序列在后面增加0或1,都是合法子序列。

动态规划的状态表示

pre[0] 从binary[0,i)中选择若干字符,形成以0结束的合法子序列数量。pre[1]以1结束的子序列数量。

dp和pre类似,对应的是binary[0,i+1)。

动态规划的转移方程

binary[i]为1

{ p r e [ 0 ] 不选择当前字符,以 0 结束的字符数量 情况一 p r e [ 1 ] 不选择当前字符,以 1 结束的字符数 情况二 p r e [ 0 ] + p r e [ 1 ] + 1 选择当前字符,以 1 结束的字符数量。 情况三 \begin{cases} pre[0] & 不选择当前字符,以0结束的字符数量 & 情况一 \\ pre[1] & 不选择当前字符,以1结束的字符数 & 情况二 \\ pre[0]+pre[1]+1 & 选择当前字符,以1结束的字符数量。 & 情况三 \\ \end{cases}pre[0]pre[1]pre[0]+pre[1]+1不选择当前字符,以0结束的字符数量不选择当前字符,以1结束的字符数选择当前字符,以1结束的字符数量。情况一情况二情况三

情况三又可以分三种情况:

{ p r e [ 0 ] 倒数第二个字符是 0 情况三一 p r e [ 1 ] 倒数第二个字符是 1 情况三二 1 子序列 1 。 情况三三 \begin{cases} pre[0] & 倒数第二个字符是0 & 情况三一 \\ pre[1] & 倒数第二个字符是1 & 情况三二 \\ 1 & 子序列{1}。 & 情况三三 \\ \end{cases}pre[0]pre[1]1倒数第二个字符是0倒数第二个字符是1子序列1情况三一情况三二情况三三

情况一、情况二、情况三 内部不存在重复情况。

情况一以0结尾,情况二、三以1结尾,所以情况一和情况二(三)不会重复。

情况二所有的情况都和情况三重合,情况二分类:

{ 倒数第二个字符是 0 被情况三一包含 倒数第二个字符是 1 被情况三二包含 子序列 1 。 和情况三三重复 \begin{cases} 倒数第二个字符是0 & 被情况三一包含 \\ 倒数第二个字符是1 & 被情况三二包含 \\ 子序列{1}。 & 和情况三三 重复\\ \end{cases}倒数第二个字符是0倒数第二个字符是1子序列1被情况三一包含被情况三二包含和情况三三重复

总结

dp[1] = pre[0]+pre[1]+1

dp[0] = pre[0]

binary[i]为0

不能为子序列{0}

dp[0] = pre[0]+pre[1]

dp[1] = pre[1]

动态规划的初始值

pre 全为0。

动态规划的返回值

pre之和。

代码

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 numberOfUniqueGoodSubsequences(string binary) {
    vector<C1097Int<>> pre(2);
    for (const auto& ch : binary)
    {
      pre = {('0'==ch)? (pre[0] + pre[1]):pre[0],('1' == ch) ? (pre[0] + pre[1]+1) : pre[1] };
    }
    int iZero = std::count(binary.begin(), binary.end(), '0') > 0;
    return (pre[0] + pre[1] + iZero).ToInt();
  }
};

2023年2月

class C1097Int

{

public:

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

{

}

C1097Int operator+(const C1097Int& o)const

{

return C1097Int(((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;
}
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;

}

bool operator<(const C1097Int& o)const

{

return m_iData < o.m_iData;

}

C1097Int& pow( int n)const

{

C1097Int iRet = 1, iCur = *this;

while (n)

{

if (n & 1)

{

iRet *= iCur;

}

iCur *= iCur;

n >>= 1;

}

return iRet;

}

C1097Int PowNegative1()

{

return pow(s_iMod - 2);

}

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;

}

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 numberOfUniqueGoodSubsequences(string binary) {

vector pre(2);

for (const auto& ch : binary)

{

vector dp(2);

if (‘0’ == ch)

{

pre[0] += pre[1];

}

else

{

pre[1] += pre[0];

pre[1] += 1;

}

}

return (pre[0] + pre[1] + (int)(-1 != binary.find(‘0’))).ToInt();

}

};

2023年7月

class Solution {

public:

int numberOfUniqueGoodSubsequences(string binary) {

bool bHasZero = binary[0] == ‘0’;

vector<C1097Int<>> pre(2);

pre[1] = (binary[0] == ‘1’);

for (int i = 1; i < binary.size(); i++)

{

vector<C1097Int<>> dp = pre ;

if (‘0’ == binary[i])

{

bHasZero = true;

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

}

else

{

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

}

pre.swap(dp);

}

return (C1097Int<>(bHasZero) + pre[0] + pre[1]).ToInt();

}

};


相关文章
|
6天前
|
存储 算法 安全
基于红黑树的局域网上网行为控制C++ 算法解析
在当今网络环境中,局域网上网行为控制对企业和学校至关重要。本文探讨了一种基于红黑树数据结构的高效算法,用于管理用户的上网行为,如IP地址、上网时长、访问网站类别和流量使用情况。通过红黑树的自平衡特性,确保了高效的查找、插入和删除操作。文中提供了C++代码示例,展示了如何实现该算法,并强调其在网络管理中的应用价值。
|
3天前
|
存储 算法 安全
基于哈希表的文件共享平台 C++ 算法实现与分析
在数字化时代,文件共享平台不可或缺。本文探讨哈希表在文件共享中的应用,包括原理、优势及C++实现。哈希表通过键值对快速访问文件元数据(如文件名、大小、位置等),查找时间复杂度为O(1),显著提升查找速度和用户体验。代码示例展示了文件上传和搜索功能,实际应用中需解决哈希冲突、动态扩容和线程安全等问题,以优化性能。
|
3月前
|
存储 算法 C++
高精度算法(加、减、乘、除,使用c++实现)
高精度算法(加、减、乘、除,使用c++实现)
795 0
高精度算法(加、减、乘、除,使用c++实现)
|
3月前
|
存储 算法 决策智能
【算法】博弈论(C/C++)
【算法】博弈论(C/C++)
|
3月前
|
存储 算法 C++
【算法】哈希映射(C/C++)
【算法】哈希映射(C/C++)
|
3月前
|
机器学习/深度学习 人工智能 算法
【算法】最长公共子序列(C/C++)
【算法】最长公共子序列(C/C++)
|
3月前
|
人工智能 算法 BI
一篇带你速通差分算法(C/C++)
一篇带你速通差分算法(C/C++)
|
12天前
|
机器学习/深度学习 算法
基于改进遗传优化的BP神经网络金融序列预测算法matlab仿真
本项目基于改进遗传优化的BP神经网络进行金融序列预测,使用MATLAB2022A实现。通过对比BP神经网络、遗传优化BP神经网络及改进遗传优化BP神经网络,展示了三者的误差和预测曲线差异。核心程序结合遗传算法(GA)与BP神经网络,利用GA优化BP网络的初始权重和阈值,提高预测精度。GA通过选择、交叉、变异操作迭代优化,防止局部收敛,增强模型对金融市场复杂性和不确定性的适应能力。
145 80
|
6天前
|
机器学习/深度学习 算法
基于遗传优化的双BP神经网络金融序列预测算法matlab仿真
本项目基于遗传优化的双BP神经网络实现金融序列预测,使用MATLAB2022A进行仿真。算法通过两个初始学习率不同的BP神经网络(e1, e2)协同工作,结合遗传算法优化,提高预测精度。实验展示了三个算法的误差对比结果,验证了该方法的有效性。
|
8天前
|
机器学习/深度学习 数据采集 算法
基于PSO粒子群优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真
本项目展示了基于PSO优化的CNN-GRU-SAM网络在时间序列预测中的应用。算法通过卷积层、GRU层、自注意力机制层提取特征,结合粒子群优化提升预测准确性。完整程序运行效果无水印,提供Matlab2022a版本代码,含详细中文注释和操作视频。适用于金融市场、气象预报等领域,有效处理非线性数据,提高预测稳定性和效率。