剑指 Offer 46. 把数字翻译成字符串
动态规划:
方法一:字符串遍历
1.先将num转成字符串,方便后续处理,因为我们需要精确到每一位数字
2.状态定义:dp[i]:以s[i-1]为结尾的数字(即从头开始总共i位数)的翻译方案数量,
3.转移方程:s[i-1]s[i]组成的两位数字可以被翻译,则dp[i]=dp[i-1]+dp[i-2];否则,dp[i]=dp[i-1]
4.注意:如果s[i-1]=0,组成的两位数无法被翻译;因此翻译范围:10~25(包括边界)
5.定义初始状态:dp[0]=dp[1]=1;dp[0]表示无数字的时候。
6.那么dp[0]=1从何而来呢?
6.1 s[0]和s[1]组成两位数属于10~25时,dp[2]=2,而dp[2]=dp[1]+dp[0] => dp[0]=1;
6.2 s[0]和s[1]组成两位数不属于10~25时,dp[2]=dp[1]=1,不关dp[0]的事
7.由于从始至终我们只需要3个变量:dp[i],dp[i-1],dp[i-2],因此我们用变量c,b,a分别去对应这三个状态,
从而减少空间的开销
class Solution {
public:
int translateNum(int num) {
//先将num转字符串,方便后续处理
string numStr=to_string(num);
//定义dp[0]
int a=1;
//定义dp[1]
int b=1;
//从i=2开始,即开始算dp[2],即以s[2-1]结尾的数
for(int i=2;i<=numStr.length();i++){
string tmpStr=numStr.substr(i-2,2);
int tmpVal=atoi(tmpStr.c_str());
int c=tmpVal>=10&&tmpVal<=25?a+b:b;
a=b;
b=c;
}
return b;
}
};
方法二:数字求余
相比于方法一,方法二少了额外的整数转字符串的空间开销,只用了常数个变量就完成了
class Solution {
public:
int translateNum(int num) {
int a=1,b=1;
//从右向左计算翻译数量
while(num>9){
int c=num%100>=10&&num%100<=25?a+b:a;
b=a;
a=c;
num/=10;
}
return a;
}
};
剑指 Offer 48. 最长不含重复字符的子字符串
方法一:滑动窗口
class Solution {
public:
int lengthOfLongestSubstring(string s) {
//用于判断字符c是否已经存在于哈希表中了
unordered_set<char>st;
//s的长度
int length=s.length();
//记录最长无重复字符子串的长度
int maxLen=0;
//用于滑动
int right=-1;
//遍历字符串
for(int i=0;i<length&&right+1<length;i++){
if(i!=0){
st.erase(s[i-1]);
}
while(right+1<length&&st.count(s[right+1])==0){
st.insert(s[right+1]);
right++;
}
maxLen=max(maxLen,right-i+1);
}
return maxLen;
}
};