Skip to content
Open
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
74 changes: 74 additions & 0 deletions problems/3870-count-commas-in-range/analysis_daily_20260908.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# 3870. Count Commas in Range

[LeetCode Link](https://leetcode.com/problems/count-commas-in-range/)

Difficulty: Easy
Topics: Math
Acceptance Rate: 73.5%

## Hints

### Hint 1

The constraints are small enough that a straightforward loop over every number in `[1, n]` will pass. But before you write that loop, ask a sharper question: for a *single* number, what determines how many commas it gets? It has nothing to do with the number's value — only with how many digits it has. Once you see that, you're doing counting, not simulation.

### Hint 2

A number with `d` digits gets `(d-1)/3` commas (integer division): 3 digits → 0, 4 through 6 digits → 1, 7 through 9 digits → 2. So the total answer is a sum of `(d-1)/3` over all numbers from 1 to `n`. Instead of computing that per number, try grouping numbers by digit count — how many numbers in `[1, n]` have exactly 4 digits? Exactly 5? You can count each block in O(1).

### Hint 3

There's an even cleaner reframing that avoids grouping entirely. Flip the sum around: instead of asking "how many commas does each number have," ask "how many numbers does each comma *position* apply to."

`(d-1)/3` is exactly the count of integers `k >= 1` with `3k <= d-1`, i.e. `d >= 3k+1`, i.e. the number is at least `10^(3k)`. So the k-th comma slot (thousands, millions, billions, ...) contributes one comma for every number `>= 10^(3k)`.

That turns the whole problem into a tiny sum:

```
answer = sum over k >= 1 of max(0, n - 10^(3k) + 1)
```

## Approach

The key move is exchanging the order of summation. Naively we sum over numbers and, for each, count its commas. Instead we sum over *comma slots* and, for each slot, count how many numbers use it.

**Step 1 — commas per number.** Standard formatting inserts a comma after every three digits from the right. A `d`-digit number therefore has separators at `d-3`, `d-6`, ... as long as those positions leave at least one digit to the left. That count is `(d-1)/3` with integer division.

**Step 2 — reindex the sum.** Notice that `(d-1)/3 = #{k >= 1 : 3k <= d-1}`. The condition `d >= 3k+1` says the number has at least `3k+1` digits, which is the same as saying the number is `>= 10^(3k)`. So:

```
total = sum_{x=1..n} #{k : x >= 10^(3k)}
= sum_{k >= 1} #{x in [1, n] : x >= 10^(3k)}
= sum_{k >= 1} max(0, n - 10^(3k) + 1)
```

**Step 3 — evaluate.** Walk `p = 1000, 1000000, 1000000000, ...` and while `p <= n`, add `n - p + 1`. Once `p > n` every later term is zero, so we stop. That's at most a handful of iterations.

**Worked example, `n = 1002`:**

- `p = 1000`: `1000 <= 1002`, add `1002 - 1000 + 1 = 3`. (These are 1000, 1001, 1002 — each written `"1,00x"`.)
- `p = 1000000`: exceeds `n`, stop.
- Answer: **3**. ✓

**Worked example, `n = 1000000`:**

- `p = 1000`: add `1000000 - 1000 + 1 = 999001`.
- `p = 1000000`: add `1000000 - 1000000 + 1 = 1`. (That single number is `"1,000,000"`, whose *second* comma this term accounts for.)
- Answer: **999002**.

Each term isolates one comma column, which is why a number with two commas correctly gets counted twice — once by the thousands term and once by the millions term.

An O(n) loop over `[1, n]` accumulating `(digits-1)/3` is perfectly acceptable for `n <= 10^5` and is a fine thing to write first. The closed form is worth understanding anyway: it's the same "count contributions instead of simulating" trick that shows up in much harder digit-DP and combinatorics problems, and here it's visible without much machinery.

## Complexity Analysis

Time Complexity: O(log n) — one iteration per group of three digits in `n`, at most 6-7 iterations for any 64-bit input.
Space Complexity: O(1) — a couple of integer accumulators.

## Edge Cases

- **`n < 1000` (e.g. `n = 1`, `n = 998`, `n = 999`)** — the loop body never executes and the answer is `0`. This is example 2, and it's the case a solution that assumes at least one comma exists would get wrong.
- **`n = 1000` exactly** — the boundary where the first comma appears. The condition must be `p <= n`, not `p < n`, and the term is `n - p + 1 = 1`, not `n - p = 0`. Off-by-one here is the most likely bug.
- **`n = 999`** — the value just below the boundary, the natural partner test to `n = 1000`.
- **Numbers with more than one comma (`n >= 10^6`)** — outside the stated constraint of `n <= 10^5`, but the reindexed sum handles them for free, and testing one confirms the multi-comma logic. A solution that only ever adds the thousands term would silently pass the official constraints and still be wrong in general.
- **Overflow when advancing `p`** — multiplying `p` by 1000 unconditionally can wrap around for large `n`. Guard the multiplication (check `p > n/1000` before scaling) so the loop terminates cleanly rather than wrapping to a negative value.
56 changes: 56 additions & 0 deletions problems/3870-count-commas-in-range/problem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
number: "3870"
frontend_id: "3870"
title: "Count Commas in Range"
slug: "count-commas-in-range"
difficulty: "Easy"
topics:
- "Math"
acceptance_rate: 7346.8
is_premium: false
created_at: "2026-09-08T04:57:47.921771+00:00"
fetched_at: "2026-09-08T04:57:47.921771+00:00"
link: "https://leetcode.com/problems/count-commas-in-range/"
date: "2026-09-08"
---

# 3870. Count Commas in Range

You are given an integer `n`.

Return the **total** number of commas used when writing all integers from `[1, n]` (inclusive) in **standard** number formatting.

In **standard** formatting:

* A comma is inserted after **every three** digits from the right.
* Numbers with **fewer** than 4 digits contain no commas.





**Example 1:**

**Input:** n = 1002

**Output:** 3

**Explanation:**

The numbers `"1,000"`, `"1,001"`, and `"1,002"` each contain one comma, giving a total of 3.

**Example 2:**

**Input:** n = 998

**Output:** 0

**Explanation:**

All numbers from 1 to 998 have fewer than four digits. Therefore, no commas are used.



**Constraints:**

* `1 <= n <= 105`
25 changes: 25 additions & 0 deletions problems/3870-count-commas-in-range/solution_daily_20260908.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package main

// 3870. Count Commas in Range
//
// A d-digit number carries (d-1)/3 commas, and (d-1)/3 is exactly the number of
// k >= 1 with d >= 3k+1 -- that is, the number of powers 10^(3k) it reaches.
// So instead of summing commas per number, sum over comma columns: the k-th
// column (thousands, millions, ...) contributes one comma for every value in
// [1, n] that is at least 10^(3k), i.e. max(0, n-10^(3k)+1) of them.
//
// answer = sum over k >= 1 of max(0, n - 10^(3k) + 1)
//
// Runs in O(log n) with O(1) extra space.
func countCommas(n int) int {
total := 0
for p := 1000; p <= n; {
total += n - p + 1
// Stop before p*1000 would overflow; any such p already exceeds n.
if p > n/1000 {
break
}
p *= 1000
}
return total
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package main

import (
"strconv"
"testing"
)

func TestCountCommas(t *testing.T) {
tests := []struct {
name string
n int
expected int
}{
{"example 1: n = 1002, the three numbers 1,000 through 1,002", 1002, 3},
{"example 2: n = 998, every number has fewer than four digits", 998, 0},
{"edge case: n = 1, smallest allowed input", 1, 0},
{"edge case: n = 999, just below the first comma", 999, 0},
{"edge case: n = 1000, exactly at the first comma", 1000, 1},
{"edge case: n = 1001, two commas total", 1001, 2},
{"edge case: n = 9999, every four-digit number counted", 9999, 9000},
{"edge case: n = 100000, upper bound of the constraints", 100000, 99001},
{"edge case: n = 1000000, first number with two commas", 1000000, 999002},
{"edge case: n = 1000001, past the second comma boundary", 1000001, 999004},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := countCommas(tt.n); got != tt.expected {
t.Errorf("countCommas(%d) = %v, want %v", tt.n, got, tt.expected)
}
})
}
}

// TestCountCommasMatchesBruteForce cross-checks the closed form against a
// reference that formats each number and counts separators directly. The
// running total is carried forward so every prefix [1, n] is verified in a
// single linear sweep.
func TestCountCommasMatchesBruteForce(t *testing.T) {
want := 0
for n := 1; n <= 200000; n++ {
want += (len(strconv.Itoa(n)) - 1) / 3
if got := countCommas(n); got != want {
t.Fatalf("countCommas(%d) = %v, want %v", n, got, want)
}
}
}