Given a large number, check if a subsequence of digits is divisible by 8

5

Given a number of at most 100 digits. We have to check if it is possible, after removing certain digits, to obtain a number of at least one digit which is divisible by 8. We are forbidden to rearrange the digits.

Examples:

Input : 1787075866
Output : Yes
There exist more one or more subsequences
divisible by 8. Example subsequences are
176, 16 and 8.

Input : 6673177113
Output : No 
No subsequence is divisible by 8.

Input : 3144
Output : Yes
The subsequence 344 is divisible by 8.

Property of the divisibility by eight : number can be divided by eight if and only if its last three digits form a number that can be divided by eight. Thus, it is enough to test only numbers that can be obtained from the original one by crossing out and that contain at most three digits i.e we check all one digits, two digits and three digit number combinations.

Method 1 (Brute Force):


We apply the brute force approach. We permute all possible single digit, double digit and triple digit combinations using iterative ladder. If we encounter a single digit number divisible by 8 or a double digit number combination divisible by 8 or a triple digit number combination divisible by 8, then that will be the solution to our problem.

// CPP program to check if a subsequence of digits
// is divisible by 8.
#include <bits/stdc++.h>
using namespace std;

// Function to calculate any permutation divisible
// by 8. If such permutation exists, the function
// will return that permutation else it will return -1
bool isSubSeqDivisible(string str)
{
    // Generating all possible permutations and checking
    // if any such permutation is divisible by 8
    for (int i = 0; i < l; i++) {
        for (int j = i; j < l; j++) {
            for (int k = j; k < l; k++) {
                if (arr[i] % 8 == 0)
                    return true;

                else if ((arr[i]*10 + arr[j])%8 == 0 &&
                         i != j)
                    return true;

                else if ((arr[i] * 100 + arr[j] * 10 + 
                          arr[k]) % 8 == 0 && i != j && 
                          j != k && i != k)
                    return true;
            }
        }
    }
    return false;
}

// Driver function
int main()
{
    string str = "3144";
    if (isSubSeqDivisible(str))
       cout << "Yes";
    else
       cout << "No";
    return 0;
}

Output:

Yes

Method 2 (Dynamic Programming):


Though we have only 100 digit number, but for longer examples larger than that, our program might exceed the given time limit.
Thus, we optimize our code by using dynamic programming approach.
Let a_{i} be the ith digit of the sample. We generate a matrix dp[i][j], 1<=i<=n and 0<=j<8. The value of dp is true if we can cross out some digits from the prefix of length i such that the remaining number gives j modulo eight, and false otherwise. For broad understanding of the concept, if at an index, we find element 8 for that index we put the value of dp[i][a_{i}mod8] = 1
For all other numbers, we build on a simple concept that either addition of that digit will contribute in formation of a number divisible by 8, or it shall be left out.
Note: We also have to keep it in mind that we cannot change the order
Now,
dp[i][(j*10+a_{i}) mod 8]=max(dp[i][(j*10+a_{i}) mod 8], dp[i-1][j]) if we add the current digit to the previous result.
dp[i][(j*10) mod 8]=max(dp[i][(j*10) mod 8], dp[i-1][j]) if we exclude the current digit in our formation.
Now, if such a number shall exist, we will get a “true” for any i in dp[i][0]

// C++ program to find if there is a subsequence
// of digits divisible by 8.
#include <bits/stdc++.h>
using namespace std;

// Function takes in an array of numbers,
// dynamically goes on the location and
// makes combination of numbers.
bool isSubSeqDivisible(string str)
{
    int n = str.length();
    int dp[n + 1][10];
    memset(dp, 0, sizeof(dp));

    // Converting string to integer array for ease
    // of computations (Indexing in arr[] is 
    // considered to be starting from 1)
    int arr[n+1];
    for (int i = 1; i <= n; i++)
        arr[i] = str[i - 1] - '0';

    for (int i = 1; i <= n; i++) {

        dp[i][arr[i] % 8] = 1;
        for (int j = 0; j < 8; j++) {

            // If we consider the number in our combination,
            // we add it to the previous combination
            if (dp[i - 1][j] > dp[i][(j * 10 + arr[i]) % 8]) 
                dp[i][(j * 10 + arr[i]) % 8] = dp[i - 1][j];            

            // If we exclude the number from our combination
            if (dp[i - 1][j] > dp[i][j]) 
                dp[i][j] = dp[i - 1][j];            
        }
    }

    for (int i = 1; i <= n; i++) {

        // If at dp[i][0], we find value 1/true, it shows
        // that the number exists at the value of 'i'
        if (dp[i][0] == 1)
           return true;
    }
 
    return false;
}

// Driver function
int main()
{
    string str = "3144";
    if (isSubSeqDivisible(str))
       cout << "Yes";
    else
       cout << "No";
    return 0;
}

Output:

Yes

Using the dynamic approach, our time complexity cuts down to O(8*n), where 8 is from which the number should be divisible and n is the length of our input. Therefore, the overall complexity is O(n).

This article is contributed by parthendo. If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geekforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.

GATE CS Corner    Company Wise Coding Practice

Recommended Posts:



5 Average Difficulty : 5/5.0
Based on 1 vote(s)










Writing code in comment? Please use ide.geeksforgeeks.org, generate link and share the link here.