← Home

728. Self Dividing Numbers

LeetCode article · C++ solution
Website made by wuisabel-gif · Original C++ code by keineahnung2345
two pointersC++Markdown
728

The trick here is to name the state correctly, then let the implementation follow. For 728. Self Dividing Numbers, the solution in this repository is mainly a two pointers solution.

Guide

What?

Before optimizing anything, pin down what information is still useful after each move. Instead of trying to be clever immediately, read the code as a sequence of questions:

  • What state are we keeping?
  • How do we move from one state to the next?
  • When do we know the answer is already determined?

For this file, the main tools are: two pointers, sliding window.

Guide

When?

Reach for this shape when a direct simulation would work logically but waste time revisiting the same information. The accepted code reduces that pressure by storing exactly the information that remains useful later.

The important function names to track are selfDividingNumbers.

Guide

Why?

The point of the implementation is not to make the code longer. It is to avoid doing the same thinking twice.

  • The final return is not magic; it is the invariant after the loops or recursion have finished doing their accounting.

Guide

How?

Walk through the solution in this order:

  1. Read the setup variables first.
  2. Follow the main loop or recursive helper next.
  3. Watch where invalid states get skipped.
  4. Check which value survives to the return statement.

The most important competitive-programming habit here is to trust the invariant. Once the invariant is right, the loops become much less scary.

Guide

Complexity

  • Time: O(n) to O(n log n), depending on the dominant loop or data structure operation
  • Space: O(n) in the usual case for auxiliary containers or recursion

Guide

C++ Solution

Your submission

The accepted solution

solution.cpp
01/**
02A self-dividing number is a number that is divisible by every digit it contains.
03
04For example, 128 is a self-dividing number because 128 % 1 == 0, 128 % 2 == 0, and 128 % 8 == 0.
05
06Also, a self-dividing number is not allowed to contain the digit zero.
07
08Given a lower and upper number bound, output a list of every possible self dividing number, including the bounds if possible.
09
10Example 1:
11Input: 
12left = 1, right = 22
13Output: [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 22]
14Note:
15
16The boundaries of each input argument are 1 <= left <= right <= 10000.
17**/
18
19//Your runtime beats 100.00 % of cpp submissions.
20class Solution {
21public:
22    vector<int> selfDividingNumbers(int left, int right) {
23        vector<int> result;
24        for(int num = left; num <= right; num++){
25            bool selfDividing = true;
26            int workNum = num;
27            while(workNum){
28                //n-th digit is 0 or n-th digit of "num" cannot divide "num"
29                if(workNum%10==0 || num%(workNum%10)!=0){
30                    selfDividing = false;
31                    break;
32                }
33                //if workNum<10, there won't be next iteration
34                workNum/=10;
35            }
36            if(selfDividing) result.push_back(num);
37        }
38        return result;
39    }
40};
41
42/**
43Approach #1: Brute Force [Accepted]
44Intuition and Algorithm
45
46For each number in the given range, we will directly test if that number is self-dividing.
47
48By definition, we want to test each whether each digit is non-zero and divides the number. For example, with 128, we want to test d != 0 && 128 % d == 0 for d = 1, 2, 8. To do that, we need to iterate over each digit of the number.
49
50A straightforward approach to that problem would be to convert the number into a character array (string in Python), and then convert back to integer to perform the modulo operation when checking n % d == 0.
51
52We could also continually divide the number by 10 and peek at the last digit. That is shown as a variation in a comment.
53
54//Java
55class Solution {
56    public List<Integer> selfDividingNumbers(int left, int right) {
57        List<Integer> ans = new ArrayList();
58        for (int n = left; n <= right; ++n) {
59            if (selfDividing(n)) ans.add(n);
60        }
61        return ans;
62    }
63    public boolean selfDividing(int n) {
64        for (char c: String.valueOf(n).toCharArray()) {
65            if (c == '0' || (n % (c - '0') > 0))
66                return false;
67        }
68        return true;
69    }
70    /*
71    Alternate implementation of selfDividing:
72    public boolean selfDividing(int n) {
73        int x = n;
74        while (x > 0) {
75            int d = x % 10;
76            x /= 10;
77            if (d == 0 || (n % d) > 0) return false;
78        }
79        return true;
80    */
81}
82
83Complexity Analysis
84
85Time Complexity: O(D), where D is the number of integers in the range [L, R], 
86and assuming log(R) is bounded. (In general, the complexity would be O(DlogR).)
87
88Space Complexity: O(D), the length of the answer.

Cost

Complexity

Time
O(n) to O(n log n), depending on the dominant loop or data structure operation
Dominated by the main traversal, recursion, or data-structure operations in the code.
Space
O(n) in the usual case for auxiliary containers or recursion
Auxiliary state plus the answer structure where the problem requires one.