📜  整数字符串中可被6整除的子字符串数

📅  最后修改于: 2021-04-27 06:28:34             🧑  作者: Mango

给定一个由整数0到9组成的字符串。任务是计算子字符串的数量,这些子字符串在转换为整数时可以被6整除。子字符串不包含前导零。

例子:

Input : s = "606".
Output : 5
Substrings "6", "0", "6", "60", "606"
are divisible by 6.

Input : s = "4806".
Output : 5
"0", "6", "48", "480", "4806" are 
substring which are divisible by 6.

方法1 :(蛮力)的想法是找到给定字符串的所有子字符串,并检查子字符串是否可被6整除。
时间复杂度: O(n 2 )。

方法2 :(动态编程)如检查大数是否可被6整除中所述。如果最后一位数字可被2整除且数字总和可被3整除,则数字可被6整除。

想法是使用动态编程,它使我们能够通过跟踪先前计算的答案并使用这些存储的答案而不是重新计算值来快速而有效地计算答案。

f(i,m)为从索引i开始的字符串数,它们的数字模3之和(到目前为止)为m,它表示的数为偶数。所以,我们的答案是
{\displaystyle \sum_{i}^{n-1}f(i,0) }

令x为字符串的i数字。从f(i,m)中,我们需要找到以i + 1开头的所有偶数子字符串。
此外,如果(x + m)本身可被3整除且x为偶数,我们将获得一个额外的子字符串。因此,我们得到了递归关系

// We initially pass m (sum modulo 3 so far) as 0
f(i, m) = ((x + m)%3 == 0 and x%2 == 0) + 
          f(i + 1, (m + x)%3)  // Recursive 

通过记忆状态,我们得到O(n)解。

以下是此方法的实现:

C++
// C++ program to calculate number of substring
// divisible by 6.
#include 
#define MAX 100002
using namespace std;
  
// Return the number of substring divisible by 6
// and starting at index i in s[] and previous sum
// of digits modulo 3 is m.
int f(int i, int m, char s[], int memoize[][3])
{
    // End of the string.
    if (i == strlen(s))
        return 0;
  
    // If already calculated, return the
    // stored value.
    if (memoize[i][m] != -1)
        return memoize[i][m];
  
    // Converting into integer.
    int x = s[i] - '0';
  
    // Increment result by 1, if current digit
    // is divisible by 2 and sum of digits is
    // divisible by 3.
    // And recur for next index with new modulo.
    int ans = ((x+m)%3 == 0 && x%2 == 0) +
              f(i+1, (m+x)%3, s, memoize);
  
    return memoize[i][m] = ans;
}
  
// Returns substrings divisible by 6.
int countDivBy6(char s[])
{
    int n = strlen(s);
  
    // For storing the value of all states.
    int memoize[n+1][3];
    memset(memoize, -1, sizeof memoize);
  
    int ans = 0;
    for (int i = 0; i < strlen(s); i++)
    {
        // If string contain 0, increment count by 1.
        if (s[i] == '0')
            ans++;
  
        // Else calculate using recursive function.
        // Pass previous sum modulo 3 as 0.
        else
            ans += f(i, 0, s, memoize);
    }
  
    return ans;
}
  
// Driven Program
int main()
{
    char s[] = "4806";
  
    cout << countDivBy6(s) << endl;
  
    return 0;
}


Java
// Java program to calculate number of substring 
// divisible by 6.
import java.util.*;
  
class GFG 
{
  
    static int MAX = 100002;
  
    // Return the number of substring divisible by 6 
    // and starting at index i in s[] and previous sum 
    // of digits modulo 3 is m. 
    static int f(int i, int m, char s[], int memoize[][]) 
    {
        // End of the string. 
        if (i == s.length)
        {
            return 0;
        }
  
        // If already calculated, return the 
        // stored value. 
        if (memoize[i][m] != -1) 
        {
            return memoize[i][m];
        }
  
        // Converting into integer. 
        int x = s[i] - '0';
  
        // Increment result by 1, if current digit 
        // is divisible by 2 and sum of digits is 
        // divisible by 3. 
        // And recur for next index with new modulo. 
        int ans = ((x + m) % 3 == 0 && x % 2 == 0) ? 1 + f(i + 1,
                (m + x) % 3, s, memoize) : f(i + 1, (m + x) % 3, s, memoize);
        memoize[i][m] = ans;
        return memoize[i][m];
    }
  
    // Returns substrings divisible by 6. 
    static int countDivBy6(char s[]) 
    {
        int n = s.length;
  
        // For storing the value of all states. 
        int[][] memoize = new int[n + 1][3];
        for (int i = 0; i < n + 1; i++)
        {
            for (int j = 0; j < 3; j++) 
            {
                memoize[i][j] = -1;
            }
        }
  
        int ans = 0;
        for (int i = 0; i < s.length; i++) 
        {
            // If string contain 0, increment count by 1. 
            if (s[i] == '0') 
            {
                ans++;
            } 
            // Else calculate using recursive function. 
            // Pass previous sum modulo 3 as 0. 
            else 
            {
                ans += f(i, 0, s, memoize);
            }
        }
  
        return ans;
    }
  
    // Driven Program 
    public static void main(String[] args) 
    {
        char s[] = "4806".toCharArray();
  
        System.out.println(countDivBy6(s));
    }
}
  
// This code is contributed by Rajput-Ji


Python3
# Python3 program to calculate number
# of substring 
  
# Return the number of substring divisible 
# by 6 and starting at index i in s[] and 
# previous sum of digits modulo 3 is m. 
def f(i, m, s, memoize):
      
    # End of the string. 
    if (i == len(s)):
        return 0
  
    # If already calculated, return 
    # the stored value. 
    if (memoize[i][m] != -1): 
        return memoize[i][m] 
  
    # Converting into integer. 
    x = ord(s[i]) - ord('0')
  
    # Increment result by 1, if current digit 
    # is divisible by 2 and sum of digits is 
    # divisible by 3. 
    # And recur for next index with new modulo. 
    ans = (((x + m) % 3 == 0 and x % 2 == 0) +
          f(i + 1, (m + x) % 3, s, memoize)) 
  
    memoize[i][m] = ans
    return memoize[i][m]
  
# Returns substrings divisible by 6. 
def countDivBy6(s):
    n = len(s)
  
    # For storing the value of all states.
    memoize = [[-1] * 3 for i in range(n + 1)]
  
    ans = 0
    for i in range(len(s)):
          
        # If string contain 0, increment 
        # count by 1. 
        if (s[i] == '0'):
            ans += 1
  
        # Else calculate using recursive function. 
        # Pass previous sum modulo 3 as 0. 
        else:
            ans += f(i, 0, s, memoize)
  
    return ans
  
# Driver Code
if __name__ == '__main__':
    s = "4806"
  
    print(countDivBy6(s))
  
# This code is contributed by PranchalK


C#
// C# program to calculate number of substring 
// divisible by 6.
using System;
  
class GFG
{
  
    static int MAX = 100002;
  
    // Return the number of substring divisible by 6 
    // and starting at index i in s[] and previous sum 
    // of digits modulo 3 is m. 
    static int f(int i, int m, char []s, int [,]memoize) 
    {
        // End of the string. 
        if (i == s.Length)
        {
            return 0;
        }
  
        // If already calculated, return the 
        // stored value. 
        if (memoize[i,m] != -1) 
        {
            return memoize[i,m];
        }
  
        // Converting into integer. 
        int x = s[i] - '0';
  
        // Increment result by 1, if current digit 
        // is divisible by 2 and sum of digits is 
        // divisible by 3. 
        // And recur for next index with new modulo. 
        int ans = ((((x + m) % 3 == 0) && (x % 2 == 0)) ? 1 : 0)
                + f(i + 1, (m + x) % 3, s, memoize);
  
        return memoize[i,m] = ans;
    }
  
    // Returns substrings divisible by 6. 
    static int countDivBy6(char []s) 
    {
        int n = s.Length;
  
        // For storing the value of all states. 
        int[,] memoize = new int[n + 1,3];
        for (int i = 0; i < n + 1; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                memoize[i,j] = -1;
            }
        }
  
        int ans = 0;
        for (int i = 0; i < s.Length; i++)
        {
            // If string contain 0, increment count by 1. 
            if (s[i] == '0') 
            {
                ans++;
            } 
            // Else calculate using recursive function. 
            // Pass previous sum modulo 3 as 0. 
            else
            {
                ans += f(i, 0, s, memoize);
            }
        }
  
        return ans;
    }
  
    // Driver code 
    public static void Main(String[] args) 
    {
        char []s = "4806".ToCharArray();
  
        Console.WriteLine(countDivBy6(s));
    }
}
  
/* This code is contributed by PrinciRaj1992 */


输出:

5

时间复杂度: O(n)。