一条包含字母 A-Z 的消息通过以下方式进行了编码:
'A' -> 1 'B' -> 2 ... 'Z' -> 26
给定一个只包含数字的非空字符串,请计算解码方法的总数。
public class Main { public static void main(String[] args) throws IOException { BufferedReader bf = new BufferedReader(new InputStreamReader(System.in)); String s = bf.readLine(); System.out.println(numDecodings(s)); } public static int numDecodings(String s) { if (s.charAt(0) == '0') return 0; int[] dp = new int[s.length() + 1]; dp[0] = dp[1] = 1; for (int i = 2; i <= s.length(); i++) { //如果该位不为'0',说明该位单独成字母合法 if (s.charAt(i - 1) != '0') { dp[i] += dp[i - 1]; } //如果后两位能组成"1x"(x为任意数字)或者"2x"(x小于7),说明最后两位组成字母合法 if ((s.charAt(i - 2) == '1') || (s.charAt(i - 2) == '2' && s.charAt(i - 1) <= '6')) { dp[i] += dp[i - 2]; } } return dp[s.length()]; } }
#include <iostream> using namespace std; int main(void){ string s; int len; cin>>s; len = s.length(); int *dp = new int[len+1]{}; dp[0] = 1; for(int i = 1; i <= len; ++i){ if(s[i-1] != '0') dp[i] += dp[i-1]; if(i >= 2 && s[i-2] == '1' || s[i-2] == '2' && s[i-1] < '7') dp[i] += dp[i-2]; } cout<<dp[len]<<endl; delete dp; return 0; }典型的动态规划问题,dp[i]表示数字串前i个数字所有的解码方案,从尾向头解码,取最后一个非0数字解码,dp[i]=d[i-1],如果i>=2并且最后两个数字组成的十进制数不大于26(十进制数不能以0开头),取最后两个数字解码,则dp[i]+=dp[i-2],注意这里初始化dp[0]=1,而其他值为0
""" 递归求解解码种数 满足条件10--26时 decoder(s[:]) = decoder(s[1:]) + decoder(s[2:]) 否则 decoder(s[:]) = decoder(s[1:]) """ import sys def decoder(s): if not s: return 1 ret = decoder(s[1:]) if len(s) >= 2: if ord(s[0]) == ord('1') or (ord(s[0]) == ord('2') and ord('0') <= ord(s[1]) <= ord('6')): ret += decoder(s[2:]) return ret if __name__ == "__main__": # sys.stdin = open("input.txt", "r") s = input().strip() ans = decoder(s) print(ans)
#include <iostream> #include <string> using namespace std; int main(int argc, char* argv[]){ string str; cin >> str; int f0 = 1, f1 = 1, f; for(int idx = 1; idx < str.length(); idx++){ int code = (str[idx-1]-'0')*10+(str[idx]-'0'); f = 0; if(code >= 1 && code <= 26) f += f0; if(str[idx] != '0') f += f1; f0 = f1; f1 = f; if(f1 == 0) break; } cout << f1 << endl; return 0; }
n = input() count = [0 for i in range(len(n))] if n=="0": print(0) else: if n[0]=="0": count[0]=0 else: count[0]=1 if n[1]!="0": t1=1 else: t1=0 if n[0]=="1" or (n[0]=="2" and int(n[1])<=6): t2=1 else: t2=0 count[1]=t1+t2 for i in range(2,len(n)): if n[i]!="0": count[i]+=count[i-1] if int(n[i-1:i+1])>=10 and int(n[i-1:i+1])<=26: count[i] +=count[i-2] print(count[len(n)-1])
解析:依然是将对应位置的结果存入数组中,记录状态。在每一个阶段时,考虑当前字符串是否可独立(是否为0),是否可与前一个字符串相结合这两种情况,如果可独立,这是的第i阶段的方法总数就加上前一阶段的方法总数,如果可合并就加上前两个阶段的方法总数,每一个阶段的初始化为零。
直接dp
1. import java.util.Scanner; 2. import static java.lang.System.in; 3. public class Main { 4. public static void main(String[] args) { 5. Scanner sc = new Scanner(in); 6. String n = sc.nextLine(); 7. System.out.println(dpProcess(n.toCharArray())); 8. } 9. public static int dpProcess(char[] str) { 10. int len = str.length; 11. int[] dp = new int[len + 1]; 12. dp[len] = 1; 13. dp[len - 1] = 1; 14. for (int i = len - 2; i >= 0; i--) { 15. if (str[i] == '1' || (str[i] == '2' && str[i + 1] <= '6')) { 16. dp[i] = dp[i + 1] + dp[i + 2]; 17. } 18. else{ 19. dp[i] = dp[i + 1]; 20. } 21. } 22. return dp[0]; 23. } 24. }
#include <bits/stdc++.h> using namespace std; int cnt = 0, l; void F(string s){ int m = s.length(); if(s=="" || m==0){ cnt++; return ; } if(m>=2 && (s[0]=='1' || (s[0]=='2' && s[1]<='6'))){ F(s.substr(2)); F(s.substr(1)); }else F(s.substr(1)); } int main(){ string s; while(cin>>s){ l = s.length(); F(s); cout<<cnt<<endl; } return 0; }
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); char[] str = br.readLine().toCharArray(); System.out.println(dfs(str, 0)); } private static int dfs(char[] str, int depth) { if(depth >= str.length){ // 字符串末尾匹配完了,增加一种翻译方案 return 1; }else{ if(str[depth] == '0'){ // 本层单独面对一个0,之前的翻译有误,这个0应该与前一个字符结合 return 0; } // 本层字符单独成为一种翻译 int ways = dfs(str, depth + 1); if(str[depth] == '1' && depth < str.length - 1){ // str[depth]与str[depth + 1]翻译成j~s ways += dfs(str, depth + 2); }else if(str[depth] == '2' && depth < str.length - 1 && (str[depth + 1] >= '0' && str[depth + 1] <= '6')){ // str[depth]与str[depth + 1]翻译成t~z ways += dfs(str, depth + 2); } return ways; } } }递归逻辑是最朴素直观的思考过程,有了递归逻辑,就可以很轻松地改出动态规划版本。
使用 dp,每个数字单独看待或者作为个位看待。
例如:12
这个 1 没什么说的:只能作为一个单独的数字看待。
这个 2 可分两种情况:
最后:因为 0 比较特殊(不能作为单独的数字存在),需要注意一下。
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String s = sc.nextLine().trim(); int[] dp = new int[s.length() + 1]; dp[0] = 1; for(int i = 0; i < s.length(); i ++) { char ch = s.charAt(i); dp[i + 1] = ch != '0' ? dp[i] : 0; if(i > 0 && (s.charAt(i - 1) == '1' || (s.charAt(i - 1) == '2' && ch <= '6'))) { dp[i + 1] += dp[i - 1]; } } System.out.println(dp[s.length()]); } }
package main import ( "fmt" ) func main(){ str := "" fmt.Scan(&str) n := len(str) dp := make([]int, n+2) dp[0] = 1 dp[1] = 2 for i := 2 ; i < n ; i++ { if str[i-1] <= '2' && str[i] <= '6' { dp[i] = dp[i-2] + dp[i-1] }else{ dp[i] = dp[i-1] } } fmt.Println(dp[n-1]) }
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String s = sc.nextLine(); System.out.println(DecodeCount(s)); } public static int DecodeCount(String strs){ int[] s = new int[strs.length()]; for(int i = 0; i < strs.length(); i++){ char c = strs.charAt(i); s[i] = c - '0'; } int[] dp = new int[strs.length()]; if(s[0] == 0) return 0; dp[0] = 1; if (s[0] * 10 + s[1] <= 26 && s[0] * 10 + s[1] > 0){ dp[1] = s[1] == 0 ? 1 : 2; }else{ if(s[1] == 0) return 0; dp[1] = 1; } for(int i = 2; i < s.length; i++){ if(s[i - 1] * 10 + s[i] <= 26 && s[i - 1] * 10 + s[i] > 0){ dp[i] = s[i] == 0 ? dp[i - 2] : dp[i - 2] + dp[i - 1]; }else{ if(s[i] == 0) return 0; dp[i] = dp[i - 1]; } } return dp[strs.length() - 1]; } }
//对于12122 可以组成四个两位数,则dp[4]=dp[4-4]*(2^4-2^3) //对于121 可以组成两个两位数 dp[2]=dp[2-2]*(2^2-2^1); //对于12 可以组成一个两位数 dp[1]=dp[1-1]*2; #include<iostream> #include<vector> #include<string> #include<math.h> using namespace std; int main() { string s; while (cin >> s) { vector<int> dp(s.size() + 1, 0); if (s.size() == 0) { cout << 0 << endl; break; } if (s.size() == 1) { cout << 1 << endl; break; } if (s.size() == 2) { int temp = s[0] - '0'; temp = temp * 10 + s[1] - '0'; if (temp <= 26 && temp >= 11) cout << 2 << endl; else cout << 1 << endl; break; } dp[0] = 1; int flag = 0; for (int i = 1; i <= s.size(); i++) { int temp = s[i - 1] - '0'; temp = temp * 10 + s[i] - '0'; if (temp <= 26 && temp >= 11) { if (flag) if (flag >= 2) dp[i] = dp[i - flag] * (pow(2, flag) - pow(2, flag - 1)); else dp[i] = dp[i - 1] + 1; else dp[i] = dp[i - 1] * 2; flag ++; } else { dp[i] = dp[i - 1]; flag = 0; } } cout << dp[s.size() - 1] << endl; } return 0; }
#include<bits/stdc++.h> using namespace std; int df1(int y); int df2(int y); int main(){ int n; cin>>n; int ans; ans = df1(n)+ df2(n); cout<<ans<<endl; return 0; } int df1(int y){ int x = y % 10; int z = y / 10; if( x == 0) return 0; if( y <= 9) return 1; return df1(z)+df2(z); } int df2(int y){ int x = y % 100; int z = y / 100; if(x <= 9 || x > 26) return 0; if(x <= 26 && z == 0) return 1; return df1(z) + df2(z); }
import java.util.*; public class Main{ public static void main(String[] args){ Scanner in=new Scanner(System.in); String num=in.next(); System.out.println(deCode(num)); } public static int deCode(String num){ int len=num.length(); int[] dp=new int[len]; dp[0]=1; String str=num.substring(0,2); int strnum=Integer.parseInt(str); if(strnum>=1&&strnum<=26){ dp[1]=2; }else{ dp[1]=1; } for(int i=2;i<len;i++){ String tmp=num.substring(i-1,i+1); int tmpnum=Integer.parseInt(tmp); if(tmpnum>=1&&tmpnum<=26){ dp[i]=dp[i-2]+dp[i-1]; }else{ dp[i]=dp[i-1]; } } return dp[len-1]; } }
ss = input() dpc = [-1]*len(ss) dpc[0] = 1 if int(ss[0:2])<=26 and int(ss[1])!=0: dpc[1] = 2 else: dpc[1] = 1 for i in range(2,len(ss)): if ss[i]==0: dpc[i] = dpc[i-1] else: if int(ss[i-1:i+1])<=26: dpc[i] = dpc[i-1] + dpc[i-2] else: dpc[i] = dpc[i-1] print(dpc[-1])
S = input() out = [0] for i in range(len(S)): if int(S[i])>2: out.append(i+1) if int(S[i])==2: if i<len(S)-1: if int(S[i+1])>6: out.append(i+1) out.append(len(S)) temp = [1,1,2] n = 3 num = 1 for i in range(len(out)-1): k = out[i+1]-out[i] while k>=n: temp.append(temp[n-1]+temp[n-2]) n += 1 num *= temp[k] print(num)
s = input() dp = [0] * len(s) dp[0] = 1 if s[0] != '0' else 0 dp[1] = dp[0] + (1 if int(s[:2]) <= 26 and s[:2] != '00' else 0) for i in range(2, len(s)): if s[i] != '0': dp[i] += dp[i-1] if s[i-1:i+1] != '00' and int(s[i-1:i+1]) <= 26: dp[i] += dp[i-2] print(dp[-1])
python 动态规划
import sys s=sys.stdin.readline().strip() n=len(s) dp=[1]*n if int(s[0]+s[1])<=26: dp[1]=2 for i in range(2,n): if int(s[i-1]+s[i])<=26: dp[i]=dp[i-1]+dp[i-2] else: dp[i]=dp[i-1] print(dp[-1])