Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions .github/workflows/gitbook.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
name: GitBook

# GitBook publishes this repo through Git sync (.gitbook.yaml -> SUMMARY.md), so
# whatever lands on main is what readers see — there is no build step in between
# to catch a stale table of contents or a link to a folder that was renamed.
# This workflow is that missing build step:
#
# * on pull requests -> validate only, so a bad TOC never reaches main
# * on push to main -> regenerate the navigation and commit any drift, which
# produces the push GitBook's Git sync reacts to
#
# Regenerating on main is what actually "updates GitBook": the commit this job
# makes is the trigger. No GitBook API token is involved.
#
# The bot commit does not re-run this workflow: GitHub suppresses workflow
# triggers for pushes made with the default GITHUB_TOKEN, so there is no loop.

on:
push:
branches: [main]
paths:
- "Easy/**"
- "Medium/**"
- "Hard/**"
- "README.md"
- "SUMMARY.md"
- "_sidebar.md"
- ".gitbook.yaml"
- "tools/**"
- ".github/workflows/gitbook.yml"
pull_request:
paths:
- "Easy/**"
- "Medium/**"
- "Hard/**"
- "README.md"
- "SUMMARY.md"
- "_sidebar.md"
- ".gitbook.yaml"
- "tools/**"
- ".github/workflows/gitbook.yml"
workflow_dispatch:

# Never let two runs race to commit regenerated navigation.
concurrency:
group: gitbook-${{ github.ref }}
cancel-in-progress: false

jobs:
validate:
name: Validate GitBook sources
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Check navigation, links, counts and math
run: ./tools/check-nav.sh

- name: Explain how to fix
if: failure()
run: |
echo "::notice::Run './tools/gen-summary.sh && ./tools/gen-sidebar.sh && ./tools/mathfix.py' locally, then commit the result."

publish:
name: Regenerate navigation and sync
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
# A real token is needed so the commit below is pushed as a normal
# commit that GitBook's Git sync app can see.
token: ${{ secrets.GITHUB_TOKEN }}

- name: Normalize math for GitBook
run: ./tools/mathfix.py

- name: Regenerate SUMMARY.md and _sidebar.md
run: |
./tools/gen-summary.sh
./tools/gen-sidebar.sh

- name: Commit drift, if any
id: commit
run: |
if git diff --quiet; then
echo "Navigation already up to date; nothing to push."
echo "changed=false" >> "$GITHUB_OUTPUT"
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add SUMMARY.md _sidebar.md Easy Medium Hard
git commit -m "Regenerate GitBook navigation"
git push
echo "changed=true" >> "$GITHUB_OUTPUT"

- name: Verify the state GitBook will sync
run: ./tools/check-nav.sh

- name: Summary
run: |
{
echo "### GitBook sync"
echo
if [ "${{ steps.commit.outputs.changed }}" = "true" ]; then
echo "Navigation had drifted; regenerated and pushed a commit."
echo "GitBook Git sync picks this up on the new push."
else
echo "Navigation was already correct — GitBook syncs this commit as-is."
fi
} >> "$GITHUB_STEP_SUMMARY"
8 changes: 8 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ The repo is published two ways from the same markdown, each with its own generat

Both scripts derive everything from the `<Difficulty>/<id>.<Title>/solution*.md` layout, so correct folder naming matters.

To check the whole publishing surface before pushing:

```bash
./tools/check-nav.sh # nav freshness, link resolution, README counts, math convention
```

CI runs the same script: `.github/workflows/gitbook.yml` validates it on pull requests and, on pushes to `main`, regenerates the navigation and commits any drift so GitBook's Git sync publishes correct pages.

## Conventions

### Directory naming
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# 3622. Check Divisibility by Digit Sum and Product

You are given a positive integer `n`. Determine whether `n` is divisible by the
**sum** of the following two values:

- The **digit sum** of `n` (the sum of its digits).
- The **digit product** of `n` (the product of its digits).

Return `true` if `n` is divisible by this sum; otherwise, return `false`.

## Example 1

```text
Input: n = 99
Output: true
Explanation:
Since 99 is divisible by the sum (9 + 9 = 18) plus product (9 * 9 = 81)
of its digits (total 99), the output is true.
```

## Example 2

```text
Input: n = 23
Output: false
Explanation:
Since 23 is not divisible by the sum (2 + 3 = 5) plus product (2 * 3 = 6)
of its digits (total 11), the output is false.
```

## Constraints

- `1 <= n <= 10^6`
127 changes: 127 additions & 0 deletions Easy/3622.Check-Divisibility-by-Digit-Sum-and-Product/solution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Intuition

The check is a direct restatement of the definition: compute the digit sum $$S$$ and
the digit product $$P$$ of `n`, then test whether `n` is divisible by $$P + S$$. Both
quantities are folds over the same sequence of decimal digits, so a single scan that
updates two accumulators is enough — there is no need to store the digits.

# Approach: Digit Extraction

1. Initialize `product = 1` and `sum = 0`, and copy `n` into a working variable `temp`.
2. While `temp > 0`, take `digit = temp % 10`, multiply it into `product`, add it to
`sum`, then drop it with `temp /= 10`.
3. Return whether `n % (product + sum) == 0`.

The peel relies on two standard identities: `temp % 10` is the last digit of `temp`,
and integer division `temp /= 10` removes it. The loop ends exactly when every digit
has been consumed. The seed values are the respective identities — `product = 1`
(seeding it with `0` would zero out every result) and `sum = 0`. Digits are visited
right-to-left, which is harmless because both addition and multiplication are
commutative.

## Worked example: `n = 99` → `true`

| iter | digit | sum | product | temp after |
| ---- | ----- | --- | ------- | ---------- |
| 1 | 9 | 9 | 9 | 9 |
| 2 | 9 | 18 | 81 | 0 |

Divisor `= 81 + 18 = 99`, and `99 % 99 == 0`, so the answer is `true`.

## Worked example: `n = 23` → `false`

| iter | digit | sum | product | temp after |
| ---- | ----- | --- | ------- | ---------- |
| 1 | 3 | 3 | 3 | 2 |
| 2 | 2 | 5 | 6 | 0 |

Divisor `= 6 + 5 = 11`, and `23 % 11 == 1`, so the answer is `false`.

## Worked example: `n = 105` → `false`

| iter | digit | sum | product | temp after |
| ---- | ----- | --- | ------- | ---------- |
| 1 | 5 | 5 | 5 | 10 |
| 2 | 0 | 5 | 0 | 1 |
| 3 | 1 | 6 | 0 | 0 |

The zero digit collapses `product` to `0` permanently. Divisor `= 0 + 6 = 6`, and
`105 % 6 == 3`, so the answer is `false`.

## Consequences worth noting

- **A zero digit removes the product entirely.** For any `n` containing a `0`, the
test degenerates to "is `n` divisible by its digit sum?".
- **Digit sum `1` always returns `true`.** For `10`, `100`, ..., `1000000` the divisor
is `1`, and every integer is divisible by `1`.
- **No single-digit `n` ever returns `true`.** A lone digit `d` gives divisor
$$d + d = 2d$$, and $$d \bmod 2d = d \ne 0$$ for every $$d \ge 1$$. So `1`, `5`,
and `9` all return `false`.
- **The divisor is never zero.** Since $$n \ge 1$$ the leading digit is at least `1`,
hence $$S \ge 1$$; with $$P \ge 0$$ this gives $$P + S \ge 1$$ and the modulo is
always well defined.
- **No 32-bit overflow.** Under $$n \le 10^6$$ the digit product peaks at
$$9^6 = 531441$$ (at `999999`), far below the `i32` limit, so Rust's `i32`
arithmetic is safe without widening.

# Complexity

- Time complexity: $$O(\log_{10} n)$$ — one iteration per decimal digit, at most 7
iterations for $$n \le 10^6$$.
- Space complexity: $$O(1)$$ — three scalar accumulators, no digit buffer.

Converting `n` to a string and folding over its characters is equally correct but
allocates; the arithmetic peel avoids that allocation entirely.

# Code

## Go

```go
func checkDivisibility(n int) bool {
temp := n
product, sum := 1, 0
for temp > 0 {
digit := temp % 10
product *= digit
sum += digit
temp /= 10
}
return n % (product + sum) == 0
}
```

## Rust

```rust
impl Solution {
pub fn check_divisibility(n: i32) -> bool {
let (mut product, mut sum, mut temp) = (1, 0, n);
while temp > 0 {
let digit = temp % 10;
product *= digit;
sum += digit;
temp /= 10;
}
n % (product + sum) == 0
}
}
```

# Test cases

| `n` | product | sum | divisor | `n % divisor` | result |
| --------- | ------- | --- | ------- | ------------- | ------- |
| `99` | 81 | 18 | 99 | 0 | `true` |
| `23` | 6 | 5 | 11 | 1 | `false` |
| `1` | 1 | 1 | 2 | 1 | `false` |
| `9` | 9 | 9 | 18 | 9 | `false` |
| `10` | 0 | 1 | 1 | 0 | `true` |
| `20` | 0 | 2 | 2 | 0 | `true` |
| `12` | 2 | 3 | 5 | 2 | `false` |
| `36` | 18 | 9 | 27 | 9 | `false` |
| `105` | 0 | 6 | 6 | 3 | `false` |
| `1000000` | 0 | 1 | 1 | 0 | `true` |

Sweeping the full constraint range, 54669 of the 1000000 values in
$$[1, 10^6]$$ return `true`.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ Easy/350.Intersection-of-Two-Arrays-II/

## Solutions index

Total: **201** problems with at least one solution file.
Total: **202** problems with at least one solution file.

Solution links use variant names when multiple approaches or languages exist (`main` = `solution.md`, others = `solution-<variant>.md`).

### Easy (51)
### Easy (52)

| Problem | LeetCode | Solution |
| ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
Expand Down Expand Up @@ -74,6 +74,7 @@ Solution links use variant names when multiple approaches or languages exist (`m
| 3375. Minimum Operations to Make Array Values Equal to k | [Link](https://leetcode.com/problems/minimum-operations-to-make-array-values-equal-to-k/) | [main](Easy/3375.Minimum-Operations-to-Make-Array-Values-Equal-to-k/solution.md) |
| 3471. Find the Largest Almost Missing Integer | [Link](https://leetcode.com/problems/find-the-largest-almost-missing-integer/) | [main](Easy/3471.Find-the-Largest-Almost-Missing-Integer/solution.md) |
| 3536. Maximum Product of Two Digits | [Link](https://leetcode.com/problems/maximum-product-of-two-digits/) | [main](Easy/3536.Maximum-Product-of-Two-Digits/solution.md) |
| 3622. Check Divisibility by Digit Sum and Product | [Link](https://leetcode.com/problems/check-divisibility-by-digit-sum-and-product/) | [main](Easy/3622.Check-Divisibility-by-Digit-Sum-and-Product/solution.md) |
| 3637. Trionic Array I | [Link](https://leetcode.com/problems/trionic-array-i/) | [main](Easy/3637.Trionic-Array-I/solution.md) |
| 3658. GCD of Odd and Even Sums | [Link](https://leetcode.com/problems/gcd-of-odd-and-even-sums/) | [main](Easy/3658.GCD-of-Odd-and-Even-Sums/solution.md) |
| 3731. Find Missing Elements | [Link](https://leetcode.com/problems/find-missing-elements/) | [main](Easy/3731.Find-Missing-Elements/solution.md) |
Expand Down
1 change: 1 addition & 0 deletions SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
* [3375. Minimum Operations to Make Array Values Equal to k](Easy/3375.Minimum-Operations-to-Make-Array-Values-Equal-to-k/solution.md)
* [3471. Find the Largest Almost Missing Integer](Easy/3471.Find-the-Largest-Almost-Missing-Integer/solution.md)
* [3536. Maximum Product of Two Digits](Easy/3536.Maximum-Product-of-Two-Digits/solution.md)
* [3622. Check Divisibility by Digit Sum and Product](Easy/3622.Check-Divisibility-by-Digit-Sum-and-Product/solution.md)
* [3637. Trionic Array I](Easy/3637.Trionic-Array-I/solution.md)
* [3658. GCD of Odd and Even Sums](Easy/3658.GCD-of-Odd-and-Even-Sums/solution.md)
* [3731. Find Missing Elements](Easy/3731.Find-Missing-Elements/solution.md)
Expand Down
Loading
Loading