The "Self Dividing Numbers" problem asks you to find all numbers within a given range such that each number is divisible by every one of its digits. Specifically, given two integers left
and right
, you must return a list of all self-dividing numbers in the inclusive range [left
, right
].
A self-dividing number is a number that is divisible by every digit it contains. For example, 128 is self-dividing because 128 % 1 == 0, 128 % 2 == 0, and 128 % 8 == 0. If the number contains the digit 0, it is not self-dividing (since division by zero is not allowed).
Constraints:
left
<= right
<= 10,000When first approaching this problem, it's natural to think about iterating through every number in the specified range and checking if each number meets the self-dividing criteria. The brute-force approach would be to examine every digit of each number and ensure that the number is divisible by each digit and that none of its digits are zero.
However, we can optimize our approach by terminating the check early if we encounter a zero digit or a digit that does not divide the number evenly. This avoids unnecessary checks for numbers that are already invalid.
The problem does not require us to store or reuse any intermediate results, so a simple iteration and digit-checking method is both effective and efficient for the given constraints.
Let's break down the steps to solve the Self Dividing Numbers problem:
num
from left
to right
(inclusive).
num % 10
and num // 10
).
This approach is straightforward and leverages early termination to avoid unnecessary computation. Since each number is checked independently, the process is simple to implement and understand.
Let's walk through an example where left = 21
and right = 23
:
Final output: [22]
Brute-force approach:
left
and right
(let's call the count n
), we check all its digits (at most 5 digits for numbers up to 10,000).d
is the maximum number of digits (at most 5).The Self Dividing Numbers problem is elegantly solved by iterating through the given range and checking each number's digits for divisibility and the absence of zero. The algorithm is efficient for the input constraints, simple to implement, and leverages early termination for performance. The key insight is that each number can be checked independently using straightforward digit operations.
class Solution:
def selfDividingNumbers(self, left: int, right: int) -> list[int]:
def is_self_dividing(num):
for digit in str(num):
if digit == '0' or num % int(digit) != 0:
return False
return True
return [num for num in range(left, right + 1) if is_self_dividing(num)]
class Solution {
public:
vector<int> selfDividingNumbers(int left, int right) {
vector<int> result;
for (int num = left; num <= right; ++num) {
int n = num;
bool isSelfDividing = true;
while (n > 0) {
int digit = n % 10;
if (digit == 0 || num % digit != 0) {
isSelfDividing = false;
break;
}
n /= 10;
}
if (isSelfDividing) result.push_back(num);
}
return result;
}
};
class Solution {
public List<Integer> selfDividingNumbers(int left, int right) {
List<Integer> result = new ArrayList<>();
for (int num = left; num <= right; num++) {
if (isSelfDividing(num)) {
result.add(num);
}
}
return result;
}
private boolean isSelfDividing(int num) {
int n = num;
while (n > 0) {
int digit = n % 10;
if (digit == 0 || num % digit != 0) {
return false;
}
n /= 10;
}
return true;
}
}
/**
* @param {number} left
* @param {number} right
* @return {number[]}
*/
var selfDividingNumbers = function(left, right) {
const result = [];
for (let num = left; num <= right; num++) {
let n = num;
let isSelfDividing = true;
while (n > 0) {
let digit = n % 10;
if (digit === 0 || num % digit !== 0) {
isSelfDividing = false;
break;
}
n = Math.floor(n / 10);
}
if (isSelfDividing) result.push(num);
}
return result;
};