给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。
示例:
s = "3[a]2[bc]", 返回 "aaabcbc".
s = "3[a2[c]]", 返回 "accaccacc".
s = "2[abc]3[cd]ef", 返回 "abcabccdcdcdef".
class Solution {//栈
public:
string decodeString(string s) {
int sSize=s.size();
stack<pair<int,string>>st;
string res;
int cnt=0;
for(int i=0;i<sSize;++i){
if(isdigit(s[i])){
cnt=cnt*10+(s[i]-'0');//cnt重复次数
}
else if(s[i]=='['){
st.push(make_pair(cnt,res));//依此把(下一个要字符串要重复的次数入栈,当前[字符前的所有正确解码的字符串)入栈
cnt=0;
res="";
}
else if(s[i]==']'){
pair p=st.top();
st.pop();
for(int j=0;j<p.first;++j)//重复cnt次
p.second+=res;
res=p.second;//当前所有正确解码的字符串
}
else res+=s[i];
}
return res;
}
};
题目是这样:你面前有一栋从 1 到 N
共 N
层的楼,然后给你 K
个鸡蛋(K
至少为 1)。现在确定这栋楼存在楼层 0 <= F <= N
,在这层楼将鸡蛋扔下去,鸡蛋恰好没摔碎(高于 F
的楼层都会碎,低于 F
的楼层都不会碎)。现在问你,最坏情况下,你至少要扔几次鸡蛋,才能确定这个楼层 F
呢?
对动态规划问题,直接套我们以前多次强调的框架即可:这个问题有什么「状态」,有什么「选择」,然后穷举。
「状态」很明显,就是当前拥有的鸡蛋数 K
和需要测试的楼层数 N
。随着测试的进行,鸡蛋个数可能减少,楼层的搜索范围会减小,这就是状态的变化。
「选择」其实就是去选择哪层楼扔鸡蛋。回顾刚才的线性扫描和二分思路,二分查找每次选择到楼层区间的中间去扔鸡蛋,而线性扫描选择一层层向上测试。不同的选择会造成状态的转移。
现在明确了「状态」和「选择」,动态规划的基本思路就形成了:肯定是个二维的 dp
数组或者带有两个状态参数的 dp
函数来表示状态转移;外加一个 for 循环来遍历所有选择,择最优的选择更新状态:
# 当前状态为 K 个鸡蛋,面对 N 层楼
# 返回这个状态下的最优结果
def dp(K, N):
int res
for 1 <= i <= N:
res = min(res, 这次在第 i 层楼扔鸡蛋)
return res
这段伪码还没有展示递归和状态转移,不过大致的算法框架已经完成了。
我们选择在第 i
层楼扔了鸡蛋之后,可能出现两种情况:鸡蛋碎了,鸡蛋没碎。注意,这时候状态转移就来了:
如果鸡蛋碎了,那么鸡蛋的个数 K
应该减一,搜索的楼层区间应该从 [1..N]
变为 [1..i-1]
共 i-1
层楼;
如果鸡蛋没碎,那么鸡蛋的个数 K
不变,搜索的楼层区间应该从 [1..N]
变为 [i+1..N]
共 N-i
层楼。
dp[1~K][0~N]:k次扔鸡蛋,n层楼
vector<vector<int>>dp(K+1,vector<int>(N+1,0));
for(int i=0;i<=N;++i)
dp[1][i]=i;
for(int k=2;k<=K;++K)
for(int n=1;n<=N;++n)
for(int i=1;i<=N;++i)
res=min(res,1+max(dp[k][n-i],dp[k-1][i-1]));//在第i层扔鸡蛋没碎和碎的情况
return res;
二分优化
dp[1~K][0~N]:k次扔鸡蛋,n层楼
vector<vector<int>>dp(K+1,vector<int>(N+1,0));
for(int i=0;i<=N;++i)
dp[1][i]=i;
for(int k=2;k<=K;++K)
for(int n=1;n<=N;++n){
int le=1,ri=N;
while(le<=ri){
int mid=le+((ri-le)>>1);
if(dp[k][n-i]>dp[k-1][i-1])
le=mid+1,res=min(res,1+dp[k][n-i]);
else
ri=mid-1,res=min(res,1+dp[k-1][i-1]);
}
}
return res;