Problem Description
Given a string s that consists only of digits, count the number of non‐empty substrings whose numeric value is divisible by its last digit (when that digit is nonzero). Note that a substring may have leading zeros. For example, if s = "12936" then there are 15 total substrings; after ruling out those substrings that are not divisible by their (nonzero) last digit, the answer is 11.
Key Insights
- Only substrings ending in a nonzero digit d are considered; the divisibility test is “number % d == 0.”
- Although one might consider checking every substring (O(n^2)), the constraint n ≤ 10^5 forces an optimized solution.
- The idea is to “precompute” the integer value of every prefix modulo d so that the value of any substring s[j...i] can be computed in O(1) time using the formula: value = pre[i+1] – pre[j] * 10^(i+1–j)
- Since the divisor is the last digit (a number 1–9) there are only a few cases. In particular: • For divisors that are “nice” (for example d = 1, 2, 5), the divisibility condition simplifies. • For digits d that are coprime with 10 (namely 1,3,7,9) one may “cancel” the powers of 10 modulo d (using modular inverses) so that the condition becomes a simple equality between values computed from prefixes. • For other digits (such as 4, 6, 8) the behavior of 10^L modulo d is “degenerate” (often quickly becoming 0 or constant), so one can break the counting into small‐length substrings (for which one checks the condition exactly) and long substrings (which, under certain conditions, are automatically valid).
- In the final solution the strategy is to precompute prefix remainders (for each relevant modulus d) and then, while scanning the string, count valid substrings ending at each index by handling each last‐digit case separately.
Space and Time Complexity
Time Complexity: O(n) – we do a single pass through the string and update auxiliary dictionaries (or counters) for each case. Space Complexity: O(n) – for storing prefix remainder arrays and frequency counters.
Solution
The approach works by processing each ending index i (where s[i] represents the last digit d of a substring) separately. Since d is a digit from 1 to 9 (we ignore zero since “nonzero last digit” is required) the divisibility condition is “number (i.e. s[j…i]) is divisible by d”. We precompute prefix remainders for each d. Then for each ending index, we “reverse‐engineer” the condition: pre[i+1] – pre[j] * 10^(i+1–j) ≡ 0 (mod d) This is rewritten as: pre[i+1] ≡ pre[j] * 10^(i+1–j) (mod d) The structure of powers of 10 modulo d depends on d. For example, when d ∈ {1,2,5} the behavior is simple so that if pre[i+1] % d == 0 then every possible starting index j makes the substring valid (thus contributing i+1 substrings). For digits coprime with 10 (e.g. 3,7,9) we may “divide” by 10^(i+1) modulo d by precomputing its modular inverse. In that case the condition is equivalent to: F(i+1) = F(j) where F(k) = pre[k] * inv(10^k) mod d. A frequency dictionary of F values for indices less than or equal to i (i.e. j in [0, i]) lets us quickly count the number of substrings ending at i. Finally for d=4,6,8 the powers of 10 quickly become 0 or constant so the count can be broken into parts (e.g. the single‐digit substring always works; for longer lengths one must check the condition and, in some cases, all such substrings are valid when the entire prefix is 0 modulo d).
We precompute the required prefix modulo arrays and (when needed) the arrays of 10’s powers modulo d. Then we scan through s once. For each index we branch by the last digit’s case and add to the answer accordingly. Similar helper dictionaries are maintained per modulus for the frequency counts.
Code Solutions
Below are code solutions in Python, JavaScript, C++, and Java. Each version is commented thoroughly so that the purpose of variables and each major step is clear.