Self Dividing Numbers solution and explanation
9 more videos on this problem
LeetCode Self Dividing Numbers Solution Explained - JavaNick White · 8:36 · 9K views
Self Dividing Number | Leetcode 728 | Amazon Google Facebook interview questionSuper Lazy Coder · 6:37 · 1K views
LeetCode Algorithms Easy: Self Dividing NumbersMike the Coder · 7:44 · 1K views
LeetCode 728 : Self Dividing Numbers || EASY || JAVA || Detailed SolutionCodeGPT · 16:03 · 808 views
728. Self Dividing Numbers (Leetcode Easy)Programming Live with Larry · 4:53 · 735 views
728 Self Dividing Numbers | leetcode Easy level Questions Complete playlist Solution in PythonEduEverybody · 5:37 · 650 views
728. Self Dividing Numbers | Leetcode | PythonAbdullah Arshed · 3:25 · 555 views
Leetcode 728 - Self Dividing Numbers (JAVA Solution Explained!)LC Bear · 10:22 · 529 views
How to Solve "728 Self Dividing Numbers" on LeetCode? - JavascriptBecoming A Better Dev (with David) · 8:38 · 336 views
728. Self Dividing Numbers | Python + Leetcode Technical Interview PracticeDC / AC · 15:46 · 333 views
The problem
A self-dividing number is a number that is divisible by every digit it contains.
- For example,
128is a self-dividing number because128 % 1 == 0,128 % 2 == 0, and128 % 8 == 0.
A self-dividing number is not allowed to contain the digit zero.
Given two integers left and right, return a list of all the self-dividing numbers in the range [left, right] (both inclusive).
Example 1:
Input: left = 1, right = 22 Output: [1,2,3,4,5,6,7,8,9,11,12,15,22]
Example 2:
Input: left = 47, right = 85 Output: [48,55,66,77]
Constraints:
1 <= left <= right <= 104
Approach overview
Problem Overview: Given a range [left, right], return all numbers where every digit divides the number itself. A valid number cannot contain the digit 0, and each digit must divide the number without remainder.
Approach 1: Brute Force Digit Check (Time: O(n * d), Space: O(1))
Iterate through every number from left to right. For each number, extract digits one by one using modulo and division operations (digit = num % 10, num /= 10). If any digit is 0 or the original number is not divisible by that digit (original % digit != 0), the number is not self dividing. Otherwise continue until all digits are validated. If every digit passes the check, add the number to the result list.
This approach works because digit extraction is constant time per digit and requires no extra data structures. The complexity depends on how many digits each number has, which is d ≈ log10(n). It fits naturally into problems involving math and simple digit manipulation.
Approach 2: Digit Analysis and Skip Non-Divisible (Time: O(n * d), Space: O(1))
This approach still scans the range sequentially but optimizes the digit validation process. While extracting digits, immediately stop processing the number when encountering 0 or a digit that does not divide the number. Early termination avoids unnecessary digit checks for invalid numbers.
Some implementations also skip forward when a 0 digit appears, since any number containing 0 cannot be self dividing. This reduces redundant checks across the range. The algorithm still performs digit extraction using modulo operations but minimizes work for numbers that fail early.
The method relies purely on arithmetic operations, making it efficient and memory-friendly. It frequently appears in beginner-friendly problems involving math and number theory patterns where digits of a number influence its validity.
Recommended for interviews: Interviewers typically expect the digit-check approach with early termination. The brute force version demonstrates that you understand how to iterate through a numeric range and extract digits. The optimized digit analysis shows awareness of pruning unnecessary checks, which keeps the implementation clean and efficient while maintaining O(n * d) time and O(1) space.
Approach 1: Brute Force Approach
This approach involves iterating over each number within the given range. For each number, extract each digit and check if the number is evenly divisible by that digit. If it passes all checks, the number is self-dividing.
def is_self_dividing(num):
original = num
while num > 0:
digit = num % 10
if digit == 0 or original % digit != 0:
return False
num //= 10
return True
def self_dividing_numbers(left, right):
result = []
for num in range(left, right + 1):
if is_self_dividing(num):
result.append(num)
return result
left, right = 1, 22
print(self_dividing_numbers(left, right))import java.util.ArrayList;
import java.util.List;
public class SelfDividingNumbers {
public static boolean isSelfDividing(int num) {
int original = num, digit;
while (num > 0) {
digit = num % 10;
if (digit == 0 || original % digit != 0) {
return false;
}
num /= 10;
}
return true;
}
public static List<Integer> selfDividingNumbers(int left, int right) {
List<Integer> result = new ArrayList<>();
for (int i = left; i <= right; i++) {
if (isSelfDividing(i)) {
result.add(i);
}
}
return result;
}
public static void main(String[] args) {
int left = 1, right = 22;
List<Integer> result = selfDividingNumbers(left, right);
System.out.println(result);
}
}#include <iostream>
#include <vector>
bool isSelfDividing(int num) {
int original = num, digit;
while (num > 0) {
digit = num % 10;
if (digit == 0 || original % digit != 0) {
return false;
}
num /= 10;
}
return true;
}
std::vector<int> selfDividingNumbers(int left, int right) {
std::vector<int> result;
for (int i = left; i <= right; i++) {
if (isSelfDividing(i)) {
result.push_back(i);
}
}
return result;
}
int main() {
int left = 1, right = 22;
std::vector<int> result = selfDividingNumbers(left, right);
for (int number : result) {
std::cout << number << " ";
}
return 0;
}function isSelfDividing(num) {
let original = num;
while (num > 0) {
let digit = num % 10;
if (digit === 0 || original % digit !== 0) {
return false;
}
num = Math.floor(num / 10);
}
return true;
}
function selfDividingNumbers(left, right) {
let result = [];
for (let i = left; i <= right; i++) {
if (isSelfDividing(i)) {
result.push(i);
}
}
return result;
}
let left = 1, right = 22;
console.log(selfDividingNumbers(left, right));#include <stdio.h>
#include <stdbool.h>
bool isSelfDividing(int num) {
int original = num, digit;
while (num > 0) {
digit = num % 10;
if (digit == 0 || original % digit != 0) {
return false;
}
num /= 10;
}
return true;
}
void selfDividingNumbers(int left, int right) {
for (int i = left; i <= right; i++) {
if (isSelfDividing(i)) {
printf("%d ", i);
}
}
}
int main() {
int left = 1, right = 22;
selfDividingNumbers(left, right);
return 0;
}using System;
using System.Collections.Generic;
class SelfDividingNumbers
{
public static bool IsSelfDividing(int num)
{
int original = num, digit;
while (num > 0)
{
digit = num % 10;
if (digit == 0 || original % digit != 0)
{
return false;
}
num /= 10;
}
return true;
}
public static List<int> SelfDividingNumbersInRange(int left, int right)
{
List<int> result = new List<int>();
for (int i = left; i <= right; i++)
{
if (IsSelfDividing(i))
{
result.Add(i);
}
}
return result;
}
static void Main()
{
int left = 1, right = 22;
List<int> result = SelfDividingNumbersInRange(left, right);
Console.WriteLine(string.Join(", ", result));
}
}This Python function is_self_dividing checks for self-divisibility. It iterates through each digit to verify divisibility, collecting results in a list.
Time Complexity: O(n*m), where n is the range and m is the number of digits in each number.
Space Complexity: O(n) for the list of results.
Approach 2: Digit Analysis and Skip Non-Divisible
This approach optimizes the check by making a presumption against numbers containing digit zero immediately. Numbers with digit zero are automatically non-self-divisible. For the rest, we still check each digit, but this could reduce the number of required operations.
def is_self_dividing(num):
original = num
while num > 0:
digit = num % 10
if digit == 0 or original % digit != 0:
return False
num //= 10
return True
def self_dividing_numbers(left, right):
result = []
for num in range(left, right + 1):
if (num % 10 != 0) and is_self_dividing(num):
result.append(num)
return result
left, right = 47, 85
print(self_dividing_numbers(left, right))import java.util.ArrayList;
import java.util.List;
public class SelfDividingNumbers {
public static boolean isSelfDividing(int num) {
int original = num, digit;
while (num > 0) {
digit = num % 10;
if (digit == 0 || original % digit != 0) {
return false;
}
num /= 10;
}
return true;
}
public static List<Integer> selfDividingNumbers(int left, int right) {
List<Integer> result = new ArrayList<>();
for (int i = left; i <= right; i++) {
if ((i % 10 != 0) && isSelfDividing(i)) {
result.add(i);
}
}
return result;
}
public static void main(String[] args) {
int left = 47, right = 85;
List<Integer> result = selfDividingNumbers(left, right);
System.out.println(result);
}
}#include <iostream>
#include <vector>
bool isSelfDividing(int num) {
int original = num, digit;
while (num > 0) {
digit = num % 10;
if (digit == 0 || original % digit != 0) {
return false;
}
num /= 10;
}
return true;
}
std::vector<int> selfDividingNumbers(int left, int right) {
std::vector<int> result;
for (int i = left; i <= right; i++) {
if ((i % 10 != 0) && isSelfDividing(i)) {
result.push_back(i);
}
}
return result;
}
int main() {
int left = 47, right = 85;
std::vector<int> result = selfDividingNumbers(left, right);
for (int number : result) {
std::cout << number << " ";
}
return 0;
}function isSelfDividing(num) {
let original = num;
while (num > 0) {
let digit = num % 10;
if (digit === 0 || original % digit !== 0) {
return false;
}
num = Math.floor(num / 10);
}
return true;
}
function selfDividingNumbers(left, right) {
let result = [];
for (let i = left; i <= right; i++) {
if ((i % 10 !== 0) && isSelfDividing(i)) {
result.push(i);
}
}
return result;
}
let left = 47, right = 85;
console.log(selfDividingNumbers(left, right));#include <stdio.h>
#include <stdbool.h>
bool isSelfDividing(int num) {
int original = num, digit;
while (num > 0) {
digit = num % 10;
if (digit == 0 || original % digit != 0) {
return false;
}
num /= 10;
}
return true;
}
void selfDividingNumbers(int left, int right) {
for (int i = left; i <= right; i++) {
if ((i % 10 != 0) && isSelfDividing(i)) {
printf("%d ", i);
}
}
}
int main() {
int left = 47, right = 85;
selfDividingNumbers(left, right);
return 0;
}using System;
using System.Collections.Generic;
class SelfDividingNumbers
{
public static bool IsSelfDividing(int num)
{
int original = num, digit;
while (num > 0)
{
digit = num % 10;
if (digit == 0 || original % digit != 0)
{
return false;
}
num /= 10;
}
return true;
}
public static List<int> SelfDividingNumbersInRange(int left, int right)
{
List<int> result = new List<int>();
for (int i = left; i <= right; i++)
{
if ((i % 10 != 0) && IsSelfDividing(i))
{
result.Add(i);
}
}
return result;
}
static void Main()
{
int left = 47, right = 85;
List<int> result = SelfDividingNumbersInRange(left, right);
Console.WriteLine(string.Join(", ", result));
}
}The Python method pre-filters by selecting only numbers not ending in zero, reducing unnecessary checks by eliminating numbers not potentially fully self-dividing.
Time Complexity: O(n*m), with potential performance gains.
Space Complexity: O(n) on account of list storage.
Approach 3: Simulation
We define a function check(x) to determine whether x is a self-dividing number. The implementation idea of the function is as follows:
We use y to record the value of x, and then continuously divide y by 10 until y is 0. During this process, we check whether the last digit of y is 0, or whether x cannot be divided by the last digit of y. If either of these conditions is met, then x is not a self-dividing number, and we return false. Otherwise, after traversing all the digits, we return true.
Finally, we traverse all the numbers in the interval [left, right], and for each number, we call check(x). If it returns true, we add this number to the answer array.
The time complexity is O(n times log_{10} M), where n is the number of elements in the interval [left, right], and M = right, which is the maximum value in the interval.
function selfDividingNumbers(left: number, right: number): number[] {
const check = (x: number): boolean => {
for (let y = x; y; y = Math.floor(y / 10)) {
if (y % 10 === 0 || x % (y % 10) !== 0) {
return false;
}
}
return true;
};
return Array.from({ length: right - left + 1 }, (_, i) => i + left).filter(check);
}func selfDividingNumbers(left int, right int) (ans []int) {
check := func(x int) bool {
for y := x; y > 0; y /= 10 {
if y%10 == 0 || x%(y%10) != 0 {
return false
}
}
return true
}
for x := left; x <= right; x++ {
if check(x) {
ans = append(ans, x)
}
}
return
}impl Solution {
pub fn self_dividing_numbers(left: i32, right: i32) -> Vec<i32> {
fn check(x: i32) -> bool {
let mut y = x;
while y > 0 {
if y % 10 == 0 || x % (y % 10) != 0 {
return false;
}
y /= 10;
}
true
}
(left..=right).filter(|&x| check(x)).collect()
}
}Complexity comparison
| Approach | Complexity |
|---|---|
| Brute Force Approach | Time Complexity: O(n*m), where n is the range and m is the number of digits in each number. |
| Digit Analysis and Skip Non-Divisible | Time Complexity: O(n*m), with potential performance gains. |
| Simulation | – |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Brute Force Digit Check | O(n * d) | O(1) | Simple implementation when checking each number independently |
| Digit Analysis with Early Break | O(n * d) | O(1) | Preferred approach in interviews due to early pruning of invalid numbers |
Frequently asked questions
Is Self Dividing Numbers easy or hard?
Self Dividing Numbers is classified as an Easy problem. The main challenge is correctly extracting digits and handling edge cases such as the digit 0, which automatically invalidates the number.
Self Dividing Numbers Python/Java solution
The core logic is identical across languages. Loop from left to right, extract digits using modulo, and check if each digit divides the original number. Python, Java, C++, C#, and JavaScript implementations all follow the same O(n * d) algorithm.
How to solve Self Dividing Numbers in O(n)?
Practically the solution runs in O(n * d) because each number requires digit extraction. However, since d is small (at most 10 digits for typical integer ranges), it behaves close to linear time. The optimized method stops checking digits early when encountering 0 or a non-divisible digit.
What is the best approach for Self Dividing Numbers?
The best approach is digit analysis with early termination. Iterate through the range and extract digits using modulo operations. If a digit is 0 or the number is not divisible by that digit, stop immediately. This keeps the solution simple with O(n * d) time and O(1) space complexity.
Is Self Dividing Numbers asked at Google/Amazon/Meta?
Self Dividing Numbers is generally considered a beginner-level screening problem. It appears in coding assessments and early interview rounds to evaluate basic math reasoning, loops, and digit manipulation rather than advanced algorithms.
What data structure is used in Self Dividing Numbers?
No complex data structures are required. The solution relies on arithmetic operations such as modulo and integer division to extract digits. A simple list or array is used to store the valid self dividing numbers in the result.
What is the time complexity of Self Dividing Numbers?
The time complexity is O(n * d), where n is the size of the range and d is the number of digits in each number (approximately log10(n)). Each number is processed once, and its digits are checked individually using modulo and division operations.
