📌  相关文章
📜  计算具有隐藏字符的给定数字序列的可能解码

📅  最后修改于: 2021-09-22 09:57:43             🧑  作者: Mango

给定一个包含数字和字符“*”(即隐藏字符)的字符串S ,任务是找到对给定字符串的这个隐藏字符进行解码的方法数。

由于答案可能非常大,将其取10 9 +7 返回。

例子:

方法:

这个问题可以通过观察到任何恒定数目可以在字符被任一解码这是一个单位的数字,或者它可以被解码成一个双位的数字,如果第(i-1)个字符为“1”或来解决(第i-1)个字符是‘2’第i个字符在1到6之间因此,当前状态依赖于前一个状态,可以使用动态规划来解决这个问题。请按照以下步骤解决问题:

1. 让dp[i]表示解码从0i的字符串字符的方法数。

2. 如果第i 个字符是‘*’ :

  • dp[i] = dp[i-1]*9考虑到‘*’可以是1 到 9 ,单独作为一个字符来考虑。
  • 现在,如果ii-1字符组合在一起,那么,
    • 如果第(i-1) 个字符是‘*’,那么两个“**”一起可以形成15 个可能的字符(如 13 将形成字符’M’),因此我们将15×dp[i-2] 添加dp[我]
    • 如果第(i-1) 个字符是‘1’dp[i] = dp[i] + 9×dp[i-2]因为可以解码的可能字符是11 到 19 (K 到 S)。
    • 如果第(i-1) 个字符是‘2’dp[i] = dp[i] + 6×dp[i-2]因为它可以取21 到 26 之间的

3.如果第i个字符不是‘*’:

  • dp[i] = dp[i] + dp[i-1]第 i 个字符单独视为一个数字。
  • 现在,如果可以将第(i-1) 个字符和第 i 个字符组合在一起,则将dp[i-2] 添加到 dp[i]。

下面是上述方法的实现:

C++
#include 
using namespace std;
 
int M = 1000000007;
int waysOfDecoding(string s)
{
 
    vector dp((int)s.size()+1);
    dp[0] = 1;
 
    // check the first character of the string
    // if it is '*' then 9 ways
 
    dp[1] = s[0] == '*'
                ? 9
                : s[0] == '0' ? 0 : 1;
 
    // traverse the string
    for (int i = 1; i < (int)s.size(); i++) {
 
        // If s[i] == '*' there can be
        // 9 possible values of *
        if (s[i] == '*') {
            dp[i + 1] = 9 * dp[i];
 
            // If previous character is 1
            // then words that can be formed
            // are K(11), L(12), M(13), N(14)
            // O(15), P(16), Q(17), R(18), S(19)
            if (s[i - 1] == '1')
                dp[i + 1]
                    = (dp[i + 1] + 9 * dp[i - 1]) % M;
 
            // If previous character is 2
            // then the words that can be formed
            // are U(21), V(22), W(23), X(24)Y(25), Z(26)
            else if (s[i - 1] == '2')
                dp[i + 1]
                    = (dp[i + 1] + 6 * dp[i - 1]) % M;
 
            // If the previous digit is * then
            // all 15 2- digit characters can be
            // formed
            else if (s[i - 1] == '*')
                dp[i + 1]
                    = (dp[i + 1] + 15 * dp[i - 1]) % M;
        }
        else {
            // taking the value from previous step
            dp[i + 1] = s[i] != '0' ? dp[i] : 0;
 
            // If previous character is 1 then
            // the i-1th character and ith
            // character can be decoded in
            // a single character therefore,
            // adding dp[i-1].
            if (s[i - 1] == '1')
                dp[i + 1]
                    = (dp[i + 1] + dp[i - 1])
                      % M;
 
            // If previous character is 2
            // and ith character is less than
            // 6
            // then the i-1th character and
            // ith character can be decoded in
            // a single character therefore,
            // adding dp[i-1].
            else if (s[i - 1] == '2'
                     && s[i] <= '6')
                dp[i + 1]
                    = (dp[i + 1] + dp[i - 1]) % M;
 
            // If previous character is * then
            // it will contain the above 2 cases
            else if (s[i - 1] == '*')
                dp[i + 1]
                    = (dp[i + 1]
                       + (s[i] <= '6' ? 2 : 1)
                             * dp[i - 1])
                      % M;
        }
    }
    return dp[(int)s.size()];
}
 
int main()
{
  string s = "12";
  cout<


Java
// Java program for the above approach
 
import java.io.*;
 
class GFG {
    static int M = 1000000007;
    static int waysOfDecoding(String s)
    {
 
        long[] dp = new long[s.length() + 1];
        dp[0] = 1;
 
        // check the first character of the string
        // if it is '*' then 9 ways
 
        dp[1] = s.charAt(0) == '*'
                    ? 9
                    : s.charAt(0) == '0' ? 0 : 1;
 
        // traverse the string
        for (int i = 1; i < s.length(); i++) {
 
            // If s[i] == '*' there can be
            // 9 possible values of *
            if (s.charAt(i) == '*') {
                dp[i + 1] = 9 * dp[i];
 
                // If previous character is 1
                // then words that can be formed
                // are K(11), L(12), M(13), N(14)
                // O(15), P(16), Q(17), R(18), S(19)
                if (s.charAt(i - 1) == '1')
                    dp[i + 1]
                        = (dp[i + 1] + 9 * dp[i - 1]) % M;
 
                // If previous character is 2
                // then the words that can be formed
                // are U(21), V(22), W(23), X(24)Y(25), Z(26)
                else if (s.charAt(i - 1) == '2')
                    dp[i + 1]
                        = (dp[i + 1] + 6 * dp[i - 1]) % M;
 
                // If the previous digit is * then
                // all 15 2- digit characters can be
                // formed
                else if (s.charAt(i - 1) == '*')
                    dp[i + 1]
                        = (dp[i + 1] + 15 * dp[i - 1]) % M;
            }
            else {
                // taking the value from previous step
                dp[i + 1] = s.charAt(i) != '0' ? dp[i] : 0;
 
                // If previous character is 1 then
                // the i-1th character and ith
                // character can be decoded in
                // a single character therefore,
                // adding dp[i-1].
                if (s.charAt(i - 1) == '1')
                    dp[i + 1]
                        = (dp[i + 1] + dp[i - 1])
                          % M;
 
                // If previous character is 2
                // and ith character is less than
                // 6
                // then the i-1th character and
                // ith character can be decoded in
                // a single character therefore,
                // adding dp[i-1].
                else if (s.charAt(i - 1) == '2'
                         && s.charAt(i) <= '6')
                    dp[i + 1]
                        = (dp[i + 1] + dp[i - 1]) % M;
 
                // If previous character is * then
                // it will contain the above 2 cases
                else if (s.charAt(i - 1) == '*')
                    dp[i + 1]
                        = (dp[i + 1]
                           + (s.charAt(i) <= '6' ? 2 : 1)
                                 * dp[i - 1])
                          % M;
            }
        }
        return (int)dp[s.length()];
    }
    public static void main(String[] args)
    {
        String s = "12";
        System.out.println(waysOfDecoding(s));
    }
}


C#
// C# program for the above approach
using System;
 
class GFG{
     
static int M = 1000000007;
static int waysOfDecoding(String s)
{
    long[] dp = new long[s.Length + 1];
    dp[0] = 1;
 
    // Check the first character of the string
    // if it is '*' then 9 ways
    dp[1] = s[0] == '*' ? 9 : s[0] == '0' ? 0 : 1;
 
    // Traverse the string
    for(int i = 1; i < s.Length; i++)
    {
         
        // If s[i] == '*' there can be
        // 9 possible values of *
        if (s[i] == '*')
        {
            dp[i + 1] = 9 * dp[i];
 
            // If previous character is 1
            // then words that can be formed
            // are K(11), L(12), M(13), N(14)
            // O(15), P(16), Q(17), R(18), S(19)
            if (s[i - 1] == '1')
                dp[i + 1] = (dp[i + 1] + 9 *
                             dp[i - 1]) % M;
 
            // If previous character is 2
            // then the words that can be formed
            // are U(21), V(22), W(23), X(24)Y(25),
            // Z(26)
            else if (s[i - 1] == '2')
                dp[i + 1] = (dp[i + 1] + 6 *
                             dp[i - 1]) % M;
 
            // If the previous digit is * then
            // all 15 2- digit characters can be
            // formed
            else if (s[i - 1] == '*')
                dp[i + 1] = (dp[i + 1] + 15 *
                             dp[i - 1]) % M;
        }
        else
        {
             
            // Taking the value from previous step
            dp[i + 1] = s[i] != '0' ? dp[i] : 0;
 
            // If previous character is 1 then
            // the i-1th character and ith
            // character can be decoded in
            // a single character therefore,
            // adding dp[i-1].
            if (s[i - 1] == '1')
                dp[i + 1] = (dp[i + 1] + dp[i - 1]) % M;
 
            // If previous character is 2
            // and ith character is less than
            // 6
            // then the i-1th character and
            // ith character can be decoded in
            // a single character therefore,
            // adding dp[i-1].
            else if (s[i - 1] == '2' && s[i] <= '6')
                dp[i + 1] = (dp[i + 1] + dp[i - 1]) % M;
 
            // If previous character is * then
            // it will contain the above 2 cases
            else if (s[i - 1] == '*')
                dp[i + 1] = (dp[i + 1] + (s[i] <= '6' ? 2 : 1) *
                             dp[i - 1]) % M;
        }
    }
    return (int)dp[s.Length];
}
 
// Driver code
public static void Main()
{
    String s = "12";
    Console.WriteLine(waysOfDecoding(s));
}
}
 
// This code is contributed by rishavmahato348


Javascript


C++
// C++ program for the above approach
#include 
using namespace std;
 
int M = 1000000007;
int waysOfDecoding(string s)
{
    long first = 1,
    second = s[0] == '*' ? 9 : s[0] == '0' ? 0 : 1;
     
    for(int i = 1; i < s.size(); i++)
    {
        long temp = second;
 
        // If s[i] == '*' there can be
        // 9 possible values of *
        if (s[i] == '*')
        {
            second = 9 * second;
             
            // If previous character is 1
            // then words that can be formed
            // are K(11), L(12), M(13), N(14)
            // O(15), P(16), Q(17), R(18), S(19)
            if (s[i - 1] == '1')
                second = (second + 9 * first) % M;
 
            // If previous character is 2
            // then the words that can be formed
            // are U(21), V(22), W(23), X(24)Y(25), Z(26)
            else if (s[i - 1] == '2')
                second = (second + 6 * first) % M;
 
            // If the previous digit is * then
            // all 15 2- digit characters can be
            // formed
            else if (s[i - 1] == '*')
                second = (second + 15 * first) % M;
        }
         
        // If s[i] != '*'
        else
        {
            second = s[i] != '0' ? second : 0;
 
            // Adding first in second
            // if s[i-1]=1
            if (s[i - 1] == '1')
                second = (second + first) % M;
 
            // Adding first in second if
            // s[i-1] == 2 and s[i]<='6'
            else if (s[i - 1] == '2' && s[i] <= '6')
                second = (second + first) % M;
 
            // If s[i-1] == '*' the union
            // of above 2 cases has to be done
            else if (s[i - 1] == '*')
                second = (second + (s[i] <= '6' ? 2 : 1) *
                          first) % M;
        }
        first = temp;
    }
    return(int)second;
}
 
// Driver code
int main()
{
    string s = "*";
    cout << waysOfDecoding(s);
    return 0;
}
 
// This code is contributed by rishavmahato348


Java
// Java program for the above approach
import java.io.*;
 
class GFG {
    static int M = 1000000007;
    static int waysOfDecoding(String s)
    {
        long first = 1, second
                        = s.charAt(0) == '*'
                              ? 9
                              : s.charAt(0) == '0' ? 0 : 1;
        for (int i = 1; i < s.length(); i++) {
            long temp = second;
 
            // If s[i] == '*' there can be
            // 9 possible values of *
            if (s.charAt(i) == '*') {
                second = 9 * second;
 
                // If previous character is 1
                // then words that can be formed
                // are K(11), L(12), M(13), N(14)
                // O(15), P(16), Q(17), R(18), S(19)
                if (s.charAt(i - 1) == '1')
                    second = (second + 9 * first) % M;
 
                // If previous character is 2
                // then the words that can be formed
                // are U(21), V(22), W(23), X(24)Y(25), Z(26)
                else if (s.charAt(i - 1) == '2')
                    second = (second + 6 * first) % M;
 
                // If the previous digit is * then
                // all 15 2- digit characters can be
                // formed
                else if (s.charAt(i - 1) == '*')
                    second = (second + 15 * first) % M;
            }
            // If s[i] != '*'
            else {
                second = s.charAt(i) != '0' ? second : 0;
 
                // Adding first in second
                // if s[i-1]=1
                if (s.charAt(i - 1) == '1')
                    second = (second + first) % M;
 
                // Adding first in second if
                // s[i-1] == 2 and s[i]<='6'
                else if (s.charAt(i - 1) == '2'
                         && s.charAt(i) <= '6')
                    second = (second + first) % M;
 
                // if s[i-1] == '*' the union
                // of above 2 cases has to be done
                else if (s.charAt(i - 1) == '*')
                    second = (second
                              + (s.charAt(i) <= '6' ? 2 : 1)
                                    * first)
                             % M;
            }
            first = temp;
        }
        return (int)second;
    }
    public static void main(String[] args)
    {
        String s = "*";
        System.out.println(waysOfDecoding(s));
    }
}


C#
// C# program for the above approach
using System;
 
class GFG{
     
static int M = 1000000007;
 
static int waysOfDecoding(string s)
{
    long first = 1,
    second = s[0] == '*' ? 9 : s[0] == '0' ? 0 : 1;
    for(int i = 1; i < s.Length; i++)
    {
        long temp = second;
 
        // If s[i] == '*' there can be
        // 9 possible values of *
        if (s[i] == '*')
        {
            second = 9 * second;
 
            // If previous character is 1
            // then words that can be formed
            // are K(11), L(12), M(13), N(14)
            // O(15), P(16), Q(17), R(18), S(19)
            if (s[i - 1] == '1')
                second = (second + 9 * first) % M;
 
            // If previous character is 2
            // then the words that can be formed
            // are U(21), V(22), W(23), X(24)Y(25), Z(26)
            else if (s[i - 1] == '2')
                second = (second + 6 * first) % M;
 
            // If the previous digit is * then
            // all 15 2- digit characters can be
            // formed
            else if (s[i - 1] == '*')
                second = (second + 15 * first) % M;
        }
         
        // If s[i] != '*'
        else
        {
            second = s[i] != '0' ? second : 0;
 
            // Adding first in second
            // if s[i-1]=1
            if (s[i - 1] == '1')
                second = (second + first) % M;
 
            // Adding first in second if
            // s[i-1] == 2 and s[i]<='6'
            else if (s[i - 1] == '2' && s[i] <= '6')
                second = (second + first) % M;
 
            // if s[i-1] == '*' the union
            // of above 2 cases has to be done
            else if (s[i - 1] == '*')
                second = (second + (s[i] <= '6' ? 2 : 1) *
                          first) % M;
        }
        first = temp;
    }
    return (int)second;
}
 
// Driver code
static public void Main()
{
    string s = "*";
     
    Console.WriteLine(waysOfDecoding(s));
}
}
 
// This code is contributed by patel2127


Javascript


输出
2

时间复杂度: O(n)
辅助空间: O(n)

进一步优化空间

如果仔细观察上面的代码,会发现dp[i]的值是使用dp[i-1]dp[i-2] 找到的。所以为了进一步优化空间,我们可以使用三个变量,而不是创建一个长度为Ndp数组——第二个(存储dp[i]的值),第一个(存储dp[i-2] 的值),和temp (存储dp[i-1] 的值)。因此,在找到second(dp[i])的值后,修改first = temptemp = second ,然后使用变量firsttemp再次计算second(dp[i])的值。

C++

// C++ program for the above approach
#include 
using namespace std;
 
int M = 1000000007;
int waysOfDecoding(string s)
{
    long first = 1,
    second = s[0] == '*' ? 9 : s[0] == '0' ? 0 : 1;
     
    for(int i = 1; i < s.size(); i++)
    {
        long temp = second;
 
        // If s[i] == '*' there can be
        // 9 possible values of *
        if (s[i] == '*')
        {
            second = 9 * second;
             
            // If previous character is 1
            // then words that can be formed
            // are K(11), L(12), M(13), N(14)
            // O(15), P(16), Q(17), R(18), S(19)
            if (s[i - 1] == '1')
                second = (second + 9 * first) % M;
 
            // If previous character is 2
            // then the words that can be formed
            // are U(21), V(22), W(23), X(24)Y(25), Z(26)
            else if (s[i - 1] == '2')
                second = (second + 6 * first) % M;
 
            // If the previous digit is * then
            // all 15 2- digit characters can be
            // formed
            else if (s[i - 1] == '*')
                second = (second + 15 * first) % M;
        }
         
        // If s[i] != '*'
        else
        {
            second = s[i] != '0' ? second : 0;
 
            // Adding first in second
            // if s[i-1]=1
            if (s[i - 1] == '1')
                second = (second + first) % M;
 
            // Adding first in second if
            // s[i-1] == 2 and s[i]<='6'
            else if (s[i - 1] == '2' && s[i] <= '6')
                second = (second + first) % M;
 
            // If s[i-1] == '*' the union
            // of above 2 cases has to be done
            else if (s[i - 1] == '*')
                second = (second + (s[i] <= '6' ? 2 : 1) *
                          first) % M;
        }
        first = temp;
    }
    return(int)second;
}
 
// Driver code
int main()
{
    string s = "*";
    cout << waysOfDecoding(s);
    return 0;
}
 
// This code is contributed by rishavmahato348

Java

// Java program for the above approach
import java.io.*;
 
class GFG {
    static int M = 1000000007;
    static int waysOfDecoding(String s)
    {
        long first = 1, second
                        = s.charAt(0) == '*'
                              ? 9
                              : s.charAt(0) == '0' ? 0 : 1;
        for (int i = 1; i < s.length(); i++) {
            long temp = second;
 
            // If s[i] == '*' there can be
            // 9 possible values of *
            if (s.charAt(i) == '*') {
                second = 9 * second;
 
                // If previous character is 1
                // then words that can be formed
                // are K(11), L(12), M(13), N(14)
                // O(15), P(16), Q(17), R(18), S(19)
                if (s.charAt(i - 1) == '1')
                    second = (second + 9 * first) % M;
 
                // If previous character is 2
                // then the words that can be formed
                // are U(21), V(22), W(23), X(24)Y(25), Z(26)
                else if (s.charAt(i - 1) == '2')
                    second = (second + 6 * first) % M;
 
                // If the previous digit is * then
                // all 15 2- digit characters can be
                // formed
                else if (s.charAt(i - 1) == '*')
                    second = (second + 15 * first) % M;
            }
            // If s[i] != '*'
            else {
                second = s.charAt(i) != '0' ? second : 0;
 
                // Adding first in second
                // if s[i-1]=1
                if (s.charAt(i - 1) == '1')
                    second = (second + first) % M;
 
                // Adding first in second if
                // s[i-1] == 2 and s[i]<='6'
                else if (s.charAt(i - 1) == '2'
                         && s.charAt(i) <= '6')
                    second = (second + first) % M;
 
                // if s[i-1] == '*' the union
                // of above 2 cases has to be done
                else if (s.charAt(i - 1) == '*')
                    second = (second
                              + (s.charAt(i) <= '6' ? 2 : 1)
                                    * first)
                             % M;
            }
            first = temp;
        }
        return (int)second;
    }
    public static void main(String[] args)
    {
        String s = "*";
        System.out.println(waysOfDecoding(s));
    }
}

C#

// C# program for the above approach
using System;
 
class GFG{
     
static int M = 1000000007;
 
static int waysOfDecoding(string s)
{
    long first = 1,
    second = s[0] == '*' ? 9 : s[0] == '0' ? 0 : 1;
    for(int i = 1; i < s.Length; i++)
    {
        long temp = second;
 
        // If s[i] == '*' there can be
        // 9 possible values of *
        if (s[i] == '*')
        {
            second = 9 * second;
 
            // If previous character is 1
            // then words that can be formed
            // are K(11), L(12), M(13), N(14)
            // O(15), P(16), Q(17), R(18), S(19)
            if (s[i - 1] == '1')
                second = (second + 9 * first) % M;
 
            // If previous character is 2
            // then the words that can be formed
            // are U(21), V(22), W(23), X(24)Y(25), Z(26)
            else if (s[i - 1] == '2')
                second = (second + 6 * first) % M;
 
            // If the previous digit is * then
            // all 15 2- digit characters can be
            // formed
            else if (s[i - 1] == '*')
                second = (second + 15 * first) % M;
        }
         
        // If s[i] != '*'
        else
        {
            second = s[i] != '0' ? second : 0;
 
            // Adding first in second
            // if s[i-1]=1
            if (s[i - 1] == '1')
                second = (second + first) % M;
 
            // Adding first in second if
            // s[i-1] == 2 and s[i]<='6'
            else if (s[i - 1] == '2' && s[i] <= '6')
                second = (second + first) % M;
 
            // if s[i-1] == '*' the union
            // of above 2 cases has to be done
            else if (s[i - 1] == '*')
                second = (second + (s[i] <= '6' ? 2 : 1) *
                          first) % M;
        }
        first = temp;
    }
    return (int)second;
}
 
// Driver code
static public void Main()
{
    string s = "*";
     
    Console.WriteLine(waysOfDecoding(s));
}
}
 
// This code is contributed by patel2127

Javascript


输出
9

时间复杂度: O(n)
辅助空间: O(1)

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程