作者推薦
【動(dòng)態(tài)規(guī)劃】【狀態(tài)壓縮】【2次選擇】【廣度搜索】1494. 并行課程 II
本文涉及知識(shí)點(diǎn)
動(dòng)態(tài)規(guī)劃匯總
LeetCode1987:不同的好子序列數(shù)目
給你一個(gè)二進(jìn)制字符串 binary 。 binary 的一個(gè) 子序列 如果是 非空 的且沒有 前導(dǎo) 0 (除非數(shù)字是 “0” 本身),那么它就是一個(gè) 好 的子序列。
請(qǐng)你找到 binary 不同好子序列 的數(shù)目。
比方說,如果 binary = “001” ,那么所有 好 子序列為 [“0”, “0”, “1”] ,所以 不同 的好子序列為 “0” 和 “1” 。 注意,子序列 “00” ,“01” 和 “001” 不是好的,因?yàn)樗鼈冇星皩?dǎo) 0 。
請(qǐng)你返回 binary 中 不同好子序列 的數(shù)目。由于答案可能很大,請(qǐng)將它對(duì) 109 + 7 取余 后返回。
一個(gè) 子序列 指的是從原數(shù)組中刪除若干個(gè)(可以一個(gè)也不刪除)元素后,不改變剩余元素順序得到的序列。
示例 1:
輸入:binary = “001”
輸出:2
解釋:好的二進(jìn)制子序列為 [“0”, “0”, “1”] 。
不同的好子序列為 “0” 和 “1” 。
示例 2:
輸入:binary = “11”
輸出:2
解釋:好的二進(jìn)制子序列為 [“1”, “1”, “11”] 。
不同的好子序列為 “1” 和 “11” 。
示例 3:
輸入:binary = “101”
輸出:5
解釋:好的二進(jìn)制子序列為 [“1”, “0”, “1”, “10”, “11”, “101”] 。
不同的好子序列為 “0” ,“1” ,“10” ,“11” 和 “101” 。
提示:
1 <= binary.length <= 105
binary 只含有 ‘0’ 和 ‘1’ 。
動(dòng)態(tài)規(guī)劃
除0外,不存在以0開始的子序列。如果存在0,則必定存在子序列{0}。以下的分析排除{0}。
排除{0}后任意合法子序列在后面增加0或1,都是合法子序列。
動(dòng)態(tài)規(guī)劃的狀態(tài)表示
pre[0] 從binary[0,i)中選擇若干字符,形成以0結(jié)束的合法子序列數(shù)量。pre[1]以1結(jié)束的子序列數(shù)量。
dp和pre類似,對(duì)應(yīng)的是binary[0,i+1)。
動(dòng)態(tài)規(guī)劃的轉(zhuǎn)移方程
binary[i]為1
{
p
r
e
[
0
]
不選擇當(dāng)前字符,以
0
結(jié)束的字符數(shù)量
情況一
p
r
e
[
1
]
不選擇當(dāng)前字符,以
1
結(jié)束的字符數(shù)
情況二
p
r
e
[
0
]
+
p
r
e
[
1
]
+
1
選擇當(dāng)前字符,以
1
結(jié)束的字符數(shù)量。
情況三
\begin{cases} pre[0] & 不選擇當(dāng)前字符,以0結(jié)束的字符數(shù)量 & 情況一 \\ pre[1] & 不選擇當(dāng)前字符,以1結(jié)束的字符數(shù) & 情況二 \\ pre[0]+pre[1]+1 & 選擇當(dāng)前字符,以1結(jié)束的字符數(shù)量。 & 情況三 \\ \end{cases}
?
?
??pre[0]pre[1]pre[0]+pre[1]+1?不選擇當(dāng)前字符,以0結(jié)束的字符數(shù)量不選擇當(dāng)前字符,以1結(jié)束的字符數(shù)選擇當(dāng)前字符,以1結(jié)束的字符數(shù)量。?情況一情況二情況三?
情況三又可以分三種情況:
{
p
r
e
[
0
]
倒數(shù)第二個(gè)字符是
0
情況三一
p
r
e
[
1
]
倒數(shù)第二個(gè)字符是
1
情況三二
1
子序列
1
。
情況三三
\begin{cases} pre[0] & 倒數(shù)第二個(gè)字符是0 & 情況三一 \\ pre[1] & 倒數(shù)第二個(gè)字符是1 & 情況三二 \\ 1 & 子序列{1}。 & 情況三三 \\ \end{cases}
?
?
??pre[0]pre[1]1?倒數(shù)第二個(gè)字符是0倒數(shù)第二個(gè)字符是1子序列1。?情況三一情況三二情況三三?
情況一、情況二、情況三 內(nèi)部不存在重復(fù)情況。
情況一以0結(jié)尾,情況二、三以1結(jié)尾,所以情況一和情況二(三)不會(huì)重復(fù)。
情況二所有的情況都和情況三重合,情況二分類:
{
倒數(shù)第二個(gè)字符是
0
被情況三一包含
倒數(shù)第二個(gè)字符是
1
被情況三二包含
子序列
1
。
和情況三三重復(fù)
\begin{cases} 倒數(shù)第二個(gè)字符是0 & 被情況三一包含 \\ 倒數(shù)第二個(gè)字符是1 & 被情況三二包含 \\ 子序列{1}。 & 和情況三三 重復(fù)\\ \end{cases}
?
?
??倒數(shù)第二個(gè)字符是0倒數(shù)第二個(gè)字符是1子序列1。?被情況三一包含被情況三二包含和情況三三重復(fù)?
總結(jié):
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]
動(dòng)態(tài)規(guī)劃的初始值
pre 全為0。
動(dòng)態(tài)規(guī)劃的返回值
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();
}
};
擴(kuò)展閱讀
視頻課程
有效學(xué)習(xí):明確的目標(biāo) 及時(shí)的反饋 拉伸區(qū)(難度合適),可以先學(xué)簡單的課程,請(qǐng)移步CSDN學(xué)院,聽白銀講師(也就是鄙人)的講解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成戰(zhàn)斗了,為老板分憂,請(qǐng)學(xué)習(xí)C#入職培訓(xùn)、C++入職培訓(xùn)等課程
https://edu.csdn.net/lecturer/6176
相關(guān)
下載
想高屋建瓴的學(xué)習(xí)算法,請(qǐng)下載《喜缺全書算法冊(cè)》doc版
https://download.csdn.net/download/he_zhidan/88348653
我想對(duì)大家說的話 |
---|
聞缺陷則喜是一個(gè)美好的愿望,早發(fā)現(xiàn)問題,早修改問題,給老板節(jié)約錢。 |
子墨子言之:事無終始,無務(wù)多業(yè)。也就是我們常說的專業(yè)的人做專業(yè)的事。 |
如果程序是一條龍,那算法就是他的是睛 |
測(cè)試環(huán)境
操作系統(tǒng):win7 開發(fā)環(huán)境: VS2019 C++17
或者 操作系統(tǒng):win10 開發(fā)環(huán)境: VS2022 C++17
如無特殊說明,本算法用**C++**實(shí)現(xiàn)。文章來源:http://www.zghlxwxcb.cn/news/detail-832295.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-832295.html
到了這里,關(guān)于【動(dòng)態(tài)規(guī)劃】【子序列除重】【C++算法】1987不同的好子序列數(shù)目的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!