Count of numbers upto N having absolute difference of at most K between any two adjacent digits

Given an integer N, the task is to count the numbers up to N having an absolute difference of at most K between any two adjacent digits.
Note: Count of integer 0 for any digits is considerable.
Examples:

Input: N = 20, K = 2 
Output: 15 
Explanation: 
The required numbers are 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 and 20. Notice that 14, 15, 16, 17, 18 and 19 all have adjacent digit’s absolute difference greater than K = 2 and thus they are not counted. 

Input: N = 30, K = 3 
Output: 22 
Explanation: 
All numbers upto 30 except 15, 16, 17, 18, 19, 26, 27, 28, 29 are accepted.

Naive Approach: The idea is to iterate till N and check for all the numbers that the difference of K exists or not. If yes then count it otherwise skip the number and keep iterating.

Time Complexity: O(N) 
Auxiliary Space: O(1)

Efficient Approach: This problem can be optimized using Digit Dynamic Programming. Following are the detailed dp states for the given problem.



Below is the implementation of the above approach:

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program to get the count
// of numbers upto N having
// absolute difference at most K
// between any two adjacent digits
  
#include <bits/stdc++.h>
using namespace std;
  
// Table to store solution
// of each subproblem
long long dp[1002][10][2][2];
  
// Function to calculate
// all possible numbers
long long possibleNumbers(
    int pos, int previous, bool tight,
    bool start, string N, int K)
{
    // Check if position reaches end that is
    // is equal to length of N
    if (pos == N.length())
        return 1;
  
    // Check if the result is
    // already computed
    // simply return it
    if (dp[pos][previous][tight][start] != -1)
        return dp[pos][previous][tight][start];
  
    int res = 0;
  
    // Maximum limit upto which we can place
    // digit. If tight is false, means number has
    // already become smaller so we can place
    // any digit, otherwise N[pos]
    int upper_limit
        = (tight)
              ? (N[pos] - '0')
              : 9;
  
    int new_tight;
  
    // Chekc if start is false the number
    // has not started yet
    if (!start) {
  
        // Check if we do not start
        // the number at pos
        // then recur forward
        res = possibleNumbers(
            pos + 1, previous,
            false, false, N, K);
  
        // If we start the number
        // we can place any digit
        // from 1 to upper_limit
        for (int i = 1; i <= upper_limit; i++) {
  
            // Finding the new tight
            new_tight
                = (tight
                   && i == upper_limit)
                      ? 1
                      : 0;
            res += possibleNumbers(
                pos + 1, i, new_tight,
                true, N, K);
        }
    }
  
    // Condition if the number
    // has already started
    else {
  
        // We can place digit upto
        // upperbound & absolute difference
        // with previous digit much
        // be atmost K
        for (int i = 0; i <= upper_limit; i++) {
  
            new_tight = (tight
                         && i == upper_limit)
                            ? 1
                            : 0;
            // Absolute difference atmost K
            if (abs(i - previous) <= K)
                res += possibleNumbers(
                    pos + 1, i,
                    new_tight, true, N, K);
        }
    }
  
    // Store the solution
    // to this subproblem
    dp[pos][previous][tight][start] = res;
  
    return dp[pos][previous][tight][start];
}
  
// Driver code
int main(void)
{
  
    string N = "20";
    int K = 2;
  
    // Initialising the
    // table with -1
    memset(dp, -1, sizeof dp);
  
    // Function call
    cout << possibleNumbers(
                0, 0, true,
                false, N, K)
         << endl;
}
chevron_right

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java program to get the count
// of numbers upto N having
// absolute difference at most K
// between any two adjacent digits
import java.util.*;
  
class GFG{
  
// Table to store solution
// of each subproblem
static int [][][][]dp = new int[1002][10][2][2];
  
// Function to calculate
// all possible numbers
static int possibleNumbers(int pos, int previous, 
                           int tight, int start,
                            String N, int K)
{
      
    // Check if position reaches end 
    // that is equal to length of N
    if (pos == N.length())
        return 1;
  
    // Check if the result is already
    // computed simply return it
    if (dp[pos][previous][tight][start] != -1)
        return dp[pos][previous][tight][start];
  
    int res = 0;
  
    // Maximum limit upto which we can 
    // place digit. If tight is false, 
    // means number has already become
    // smaller so we can place
    // any digit, otherwise N[pos]
    int upper_limit = (tight == 1) ? 
                      (N.charAt(pos) - '0') : 9;
                        
    int new_tight;
  
    // Check if start is false the number
    // has not started yet
    if (start == 0)
    {
          
        // Check if we do not start
        // the number at pos
        // then recur forward
        res = possibleNumbers(pos + 1, previous,
                              0, 0, N, K);
  
        // If we start the number
        // we can place any digit
        // from 1 to upper_limit
        for(int i = 1; i <= upper_limit; i++)
        {
              
            // Finding the new tight
            new_tight = (tight > 0 && 
                         i == upper_limit) ? 1 : 0;
            res += possibleNumbers(pos + 1, i,
                                   new_tight,
                                   1, N, K);
        }
    }
      
    // Condition if the number
    // has already started
    else
    {
          
        // We can place digit upto
        // upperbound & absolute difference
        // with previous digit much
        // be atmost K
        for(int i = 0; i <= upper_limit; i++)
        {
            new_tight = (tight > 0 && 
                         i == upper_limit) ? 1 : 0;
                           
            // Absolute difference atmost K
            if (Math.abs(i - previous) <= K)
                res += possibleNumbers(pos + 1, i,
                                       new_tight, 1,
                                       N, K);
        }
    }
  
    // Store the solution
    // to this subproblem
    dp[pos][previous][tight][start] = res;
  
    return dp[pos][previous][tight][start];
}
  
// Driver code
public static void main(String[] args) 
{
    String N = "20";
    int K = 2;
  
    // Initialising the
    // table with -1
    for(int i = 0; i < 1002; i++)
        for(int j = 0; j < 10; j++)
            for(int k = 0; k < 2; k++)
                for(int l = 0; l < 2; l++)
                    dp[i][j][k][l] = -1;
  
    // Function call
    System.out.print(possibleNumbers(0, 0, 1, 0
                                     N, K) + "\n");
}
}
  
// This code is contributed by Princi Singh
chevron_right

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 program to get the count of 
# numbers upto N having absolute
# difference at most K between any 
# two adjacent digits
  
# Table to store solution
# of each subproblem
dp = [[[[ -1 for i in range(2)]
             for j in range(2)]
             for i in range(10)]
             for j in range(1002)]
  
# Function to calculate
# all possible numbers
def possibleNumber(pos, previous, tight,
                   start, N, K):
  
    # Check if position reaches end 
    # that is equal to length of N
    if(pos == len(N)):
        return 1
  
    # Check if the result is
    # already computed
    # simply return it
    if(dp[pos][previous][tight][start] != -1):
        return dp[pos][previous][tight][start]
  
    res = 0
  
    # Maximum limit upto which we can place
    # digit. If tight is false, means number has
    # already become smaller so we can place
    # any digit, otherwise N[pos]
    if(tight):
        upper_limit = ord(N[pos]) - ord('0')
    else:
        upper_limit = 9
  
    # Chekc if start is false the number
    # has not started yet
    if(not start):
  
        # Check if we do not start
        # the number at pos
        # then recur forward
        res = possibleNumber(pos + 1, previous,
                             False, False, N, K)
  
        # If we start the number
        # we can place any digit
        # from 1 to upper_limit
        for i in range(1, upper_limit + 1):
  
            # Finding the new tight
            if(tight and i == upper_limit):
                new_tight = 1
            else:
                new_tight = 0
  
            res += possibleNumber(pos + 1, i, 
                                  new_tight,
                                  True, N, K)
                                    
    # Condition if the number
    # has already started
    else:
          
        # We can place digit upto
        # upperbound & absolute 
        # difference with previous
        # digit much be atmost K
        for i in range(upper_limit + 1):
            if(tight and i == upper_limit):
                new_tight = 1
            else:
                new_tight = 0
  
            # Absolute difference atmost K
            if(abs(i - previous) <= K):
                res += possibleNumber(pos + 1, i,
                                      new_tight,
                                        True, N, K)
  
    # Store the solution to this subproblem
    dp[pos][previous][tight][start] = res
  
    return dp[pos][previous][tight][start]
  
# Driver code
if __name__ == '__main__':
      
    N = "20"
    K = 2
      
    # Function call
    print(possibleNumber(0, 0, True,
                         False, N, K))
  
# This code is contributed by Shivam Singh
chevron_right

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# program to get the count
// of numbers upto N having
// absolute difference at most K
// between any two adjacent digits
using System;
  
class GFG{
  
// Table to store solution
// of each subproblem
static int [,,,]dp = new int[1002, 10, 2, 2];
  
// Function to calculate
// all possible numbers
static int possibleNumbers(int pos, int previous, 
                           int tight, int start,
                            String N, int K)
{
      
    // Check if position reaches end 
    // that is equal to length of N
    if (pos == N.Length)
        return 1;
  
    // Check if the result is already
    // computed simply return it
    if (dp[pos, previous, tight, start] != -1)
        return dp[pos, previous, tight, start];
  
    int res = 0;
  
    // Maximum limit upto which we can 
    // place digit. If tight is false, 
    // means number has already become
    // smaller so we can place
    // any digit, otherwise N[pos]
    int upper_limit = (tight == 1) ? 
                      (N[pos] - '0') : 9;
                      
    int new_tight;
  
    // Check if start is false the number
    // has not started yet
    if (start == 0)
    {
          
        // Check if we do not start
        // the number at pos
        // then recur forward
        res = possibleNumbers(pos + 1, previous,
                              0, 0, N, K);
  
        // If we start the number
        // we can place any digit
        // from 1 to upper_limit
        for(int i = 1; i <= upper_limit; i++)
        {
              
            // Finding the new tight
            new_tight = (tight > 0 && 
                         i == upper_limit) ? 1 : 0;
            res += possibleNumbers(pos + 1, i,
                                   new_tight,
                                   1, N, K);
        }
    }
      
    // Condition if the number
    // has already started
    else
    {
          
        // We can place digit upto
        // upperbound & absolute difference
        // with previous digit much
        // be atmost K
        for(int i = 0; i <= upper_limit; i++)
        {
            new_tight = (tight > 0 && 
                         i == upper_limit) ? 1 : 0;
                          
            // Absolute difference atmost K
            if (Math.Abs(i - previous) <= K)
                res += possibleNumbers(pos + 1, i,
                                       new_tight, 1,
                                       N, K);
        }
    }
  
    // Store the solution
    // to this subproblem
    dp[pos, previous, tight, start] = res;
  
    return dp[pos, previous, tight, start];
}
  
// Driver code
public static void Main(String[] args) 
{
    String N = "20";
    int K = 2;
  
    // Initialising the
    // table with -1
    for(int i = 0; i < 1002; i++)
        for(int j = 0; j < 10; j++)
            for(int k = 0; k < 2; k++)
                for(int l = 0; l < 2; l++)
                    dp[i, j, k, l] = -1;
  
    // Function call
    Console.Write(possibleNumbers(0, 0, 1, 0, 
                                  N, K) + "\n");
}
}
  
// This code is contributed by amal kumar choubey
chevron_right

Output: 
15

Time Complexity: O( D * 10 * 2 * 2 * 10), considering N has D digits.
 

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.




Recommended Posts:


Check out this Author's contributed articles.

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

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.



Article Tags :