首页 > 试题广场 >

解码方法

[编程题]解码方法
  • 热度指数:7864 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解

一条包含字母 A-Z 的消息通过以下方式进行了编码:

'A' -> 1
'B' -> 2
...
'Z' -> 26

给定一个只包含数字的非空字符串,请计算解码方法的总数。


输入描述:
12可以解码成“AB”,“L”这两种


输出描述:
解码方法的总数
示例1

输入

12

输出

2

说明

12可以解码成“AB”,“A,B"这两种 
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()];
    }
}
发表于 2019-08-15 18:57:21 回复(0)
#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
编辑于 2019-08-29 10:54:33 回复(1)
"""
递归求解解码种数
满足条件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)

发表于 2019-07-11 10:00:23 回复(3)
#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;
}

编辑于 2020-04-11 20:46:44 回复(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阶段的方法总数就加上前一阶段的方法总数,如果可合并就加上前两个阶段的方法总数,每一个阶段的初始化为零。


发表于 2019-09-22 16:09:16 回复(0)

直接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. }
发表于 2019-08-02 20:25:49 回复(0)
#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;
}

发表于 2019-07-10 07:46:49 回复(0)
动态规划的思想:
当前位置的编码方式需要根据前面的步骤来计算;
举例:
1226
当前位置:1   -->编码方式: 1  
当前位置:2   -->编码方式:1  2 ; 12
当前位置:2   -->编码方式:1 2 2 ;12 2 ;1 22
当前位置:6   -->编码方式:1 2 2 6 ; 12 2 6 ; 1 22 6 ; 1 2 26 ; 12 26
规律总结:
如果当前数字不是0,则判断 它和前一位数字组合是否大于26,如果不大于26,则可以通过组合形式形成新的编码方法,如果和前一位组合后大于26,则只能单独出道;可以看出,如果可以组合,则是在dp[i-2] 的基础上进行组合,如果不能组合即单独出道,即在dp[i-1] 的基础上单独出道,如果又能单独出道又能组合,则dp[i] = dp[i-1] + dp[i-2]
发表于 2020-03-22 23:22:31 回复(0)

暴力递归

从左往右尝试:(1) 如果尝试到字符串末尾了就生成一种可行的翻译方案;(2) 如果遇到0,则当前翻译错误;(3) 如果当前遇到1,看是否能与下一个字符组合起来翻译成j~s;(4) 如果遇到2,看是否能与下一个字符组合起来翻译成t~z;(5) 否则只能当前字符单独翻译成某个字符。
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;
        }
    }
}
递归逻辑是最朴素直观的思考过程,有了递归逻辑,就可以很轻松地改出动态规划版本。
发表于 2022-01-17 10:46:39 回复(0)

使用 dp,每个数字单独看待或者作为个位看待。

例如:12

  1. 这个 1 没什么说的:只能作为一个单独的数字看待。

  2. 这个 2 可分两种情况:

    1. 单独作为数字 2 。
    2. 作为数字 12 的个位数字。

最后:因为 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()]);
    }
}
编辑于 2019-08-12 02:08:43 回复(0)
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])
}

发表于 2023-09-18 21:14:30 回复(0)
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];
    }
}

编辑于 2022-04-02 15:00:27 回复(0)
//对于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;
}


编辑于 2020-12-22 20:31:03 回复(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);
}
从后往前推,分别除以10和100,对应有两种情况:只能一位一位地编码和只能两位两位的编码:
1、当一位一位编码时:如果此位为0,不能编码,返回0;如果此位前面的高位是0到9以内的,则可以结束,返回1;都不是,继续求商和余数来编码。
2、当两位两位编码时:如果此两位小于10或大于26,不能编码,返回0;如果此两位前面没有最高位了,则返回1;否则继续求商和余数来编码。
编辑于 2020-09-18 20:34:47 回复(0)
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];
    }
}

发表于 2020-04-28 21:13:35 回复(0)
动态规划,f[i]=f[i-1]+f[i-2]注意边界和限定条件。
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])


发表于 2020-04-03 10:34:14 回复(0)
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)


编辑于 2019-11-27 17:48:21 回复(0)
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 动态规划

发表于 2019-10-19 11:49:11 回复(0)
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])

发表于 2019-09-14 19:44:31 回复(0)