Given the integers N, K and M, the task is to find the Kth number greater than N whose sum of digits is divisible by M.
Examples:
Input: N = 6, K = 5, M = 5
Output: 32
Explanation:
The number greater than N = 6 with the sum of their digits divisible by 5 are {14, 19, 23, 28, 32, …}. The Kth number i.e., the 5th number is 32.Input: N = 40, K = 4, M = 5
Output: 55
Explanation:
The number greater than N = 40 with the sum of their digits divisible by 5 are {41, 46, 50, 55, …}. The Kth number i.e., the 4th number is 55.
Naive Approach: The simplest approach is to check every number greater than N and if the sum of its digits is divisible by M, increment the counter by 1. Keep checking the number until the counter becomes equal to K.
Time Complexity: O(K)
Auxiliary Space: O(1)
Efficient Approach: The idea is to use Dynamic Programming and Binary Search. Follow the below steps to solve the problem:
- First, create a recursive memorized function to find the total number of integers smaller than or equal to S having the sum of digits divisible by M as shown below:
The dp transitions will be:
dp(S, index, sum, tight, M) = dp(index+1, (sum+i)%M, tight, M) where,
- S is given limit for which all numbers smaller than or equal to S with the sum of digits divisible by M needs to be found.
- index is the current index for which a digit needs to be placed.
- sum takes the values from 0 to 4.
- Base condition is, if index becomes greater than the length of S and sum is divisible by M, return 1.
- M is the divisor.
If the previous digit already placed such that it becomes smaller than S then
- tight will become equal to 0.
- i will iterate from 0 to 9.
If all the previous digits match with the corresponding digits in S, then
- tight will become 1, which denotes that the number is still not become smaller than S.
- i will iterate from 0 to digit S[index].
- Now using Binary Search, where the lower limit will be N+1 and the upper limit will be some large integer.
- Initialize a variable left for storing the total numbers smaller than or equal to N whose sum of digits is divisible by M.
- Find the midpoint of the lower and the upper limit and then find the numbers smaller than or equal midpoint whose sum of digits is divisible by M using the above dp function. Let it be right.
- If left + K is equals to right then, update the answer as mid and set the upper limit as midpoint – 1.
- Otherwise, if left + K is smaller than right, set the upper limit as midpoint-1.
- If left + K is greater than right, set the lower limit as midpoint+1.
- Repeat the above steps, while the lower limit is smaller than or equal to the upper limit.
Below is the implementation of the above approach:
C++
// C++ program for the above approach #include <bits/stdc++.h> using namespace std; // Initialize dp array int dp[100000][100][2]; // Function to find the numbers <= S // having digits sum divisible by M int solve(string s, int index, int sum, int tight, int z) { // Base Case if (index >= s.size()) { if (sum % z == 0) return 1; return 0; } // Visited state if (dp[index][sum][tight] != -1) return dp[index][sum][tight]; // Store answer int ans = 0; // If number still does not // become smaller than S if (tight == 1) { // Find limit int l = s[index] - '0' ; // Iterate through all // the digits for ( int i = 0; i <= l; i++) { // If current digit is limit if (i == l) { ans += solve(s, index + 1, (sum + i) % z, 1, z); } // Number becomes smaller than S else { ans += solve(s, index + 1, (sum + i) % z, 0, z); } } } else { // If number already becomes // smaller than S for ( int i = 0; i <= 9; i++) ans += solve(s, index + 1, (sum + i) % z, 0, z); } // Return and store the answer // for the current state return dp[index][sum][tight] = ans; } // Function to find the Kth number // > N whose sum of the digits is // divisible by M int search( int n, int k, int z) { // Initialize lower limit int low = n + 1; // Initialize upper limit int high = 1e9; // Mask dp states unvisited memset (dp, -1, sizeof (dp)); // Numbers <= N except 0 with // digits sum divisible by M int left = solve(to_string(n), 0, 0, 1, z) - 1; // Initialize answer with -1 int ans = -1; while (low <= high) { // Calculate mid int mid = low + (high - low) / 2; // Mark dp states unvisited memset (dp, -1, sizeof (dp)); // Numbers < mid with digits // sum divisible by M int right = solve(to_string(mid), 0, 0, 1, z) - 1; // If the current mid is // satisfy the condition if (left + k == right) { // Might be the answer ans = mid; // Update upper limit high = mid - 1; } else if (left + k < right) { // Update upper limit high = mid - 1; } else { // Update lower limit low = mid + 1; } } // Return the answer return ans; } // Driver Code int main() { // Given N, K, and M int N = 40; int K = 4; int M = 2; // Function Call cout << search(N, K, M) << endl; } // This code is contributed by bolliranadheer |
Java
// Java program for the above approach import java.util.*; public class Main { static int dp[][][]; // Function to find the Kth number // > N whose sum of the digits is // divisible by M public static int search( int n, int k, int z) { // Initialize dp array dp = new int [ 100000 + 1 ][z][ 2 ]; // Initialize lower limit int low = n + 1 ; // Initialize upper limit int high = Integer.MAX_VALUE / 2 ; // Mask dp states unvisited clear(); // Numbers <= N except 0 with // digits sum divisible by M int left = solve(n + "" , 0 , 0 , 1 , z) - 1 ; // Initialize answer with -1 int ans = - 1 ; while (low <= high) { // Calculate mid int mid = low + (high - low) / 2 ; // Mark dp states unvisited clear(); // Numbers < mid with digits // sum divisible by M int right = solve(mid + "" , 0 , 0 , 1 , z) - 1 ; // If the current mid is // satisfy the condition if (left + k == right) { // Might be the answer ans = mid; // Update upper limit high = mid - 1 ; } else if (left + k < right) { // Update upper limit high = mid - 1 ; } else { // Update lower limit low = mid + 1 ; } } // Return the answer return ans; } // Function to find the numbers <= S // having digits sum divisible by M public static int solve( String s, int index, int sum, int tight, int z) { // Base Case if (index >= s.length()) { if (sum % z == 0 ) return 1 ; return 0 ; } // Visited state if (dp[index][sum][tight] != - 1 ) return dp[index][sum][tight]; // Store answer int ans = 0 ; // If number still does not // become smaller than S if (tight == 1 ) { // Find limit int l = s.charAt(index) - '0' ; // Iterate through all // the digits for ( int i = 0 ; i <= l; i++) { // If current digit is limit if (i == l) { ans += solve(s, index + 1 , (sum + i) % z, 1 , z); } // Number becomes smaller than S else { ans += solve(s, index + 1 , (sum + i) % z, 0 , z); } } } else { // If number already becomes // smaller than S for ( int i = 0 ; i <= 9 ; i++) ans += solve(s, index + 1 , (sum + i) % z, 0 , z); } // Return and store the answer // for the current state return dp[index][sum][tight] = ans; } // Function to clear the states public static void clear() { for ( int i[][] : dp) { for ( int j[] : i) Arrays.fill(j, - 1 ); } } // Driver Code public static void main(String args[]) { // Given N, K, and M int N = 40 ; int K = 4 ; int M = 2 ; // Function Call System.out.println(search(N, K, M)); } } |
Python3
# Python program for the # above approach # Initialize dp array dp = [[[]]] # Function to find the # numbers <= S having # digits sum divisible # by M def solve(s, index, sum ,tight, z): # Base Case if (index > = len (s)): if ( sum % z = = 0 ): return 1 return 0 # Visited state if (dp[index][ sum ][tight] ! = - 1 ): return dp[index][ sum ][tight] # Store answer ans = 0 # If number still does not # become smaller than S if (tight = = 1 ): # Find limit l = int ( ord (s[index]) - ord ( '0' )) # Iterate through all # the digits for i in range ( 0 , l + 1 ): # If current digit is # limit if (i = = l): ans + = solve(s, index + 1 , ( sum + i) % z, 1 , z) # Number becomes smaller # than S else : ans + = solve(s, index + 1 , ( sum + i) % z, 0 , z) else : # If number already becomes # smaller than S for i in range ( 0 , 10 ): ans + = solve(s, index + 1 , ( sum + i) % z, 0 , z) # Return and store the answer # for the current state dp[index][ sum ][tight] = ans return ans # Function to find the Kth number # > N whose sum of the digits is # divisible by M def search(n, k, z): global dp dp = [[[ - 1 , - 1 ] for j in range (z)] for i in range ( 100001 )] # Initialize lower limit low = n + 1 # Initialize upper limit high = 1000000009 # Numbers <= N except 0 with # digits sum divisible by M left = solve( str (n), 0 , 0 , 1 , z) - 1 # Initialize answer with -1 ans = - 1 while (low < = high): # Calculate mid mid = low + (high - low) / / 2 # Mark dp states unvisited dp = [[[ - 1 , - 1 ] for j in range (z)] for i in range ( 100000 )] # Numbers < mid with digits # sum divisible by M right = solve( str (mid), 0 , 0 , 1 , z) - 1 # If the current mid is # satisfy the condition if (left + k = = right): # Might be the answer ans = mid # Update upper limit high = mid - 1 elif (left + k < right): # Update upper limit high = mid - 1 else : # Update lower limit low = mid + 1 # Return the answer return ans # Driver Code if __name__ = = "__main__" : # Given N, K, and M N = 40 K = 4 M = 2 # Function Call print (search(N, K, M)) # This code is contributed by Rutvik_56 |
C#
// C# program for the above approach using System; class GFG{ static int [,,]dp; // Function to find the Kth number // > N whose sum of the digits is // divisible by M public static int search( int n, int k, int z) { // Initialize dp array dp = new int [100000 + 1, z, 2]; // Initialize lower limit int low = n + 1; // Initialize upper limit int high = int .MaxValue / 2; // Mask dp states unvisited Clear(z); // Numbers <= N except 0 with // digits sum divisible by M int left = solve(n + "" , 0, 0, 1, z) - 1; // Initialize answer with -1 int ans = -1; while (low <= high) { // Calculate mid int mid = low + (high - low) / 2; // Mark dp states unvisited Clear(z); // Numbers < mid with digits // sum divisible by M int right = solve(mid + "" , 0, 0, 1, z) - 1; // If the current mid is // satisfy the condition if (left + k == right) { // Might be the answer ans = mid; // Update upper limit high = mid - 1; } else if (left + k < right) { // Update upper limit high = mid - 1; } else { // Update lower limit low = mid + 1; } } // Return the answer return ans; } // Function to find the numbers <= S // having digits sum divisible by M public static int solve(String s, int index, int sum, int tight, int z) { // Base Case if (index >= s.Length) { if (sum % z == 0) return 1; return 0; } // Visited state if (dp[index, sum, tight] != -1) return dp[index, sum, tight]; // Store answer int ans = 0; // If number still does not // become smaller than S if (tight == 1) { // Find limit int l = s[index] - '0' ; // Iterate through all // the digits for ( int i = 0; i <= l; i++) { // If current digit is limit if (i == l) { ans += solve(s, index + 1, (sum + i) % z, 1, z); } // Number becomes smaller than S else { ans += solve(s, index + 1, (sum + i) % z, 0, z); } } } else { // If number already becomes // smaller than S for ( int i = 0; i <= 9; i++) ans += solve(s, index + 1, (sum + i) % z, 0, z); } // Return and store the answer // for the current state return dp[index, sum, tight] = ans; } // Function to clear the states public static void Clear( int z) { for ( int i = 0; i < 100001; i++) { for ( int j = 0; j < z; j++) { for ( int l = 0; l < 2; l++) dp[i, j, l] = -1; } } } // Driver Code public static void Main(String []args) { // Given N, K, and M int N = 40; int K = 4; int M = 2; // Function Call Console.WriteLine(search(N, K, M)); } } // This code is contributed by gauravrajput1 |
Javascript
<script> // Javascript program for the above approach let dp; // Function to find the Kth number // > N whose sum of the digits is // divisible by M function search(n,k,z) { // Initialize dp array dp = new Array(100000 + 1); for (let i=0;i<100000+1;i++) { dp[i]= new Array(z); for (let j=0;j<z;j++) { dp[i][j]= new Array(2); } } // Initialize lower limit let low = n + 1; // Initialize upper limit let high = Math.floor(Number.MAX_VALUE / 2); // Mask dp states unvisited clear(); // Numbers <= N except 0 with // digits sum divisible by M let left = solve(n + "" , 0, 0, 1, z) - 1; // Initialize answer with -1 let ans = -1; while (low <= high) { // Calculate mid let mid = low + Math.floor((high - low) / 2); // Mark dp states unvisited clear(); // Numbers < mid with digits // sum divisible by M let right = solve(mid + "" , 0, 0, 1, z) - 1; // If the current mid is // satisfy the condition if (left + k == right) { // Might be the answer ans = mid; // Update upper limit high = mid - 1; } else if (left + k < right) { // Update upper limit high = mid - 1; } else { // Update lower limit low = mid + 1; } } // Return the answer return ans; } // Function to find the numbers <= S // having digits sum divisible by M function solve(s,index,sum,tight,z) { // Base Case if (index >= s.length) { if (sum % z == 0) return 1; return 0; } // Visited state if (dp[index][sum][tight] != -1) return dp[index][sum][tight]; // Store answer let ans = 0; // If number still does not // become smaller than S if (tight == 1) { // Find limit let l = s[index].charCodeAt(0) - '0' .charCodeAt(0); // Iterate through all // the digits for (let i = 0; i <= l; i++) { // If current digit is limit if (i == l) { ans += solve(s, index + 1, (sum + i) % z, 1, z); } // Number becomes smaller than S else { ans += solve(s, index + 1, (sum + i) % z, 0, z); } } } else { // If number already becomes // smaller than S for (let i = 0; i <= 9; i++) ans += solve(s, index + 1, (sum + i) % z, 0, z); } // Return and store the answer // for the current state return dp[index][sum][tight] = ans; } // Function to clear the states function clear() { for (let i=0;i<dp.length;i++) { for (let j=0;j<dp[i].length;j++) { for (let k=0;k<dp[i][j].length;k++) { dp[i][j][k]=-1; } } } } // Driver Code // Given N, K, and M let N = 40; let K = 4; let M = 2; // Function Call document.write(search(N, K, M)+ "<br>" ); // This code is contributed by patel2127 </script> |
48
Time Complexity: O(log(INT_MAX))
Auxiliary Space: O(K * M * log(INT_MAX))
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!