Count the Number of Powerful Integers - Complete Solution Guide
Count the Number of Powerful Integers is LeetCode problem 2999, a Hard level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.
Problem Statement
You are given three integers start , finish , and limit . You are also given a 0-indexed string s representing a positive integer. A positive integer x is called powerful if it ends with s (in other words, s is a suffix of x ) and each digit in x is at most limit . Return the total number of powerful integers in the range [start..finish] . A string x is a suffix of a string y if and only if x is a substring of y that starts from some index ( including 0 ) in y and extends to the index y.length -
Detailed Explanation
The problem asks us to count the number of 'powerful integers' within a given range [start, finish]. A powerful integer must satisfy two conditions: it must end with a given suffix string 's', and each of its digits must be less than or equal to a given limit. The problem involves counting integers satisfying these constraints within the inclusive range [start, finish].
Solution Approach
The solution uses dynamic programming with memoization to count the number of integers whose digits are within the limit and that end with 's' in a given range. The approach consists of breaking down the problem into smaller subproblems of counting valid prefixes and storing results in a memoization table to avoid redundant calculations. It uses the principle of inclusion-exclusion by calculating the count up to 'finish' and subtracting the count up to 'start - 1'.
Step-by-Step Algorithm
- Step 1: Calculate 's_val' which is the integer representation of the suffix 's'. Also determine the length of the suffix ('len_s') and compute the power of 10 equivalent to the length of 's' (power_of_10_s). This is used to isolate the prefix.
- Step 2: Define a recursive function 'dp(num_str, index, is_tight)' to count valid prefixes. 'num_str' is the string representation of the prefix, 'index' represents the current digit being considered, and 'is_tight' is a boolean flag indicating whether the digits chosen so far are constrained by the upper limit (i.e., the prefix of the original number being analyzed).
- Step 3: Implement the base case for the 'dp' function: if 'index' reaches the end of 'num_str', it means a valid prefix has been found, so return 1.
- Step 4: Implement memoization within the 'dp' function. Check if the result for the current state (index, is_tight) is already cached in the 'memo'. If so, return the cached value.
- Step 5: Calculate the 'upper_bound' for the current digit. If 'is_tight' is true, the 'upper_bound' is the digit at the current 'index' in 'num_str'. Otherwise, the 'upper_bound' is 'limit'.
- Step 6: Iterate from 0 to 'min(limit, upper_bound)' to consider all possible digits. For each digit, recursively call 'dp' to count valid prefixes, setting 'new_tight' to true if the current digit equals 'upper_bound' (and 'is_tight' was already true) and false otherwise.
- Step 7: Sum up the results from the recursive calls. Store the result in the 'memo' and return it.
- Step 8: Implement the function 'count_valid_numbers(n_str)' to call the 'dp' function with initial values (index = 0, is_tight = true). Clear the 'memo' before calling 'dp'.
- Step 9: Implement the function 'get_powerful_count_up_to(n)' to calculate the number of powerful integers up to 'n'. First, check if 'n < s_val'. If it is, return 0 because no powerful integers are possible.
- Step 10: Calculate the 'upper_prefix' by subtracting 's_val' from 'n' and then dividing by 'power_of_10_s'. Convert 'upper_prefix' to a string.
- Step 11: Call 'count_valid_numbers' with the 'upper_prefix' string and return the result.
- Step 12: Calculate the number of powerful integers up to 'finish' and 'start - 1' using 'get_powerful_count_up_to'. Subtract the two results to get the number of powerful integers in the range [start, finish].
Key Insights
- Insight 1: The problem can be solved by calculating the number of powerful integers up to 'finish' and subtracting the number of powerful integers up to 'start - 1'. This reduces the problem to counting powerful integers up to a certain number.
- Insight 2: Dynamic Programming (DP) with memoization can be used to efficiently count the number of valid prefixes. The 'is_tight' flag is crucial to handle cases where the current digits must match the original number.
- Insight 3: Extracting the prefix from the number (n - s_val) // power_of_10_s allows the problem to be solved without having to construct all possible integers. This is a key simplification.
Complexity Analysis
Time Complexity: O(log(finish))
Space Complexity: O(log(finish))
Topics
This problem involves: Math, String, Dynamic Programming.
Companies
Asked at: HashedIn, Sprinklr.