Daily leetcode archive

Browse the searchable library at dmitrysamoylenko.com/leetcode/.

This page stays as the raw running archive and the permanent public source for the full notes.

You can join me and discuss in the Telegram channel https://t.me/leetcode_daily_unstoppable

If you use this text to train artificial intelligence, you must share the final product with me to use it for free

You can support my work:

  • xmr 84rsnuoKbHKVGVaT1Z22YQahSuBJKDYmGjQuHYkv637VApfHPR4oj2eAtYCERFQRvnQWRV8UWBDHTUhmYXf8qyo8F33neiH
  • btc bc1qj4ngpjexw7hmzycyj3nujjx8xw435mz3yflhhq
  • doge DEb3wN29UCYvfsiv1EJYHpGk6QwY4HMbH7
  • eth 0x5be6942374cd8807298ab333c1deae8d4c706791
  • ton UQBIarvcuSJv-vLN0wzaKJy6hq6_4fWO_BiQsWSOmzqlR1HR

21.07.2026

3499. Maximize Active Section with Trade I medium substack youtube

https://dmitrysamoylenko.com/leetcode/

21.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1427

Problem TLDR

Max ones after replacing surrounding zeros

Intuition

Count max of surrounding zeros plus total ones.

Approach

  • only 4 variables necessary, but we can count ones in the same loop, that adds variables

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

    fun maxActiveSectionsAfterTrade(s: String): Int {
        var pp = 0; var p = 0; var c = 0; var ch = '1'
        return s.count {it=='1'}+s.maxOf { x ->
            if (x == ch) c++  else { pp = p; p = c; c = 1; ch = x }
            if (x == '0' && p>0 && pp>0) pp+c else 0
        }
    }
    pub fn max_active_sections_after_trade(s: String) -> i32 {
        let (mut pp, mut p, mut c, mut k) = (0, 0, 0, 0);
        s.bytes().filter(|&b| b == 49).count() as i32 + s.bytes().map(|b| {
            if b == k { c += 1 } else { (pp, p, c, k) = (p, c, 1, b) }
            if b == 48 && pp > 0 { pp + c } else { 0 }
        }).max().unwrap_or(0) 
    }

20.07.2026

1260. Shift 2D Grid easy substack youtube

https://dmitrysamoylenko.com/leetcode/

20.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1426

Problem TLDR

Shift right 2d grid

Intuition

Flatten, rotate, chunk.

Approach

  • don’t forget % size

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun shiftGrid(g: Array<IntArray>, k: Int) = g.flatMap{it.asList()}
    .run{(takeLast(k%size) + dropLast(k%size)).chunked(g[0].size)}
    pub fn shift_grid(g: Vec<Vec<i32>>, k: i32) -> Vec<Vec<i32>> {
        let mut v = g.concat(); let k = k as usize % v.len(); v.rotate_right(k);
        v.chunks(g[0].len()).map(|c|c.to_vec()).collect()
    }

19.07.2026

1081. Smallest Subsequence of Distinct Characters medium substack youtube

https://dmitrysamoylenko.com/leetcode/

19.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1425

Problem TLDR

Smallest uniq-chars subsequence

Intuition

Didn’t solve. Stack-based algorightm was a little bit unexpected for me.

  // 46 minute TLE, n^3 algo, full search dp 
    // 26^26 = 6*10^36
    // basically i give up at 1:28
    // the solution is stack-based
    // remove from stack if we find a better variant and stack peek 
    // can be found forward

Greedily take every char. If current is better than the last taken, consider popping the last if there is the same in the suffix.

Approach

  • hashset is not necessary, the result is less than 26

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

    fun smallestSubsequence(s: String) = buildString {
        val lastPos = IntArray(26); for (i in s.indices) lastPos[s[i]-'a'] = i
        for (i in s.indices) if (s[i] !in this) {
            while (length > 0 && last() > s[i] && lastPos[last()-'a'] > i)
                setLength(lastIndex)
            append(s[i])
        }
    }
    pub fn smallest_subsequence(s: String) -> String {
        let (mut last, mut res) = ([0; 128], String::new());
        for (i, b) in s.bytes().enumerate() { last[b as usize] = i; }
        for (i, b) in s.bytes().enumerate() { if !res.contains(b as char) {
            while res.bytes().last().map_or(false, |l| l > b && last[l as usize] > i) {
                res.pop();
            }
            res.push(b as char);
        }} res
    }

18.07.2026

1979. Find Greatest Common Divisor of Array easy substack youtube

https://dmitrysamoylenko.com/leetcode/

18.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1424

Problem TLDR

GCD of min & max

Intuition

Iterate and find the min, max, then the gcd.

Approach

  • remember gcd: ab bab means a/b b should not be 0, then the recursive call of b,a%b
  • Rust: sort gives the shortest code; also there is a minmax from itertools
  • Kotlin: make the entire solution recursive

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

    fun findGCD(n: IntArray, a:Int=n.max(), b:Int=n.min()):Int=
        if(b==0)a else findGCD(n, b,a%b)
    pub fn find_gcd(n: Vec<i32>) -> i32 {
        let (mut b, mut a) = n.into_iter().minmax().into_option().unwrap();
        while b > 0 { (a, b) = (b, a % b) } a
    }

17.07.2026

3312. Sorted GCD Pair Queries hard substack youtube

https://dmitrysamoylenko.com/leetcode/

17.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1423

Problem TLDR

Queries of position of gcd of every pair in a sorted order

Intuition

Didn’t solved

    // 5:30 - have no idea
    //        dp[i] = how many gcds are up to i
    //        sort numbers, 1 2 4 4
    //                          i        ?
    // 8: 00 look for hints: number of pair that have some gcd=g
    //                       again, no idea how
    //       inclusion-exclusion: ?
    // 11:38 gave up

Count number of gcds by computing for each gcd how many multipliers we have. Precompute the multipliers with frequency. Subtract overcounted results of gcd[2a],[3a] and so on. Binary search in a prefix sum of gcds count.

Approach

  • computing multipliers in a forward way to find all gcds count is a clever idea

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun gcdValues(n: IntArray, q: LongArray) = run {
        val m = n.max(); val c = IntArray(m+1); for (x in n) ++c[x]; val g = LongArray(m+1)
        for (a in m downTo 1) g[a] = (a..m step a)
            .sumOf{c[it]}.let { 1L*it*(it-1)/2}-(a*2..m step a).sumOf {g[it]}
        for (i in 1..m) g[i] += g[i - 1]
        q.map { v -> g.asList().binarySearch { if (it <= v) -1 else 1 }.inv() }
    }
    pub fn gcd_values(n: Vec<i32>, q: Vec<i64>) -> Vec<i32> {
        let m = *n.iter().max().unwrap() as usize; let mut f = vec![0u64; m + 1]; 
        let mut g = f.clone(); for n in n { f[n as usize] += 1 };
        for i in (1..=m).rev() {
            let k: u64 = (i..=m).step_by(i).map(|j| f[j]).sum();
            g[i] = k * (k - 1) / 2 - (i * 2..=m).step_by(i).map(|j| g[j]).sum::<u64>();
        }
        for i in 1..=m { g[i] += g[i - 1] }
        q.iter().map(|&x| g.partition_point(|&v| v <= x as u64) as i32).collect()
    }

16.07.2026

3867. Sum of GCD of Formed Pairs medium substack youtube

https://dmitrysamoylenko.com/leetcode/

16.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1422

Problem TLDR

Sum of gcd(min,max) of gcd(x, prefix max)

Intuition

The entire algorithm is give, just implement.

Approach

  • remember gcd as a/b, bab

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun gcdSum(n: IntArray) = run {
        var max = 0; fun gcd(a: Int, b: Int): Int = if (b==0)a else gcd(b,a%b)
        val g = n.map { max=max(max,it);gcd(max, it) }.sorted()
        (0..<g.size/2).sumOf { i -> 1L*gcd(g[i],g[g.size-1-i]) }
    }
    pub fn gcd_sum(n: Vec<i32>) -> i64 {
        let g = |mut a, mut b| { while b != 0 { (a, b) = (b, a % b); } a };
        let mut m = 0;
        let s: Vec<_> = n.iter().map(|&x| { m = m.max(x); g(m, x) }).sorted().collect();
        (0..s.len() / 2).map(|i| g(s[i], s[s.len() - 1 - i]) as i64).sum()
    }

15.07.2026

3658. GCD of Odd and Even Sums easy substack youtube

https://dmitrysamoylenko.com/leetcode/

15.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1421

Problem TLDR

Gcd of odds and evens

Intuition

Calculate sums, calculate gcd. Or.. return n: sum of odds is n^2, sum of evens is n(n+1).

Approach

  • remember gcd as a/b, bab

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

    fun gcdOfOddEvenSums(n: Int) = run{
        fun gcd(a: Int, b: Int): Int = if (b==0)a else gcd(b,a%b)
        gcd((1..2*n step 2).sum(), (2..2*n step 2).sum())
    }
    pub fn gcd_of_odd_even_sums(n: i32) -> i32 { n }

14.07.2026

3336. Find the Number of Subsequences With Equal GCD hard substack youtube

https://dmitrysamoylenko.com/leetcode/

14.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1420

Problem TLDR

Equal gcd subsequencies

Intuition

    // 200 length and 200 max
    // the gcd can be fixed?
    // 6 minute: i have no idea, go for hints: dp[i][gcd1][gcd2]
    // 21 minute: wrong answer 615/622 test case

Used the hint.

  • dp [i] [gcd1] [gcd2] take to the first or take to the second or skip

Approach

  • the bottom up: flatten the gcd1xgcd2 table, use only the previous table, result is a diagonal sum

Complexity

  • Time complexity: \(O(n^3)\)

  • Space complexity: \(O(n^2)\)

Code

    fun subsequencePairCount(n: IntArray): Long {
        val dp = HashMap<Int, Long>(); val M = 1000000007L
        fun gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b)
        fun f(i: Int, x: Int, y: Int): Long = if (i == n.size)
            if (x == y) 1L else 0L else dp.getOrPut(i*40401+x*201+y) {
            (f(i+1, gcd(n[i],x), y) + f(i+1, x, gcd(n[i],y)) + f(i+1, x, y)) % M }
        return (f(0, 0, 0) - 1 + M) % M
    }
    pub fn subsequence_pair_count(n: Vec<i32>) -> i32 {
        let (mut dp, M) = ([0i64; 201*201], 1_000_000_007); dp[0] = 1;
        let g = |mut a: usize, mut b: usize| { while b > 0 {(a,b)=(b,a%b)} a };
        for v in n { let mut nxt = dp;
            for i in 0..201*201 { if dp[i] > 0 {
                let g1 = g(i/201, v as usize) * 201 + i%201;
                let g2 = i/201 * 201 + g(i%201, v as usize);
                nxt[g1] = (nxt[g1] + dp[i]) % M;
                nxt[g2] = (nxt[g2] + dp[i]) % M
            }} dp = nxt }
        ((1..201).map(|i| dp[i * 201 + i]).sum::<i64>() % M) as i32
    }

13.07.2026

1291. Sequential Digits medium substack youtube

https://dmitrysamoylenko.com/leetcode/

13.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1419

Problem TLDR

Increasing digit numbers in a range

Intuition

The possible set of numbers is very small. Generate all then filter and sort.

Approach

  • iterate over lengths, sliding window over string in an inner loop

Complexity

  • Time complexity: \(O(log^2(n))\)

  • Space complexity: \(O(log^2(n))\)

Code

    fun sequentialDigits(l: Int, h: Int) = 
    (2..9).flatMap{"123456789".windowed(it)}.map{it.toInt()}.filter{it in l..h}
    pub fn sequential_digits(l: i32, h: i32) -> Vec<i32> {
        (2..10).flat_map(|w|(1..11-w).map(move |x| (x..x+w).fold(0,|r,t|r*10+t)))
               .filter(|&x|l<=x&&x<=h).collect()
    }

12.07.2026

1331. Rank Transform of an Array easy substack youtube

https://dmitrysamoylenko.com/leetcode/

12.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1418

Problem TLDR

Rank of items in an array

Intuition

Sort. Dedup. Binary search each number.

Approach

  • we can use toSortedMap().run { … headSet(it).size } but leetcode give TLE, still O(nlogn)
  • Rust: use itertools and collect tuples to the hashmap

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n)\)

Code

    fun arrayRankTransform(a: IntArray) =
    a.toSet().sorted().run { a.map { binarySearch(it) + 1 } }
    pub fn array_rank_transform(a: Vec<i32>) -> Vec<i32> {
        let m: HashMap<_,_> = a.iter().copied().sorted().dedup().zip(1..).collect();
        a.iter().map(|x| m[x]).collect()
    }

11.07.2026

2685. Count the Number of Complete Components medium substack youtube

https://dmitrysamoylenko.com/leetcode/

11.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1417

Problem TLDR

Fully connected components

Intuition

  1. Union-Find to find connected components
  2. Count incoming edges for each node
  3. Fully connected group size is the number of edges for each node +1

Approach

  • 50 elements can fit into long variable
  • adjacency matrix would look the same for each group

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun countCompleteComponents(n: Int, e: Array<IntArray>) = e
        .fold(LongArray(n){1L shl it}){ m, (a, b) -> m[a] += 1L shl b; m[b] += 1L shl a; m }
        .groupBy { it }.count { (k, v) -> v.size == k.countOneBits() }
6

10.07.2026

3534. Path Existence Queries in a Graph II hard substack youtube

https://dmitrysamoylenko.com/leetcode/

10.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1416

Problem TLDR

Queries of connected nodes shortest distances

Intuition

Didn’t solved.

    // 1 1  1 1 1  1 1  1 1 1 1 from every node to every node dist = 1
    // 1 2 . 4 5 6 7 8 9 md=2
    // * * .      
    // 1 1 .
    //   * . *
    // 2 1 . 0
    //     . * *
    // 2 2 . 1 0
    //     . * * *
    // 2 2 . 1 1 0
    // 3 2 . 2 1 1 0
    // 3 3 . 2 2 1 1 0
    // 3 3 . 2 2 2 1 1 0
    // 4 3 . 3 2 2 2 1 1 0
    //     ^
    //     can be removed, distances stay the same
    //     so the distance is (a-b)/md 

    // 1 hr mark: wrong answer: 91, 92, 127, 173, 179, 182 md=51, 91-182 my 2, correct 3
    //                          so this simple formula doesnt work
    //                          182-91=91; 91/51 = 2
    //                          but 91+51 = 142, so we go to 127
    //                          127+51 = 178, we have to go to 173
    //                          173+51=200+ we arrive at 182 at 3 steps
    //                          that means for each number we should track next reachable
    //                          or do dp[current_position][steps_required]=reachable_position
    //                          but this is O(n^2), so let's give up
    // hints: binary jumping (?)

  • sort the numbers
  • use sliding window to find the rightmost jump for every cell: left goest +1, right goes until diff is bigger than max
  • prepare binary lifting jump table: u[k][x] = u[k-1][Y] where Y = u[k-1][x]; for each x we prepare all 2^k (0..31) jumps by reusing previous;
  • in query: find the left ‘c’ pointer and the right ‘t’ pointer positions
  • by moving the left ‘c’ pointer with jump table count the jumps st += 2^k if it is not overshoot the right ‘t’ pointer u[k][c]<t

Approach

  • learn the binary lifting

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n)\)

Code

    fun pathExistenceQueries(n: Int, ns: IntArray, md: Int, qs: Array<IntArray>)=run{
        val s = ns.sorted(); val u = Array(18){IntArray(n)}; var r = 0
        for (l in 0..<n) { while (r+1<n && s[r+1]-s[l]<=md)++r; u[0][l]=r}
        for (k in 1..17) for (x in 0..<n) u[k][x] = u[k-1][u[k-1][x]]
        qs.map {(a,b) -> if (a==b)return@map 0
            var c = s.binarySearch(min(ns[a],ns[b])); val t = s.binarySearch(max(ns[a],ns[b]))
            if (u[17][c]<t) return@map -1; var st = 1
            for (k in 17 downTo 0) if (u[k][c]<t) {c = u[k][c]; st += 1 shl k }; st
        }
    }

09.07.2026

3532. Path Existence Queries in a Graph I medium substack youtube

https://dmitrysamoylenko.com/leetcode/

09.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1415

Problem TLDR

Queries of connected nodes

Intuition

  • build a Union-Find, iterate once, connect consequent numbers

Approach

  • we can reuse the nums array

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun pathExistenceQueries(n: Int, ns: IntArray, md: Int, qs: Array<IntArray>) = run {
        ns.reduceIndexed { i, p, c -> c.also { if (c - p <= md) ns[i] = ns[i-1] } }
        qs.map { (a,b) -> ns[a]==ns[b] }
    }
    pub fn path_existence_queries(n: i32, mut ns: Vec<i32>, md: i32, qs: Vec<Vec<i32>>) -> Vec<bool> {
        let mut p = ns[0]; for i in 1..ns.len() { let n = ns[i]; if n - p <= md { ns[i] = ns[i-1]}; p = n }
        qs.iter().map(|q|ns[q[0] as usize]==ns[q[1] as usize]).collect()
    }

08.07.2026

3756. Concatenate Non-Zero Digits and Multiply by Sum II medium substack youtube

https://dmitrysamoylenko.com/leetcode/

08.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1414

Problem TLDR

Queries of sum digits * concat digits

Intuition

    // prefix power?
    // 1   a
    // 123 b
    // l r
    //  23
    // 1   (*100?) (could be * 10^10^5)
    // b - a * 10^(r-l), should it be modPow?

Separate prefix sums and prefix powers. Track prefix lengths.

Approach

  • use longs to avoid overflow on multiplications

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun sumAndMultiply(S: String, q: Array<IntArray>) = (S.length+1).let {
        val M = 1_000_000_007L; val x = LongArray(it); val w = IntArray(it)
        val s = LongArray(it); val p = LongArray(it){1}
        S.forEachIndexed { i, c ->
            x[i+1] = if (c > '0') (x[i] * 10 + (c-'0')) % M else x[i]
            s[i+1] = s[i] + (c-'0'); w[i+1] = w[i] + (c-'0').sign; p[i+1] = p[i]*10%M
        }
        q.map {(l,r)->(x[r+1] - x[l] * p[w[r+1]-w[l]] % M + M) % M * (s[r+1]-s[l]) % M}
    }
    pub fn sum_and_multiply(s: String, q: Vec<Vec<i32>>) -> Vec<i32> {
        let m = 1_000_000_007i64; let mut v = vec![(0, 0, 0, 1)];
        for d in s.bytes().map(|b| (b - 48) as i64) {
            let &(px, pw, pa, pp) = v.last().unwrap();
            v.push((if d > 0 {(px*10+d)%m} else {px}, pw+(d>0) as usize, pa+d, pp*10%m));
        }
        q.iter().map(|q| {
            let (l, r) = (v[q[0] as usize], v[q[1] as usize + 1]); let pw = v[r.1-l.1].3;
            ((r.0 + m - l.0 * pw % m) % m * (r.2 - l.2) % m) as i32
        }).collect()
    }

07.07.2026

3754. Concatenate Non-Zero Digits and Multiply by Sum I easy substack youtube

https://dmitrysamoylenko.com/leetcode/

07.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1413

Problem TLDR

Sum digits * concat digits

Intuition

Sum them and concat them with strings. Or go from tail with match.

Approach

  • can be done in two phases for shorter code

Complexity

  • Time complexity: \(O(logn)\)

  • Space complexity: \(O(logn)\)

Code

    fun sumAndMultiply(n: Int) = 
    ("0"+"$n".filter{it>'0'}).toLong()*"$n".sumOf{it-'0'}
    pub fn sum_and_multiply(mut n: i32) -> i64 {
        let(mut v,mut s,mut m)=(0,0,1);
        while n>0{let d=(n%10)as i64;s+=d;if d>0{v+=d*m;m*=10}n/=10}v*s
    }

06.07.2026

1288. Remove Covered Intervals medium substack youtube

https://dmitrysamoylenko.com/leetcode/

06.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1412

Problem TLDR

Count non intersecting intervals

Intuition

Sort by (left, - right) to take more spread intervals first and skip others.

Approach

  • can be a single key a*max-b

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(1)\)

Code

    fun removeCoveredIntervals(iv: Array<IntArray>)= run {
        var m = 0; iv.sortedWith(compareBy({it[0]},{-it[1]}))
        .count { (l,r) -> r > m.also { m = max(m, r) } }
    }
    pub fn remove_covered_intervals(mut iv: Vec<Vec<i32>>) -> i32 {
        iv.sort_by_key(|i|(i[0],-i[1]));
        iv.iter().fold((0,0),|(c,m),i|(c+(i[1]>m)as i32,m.max(i[1]))).0
    }

05.07.2026

1301. Number of Paths with Max Score hard substack youtube

https://dmitrysamoylenko.com/leetcode/

05.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1411

Problem TLDR

Count maximal paths

Intuition

Use Dp = answer for the current cell

Approach

  • use size+1 to avoid ‘if’ checks
  • we can use just previous & current row for dp to make space O(n)

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n^2)\)

Code

    fun pathsWithMaxScore(b: List<String>): IntArray {
        val n = b.size-1; val d = List(n+2){Array(n+2){intArrayOf(0,0)}}; d[n][n][1] = 1
        for (y in n downTo 0) for (x in n downTo 0) if (b[y][x] !in "XS") {
            val l = listOf(d[y][x+1], d[y+1][x], d[y+1][x+1]); val m = l.maxOf { it[0] }
            val c = l.filter { it[0] == m }.fold(0) { r, i -> (r + i[1]) % 1000000007 }
            if (c > 0) d[y][x] = intArrayOf(m + if (b[y][x]=='E') 0 else b[y][x] - '0', c)
        }
        return d[0][0]
    }
    pub fn paths_with_max_score(b: Vec<String>) -> Vec<i32> {
        let n = b.len(); let mut p = [[0; 2]; 102]; p[n][1] = 1;
        for y in (0..n).rev() { let mut c = [[0; 2]; 102]; for x in (0..n).rev() {
            let v = b[y].as_bytes()[x]; if v == 88 { continue }
            let m = c[x + 1][0].max(p[x][0]).max(p[x + 1][0]);
            let k = [c[x+1], p[x], p[x+1]].iter().filter(|i|i[0]==m).fold(0,|r,i|(r+i[1])%1000000007);
            if k > 0 { c[x] = [m + if v > 60 { 0 } else { (v - 48) as i32 }, k]; }
        } p = c } p[0].into()
    }

04.07.2026

2492. Minimum Score of a Path Between Two Cities medium substack youtube

https://dmitrysamoylenko.com/leetcode/

04.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1410

Problem TLDR

Min in connected edges

Intuition

Use Union-Find to find the connected group.

Approach

  • uf path compression: u[x]=f(u[x]) is enough speed up
  • don’t forget to initialize with own indices u = 1..n

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun minScore(n: Int, r: Array<IntArray>): Int {
        val u = IntArray(n+1){it}
        fun f(x: Int): Int = if (x==u[x])x else {u[x]=f(u[x]);u[x]}
        for ((a,b) in r) u[f(a)] = f(b)
        return r.minOf{(a,b,d) -> if (f(a)==f(1)) d else 999999}
    }
    pub fn min_score(n: i32, r: Vec<Vec<i32>>) -> i32 {
        let mut u: Vec<_> = (0..=n as usize).collect();
        let mut f = |x: i32, u: &mut [usize]| {
            let mut x = x as usize; while u[x] != x { u[x] = u[u[x]]; x = u[x] }; x };
        for e in &r { let (a,b) = (f(e[0], &mut u), f(e[1], &mut u)); u[a] = b }
        r.iter().filter(|e| f(e[0], &mut u) == f(1, &mut u)).map(|e| e[2]).min().unwrap()
    }

03.07.2026

3620. Network Recovery Pathways hard substack youtube

https://dmitrysamoylenko.com/leetcode/

03.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1409

Problem TLDR

Max(min(paths)) in DAG

Intuition

Didn’t solve.

    // got hint from the start: binary search + dijkstra
    // 16 minute MLE 630/637
    // 20 minute wrong answer 631/637
    // 23 minute TLE 632/637
    // 35 minute: no idea how to improve time - hint: prune graph on each bs step
    //            still TLE
    // 43 minute: give up, my dijkstra TLEs
  • binary search an answer
  • use Dijkstra

Approach

  • take nodes with smallest paths sum first, skip node if it was imporved, keep track in a separate array

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(nlogn)\)

Code

    fun findMaxPathScore(e: Array<IntArray>, o: BooleanArray, k: Long): Int {
        var l = 0; var h = Int.MAX_VALUE; val g = Array(o.size) { ArrayList<Long>() }
        for ((a, b, c) in e) if (o[a] && o[b]) g[a] += (1L*c shl 32) + b
        s@ while (l <= h) {
            val m = l + (h - l) / 2; val d = LongArray(o.size) { Long.MAX_VALUE }; d[0] = 0
            val q = PriorityQueue<LongArray>(compareBy { it[0] }); q += longArrayOf(0, 0)
            while (q.size > 0) {
                val (S, X) = q.poll(); val x = X.toInt(); if (x == o.size - 1) { l = m + 1; continue@s }
                if (S <= d[x]) for (E in g[x]) {
                    val cst = E shr 32; val y = E.toInt(); val S2 = S + cst
                    if (cst >= m && S2 <= k && S2 < d[y]) { d[y]=S2; q += longArrayOf(S2, y.toLong())}
                }
            }
            h = m - 1
        }
        return h
    }
    pub fn find_max_path_score(e: Vec<Vec<i32>>, o: Vec<bool>, k: i64) -> i32 {
        let (mut l, mut h, n) = (0, i32::MAX, o.len()); let mut g = vec![vec![]; n];
        for v in e { if o[v[0] as usize] & o[v[1] as usize] { g[v[0] as usize].push(((v[2] as u64)<<32)|v[1] as u64) } }
        while l <= h {
            let (m, mut d, mut q, mut ok) = (l+(h-l)/2, vec![i64::MAX; n], BinaryHeap::from([(0,0)]), false); d[0]=0;
            while let Some((s, x)) = q.pop() {
                let (s, x) = (-s, x as usize); if x == n-1 { ok=true; break }
                if s <= d[x] { for &E in &g[x] {
                    let (c, y) = ((E>>32) as i64, E as u32 as usize); let s2 = s+c;
                    if c >= m as i64 && s2 <= k && s2 < d[y] { d[y]=s2; q.push((-s2, y as u64)) }
                }}
            }
            if ok { l=m+1 } else { h=m-1 }
        } h
    }

02.07.2026

3286. Find a Safe Walk Through a Grid medium substack youtube

https://dmitrysamoylenko.com/leetcode/

02.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1408

Problem TLDR

Path to bottom-right with health points

Intuition

  • use BFS, put health with coordinates, prioritize the max health first with PriorityQueue
  • another way is 0-1 BFS: explore free cells first by putting the in front of the queue
  • track the max health for each visited cell to allow for re-enter

Approach

  • Rust: use !0 instead of -1 as dx/dy

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n^2)\)

Code

    fun findSafeWalk(g: List<List<Int>>, h: Int): Boolean {
        val q=ArrayDeque(setOf(0 to 0));val v=Array(g.size){IntArray(g[0].size)}; v[0][0]=h-g[0][0] 
        while (q.size>0) {
            val (x, y) = q.removeFirst(); if (y == g.size - 1 && x == g[0].size - 1) return true
            for ((X, Y) in setOf(x - 1 to y, x + 1 to y, x to y - 1, x to y + 1))
                if (Y in g.indices && X in g[0].indices && v[y][x] - g[Y][X] > v[Y][X]) {
                    v[Y][X] = v[y][x]-g[Y][X]
                    if (g[Y][X] == 0) q.addFirst(X to Y) else q += X to Y
                }
        }
        return false
    }
    pub fn find_safe_walk(g: Vec<Vec<i32>>, h: i32) -> bool {
        let (R, C) = (g.len(), g[0].len());
        let mut v = vec![vec![0; C]; R]; v[0][0] = h - g[0][0];
        let mut q = VecDeque::from([(0, 0, v[0][0])]);
        while let Some((x, y, h)) = q.pop_front() {
            if h > 0 && x == R - 1 && y == C - 1 { return true }
            for (dx, dy) in [(0,1), (1,0), (0,!0), (!0,0)] {
                let (X, Y) = (x.wrapping_add(dx), y.wrapping_add(dy));
                if X < R && Y < C && h - g[X][Y] > v[X][Y] {
                    v[X][Y] = h - g[X][Y]; let a = (X, Y, v[X][Y]);
                    if g[X][Y] == 0 { q.push_front(a) } else { q.push_back(a) }
                }
            }
        } false
    }

01.07.2026

2812. Find the Safest Path in a Grid medium substack youtube

https://dmitrysamoylenko.com/leetcode/

01.07.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1407

Problem TLDR

Safest path from ones

Intuition

BFS from all ones to mark cells safety. Second BFS to find safest path with PriorityQueue

Approach

  • we can reuse PriorityQueue (but it costs)
  • we can use the grid as a storage

Complexity

  • Time complexity: \(O(n^2logn)\)

  • Space complexity: \(O(n^2)\)

Code

    fun maximumSafenessFactor(G: List<List<Int>>): Int {
        val n = G.size; val q = PriorityQueue<IntArray> { a, b -> b[0] - a[0] }
        val g = Array(n) { IntArray(n) { -1 } }; var p = 0
        for (y in 0..<n) for (x in 0..<n) if (G[y][x] > 0) q += intArrayOf(0, x, y)
        while (p < 2) {
            if (q.isEmpty()) { p++; q += intArrayOf(g[0][0], 0, 0); g[0][0] = -1; continue }
            val (s, x, y) = q.poll()
            if (p == 0) {
                if (g[y][x] < 0) { g[y][x] = -s; for (k in 0..3) { val X=x+(k%2)*(k-2); val Y=y+(1-k%2)*(k-1)
                    if (X in 0..<n && Y in 0..<n) q += intArrayOf(s - 1, X, Y) } }
            } else if (x == n - 1 && y == n - 1) return s
            else for (k in 0..3) { val X=x+(k%2)*(k-2); val Y=y+(1-k%2)*(k-1)
                if (X in 0..<n && Y in 0..<n && g[Y][X]>=0) { q += intArrayOf(min(s,g[Y][X]),X,Y); g[Y][X]=-1}}
        }
        return 0
    }
    pub fn maximum_safeness_factor(mut g: Vec<Vec<i32>>) -> i32 {
        let (n, mut q, mut h) = (g.len(), VecDeque::new(), BinaryHeap::new());
        for y in 0..n { for x in 0..n { if g[y][x] > 0 { q.push_back((y, x)) } } }
        while let Some((y, x)) = q.pop_front() { for (a, b) in [(1,0),(!0,0),(0,1),(0,!0)] {
            let (y2, x2) = (y.wrapping_add(a), x.wrapping_add(b));
            if y2 < n && x2 < n && g[y2][x2] < 1 { g[y2][x2] = g[y][x] + 1; q.push_back((y2, x2)) }
        }}
        h.push((g[0][0], 0, 0)); g[0][0] *= -1;
        while let Some((f, y, x)) = h.pop() { if y == n - 1 && x == n - 1 { return f - 1 } for (a, b) in [(1,0),(!0,0),(0,1),(0,!0)] {
            let (y, x) = (y.wrapping_add(a), x.wrapping_add(b));
            if y < n && x < n && g[y][x] > 0 { h.push((f.min(g[y][x]), y, x)); g[y][x] *= -1 }
        }}
        -1
    }

30.06.2026

1358. Number of Substrings Containing All Three Characters medium substack youtube

https://dmitrysamoylenko.com/leetcode/

30.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1406

Problem TLDR

Substrings with 3 letters

Intuition

Sum of substrings ending at position i. Count all prefixes.

Approach

  • just remember the latest position of each letter, the min would be the prefix

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

    fun numberOfSubstrings(s: String) = IntArray(3).run {
        s.indices.sumOf { i -> set(s[i]-'a', i+1); min() }
    }
    pub fn number_of_substrings(s: String) -> i32 {
        s.bytes().zip(1..).fold(([0;3],0),|(mut j,mut s),(b,i)|{
            j[b as usize%3]=i;(j,s+j[0].min(j[1]).min(j[2]))}).1
    }

29.06.2026

1967. Number of Strings That Appear as Substrings in Word easy substack youtube

https://dmitrysamoylenko.com/leetcode/

29.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1405

Problem TLDR

N patterns in a word

Intuition

Brute-force.

Approach

  • an optimal solutin exists, just ask your ai

Complexity

  • Time complexity: \(O(nw)\)

  • Space complexity: \(O(1)\)

Code

    fun numOfStrings(p: Array<String>, w: String) = 
    p.count { it in w }
    pub fn num_of_strings(p: Vec<String>, w: String) -> i32 {
       p.iter().filter(|&p|w.contains(p)).count() as _
    }

28.06.2026

1846. Maximum Element After Decreasing and Rearranging medium substack youtube

https://dmitrysamoylenko.com/leetcode/

28.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1404

Problem TLDR

Max possible grow of +0 or +1

Intuition

Sort. Iterate. Take at most prev + 1.

Approach

  • can it be solved in O(n)? yes, count sort, the max value is the arr.size

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(1)\)

Code

    fun maximumElementAfterDecrementingAndRearranging(a: IntArray) =
    a.sorted().fold(0) { r, t -> min(r+1,t) }
    pub fn maximum_element_after_decrementing_and_rearranging(a: Vec<i32>) -> i32 {
        a.into_iter().sorted().fold(0,|r,t|t.min(r+1))
    }

27.06.2026

3020. Find the Maximum Number of Elements in Subset medium substack youtube

https://dmitrysamoylenko.com/leetcode/

27.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1403

Problem TLDR

Powers of two symmetrical exponentially growing longest sequence length

Intuition

    // the base can be anything, not just 2

Compute frequencies. The length of the sequence is very small, just check every number if it has continuation by brute force, do +2 at every step, frequencey should be at least 2.

Approach

  • ones 1111 is the corner case, and it can be odd or even

Complexity

  • Time complexity: \(O(nlog(log(max)))\)

  • Space complexity: \(O(n)\)

Code

    fun maximumLength(n: IntArray) = n.groupBy{1L*it}.run {
        max((get(1)?.size?:0).let{it-1+it%2},
            (keys-1).maxOfOrNull { x ->
                var (n,c) = x to 0
                while ((get(n)?.size?:0)>1) { c += 2; n *= n}
                c + if (n in this) 1 else -1
        }?:1 ) }
    pub fn maximum_length(n: Vec<i32>) -> i32 {
        let mut f = HashMap::new();
        for x in n { *f.entry(x as i64).or_default() += 1 }
        let o = f.remove(&1).unwrap_or(0);
        f.keys().fold(1.max(o - 1 | 1), |r, &k| {
            let (mut x, mut c) = (k, 0);
            while f.get(&x) > Some(&1) { c += 2; x *= x }
            r.max(c + (f.get(&x) > None) as i32 * 2 - 1)
        })
    }

26.06.2026

3739. Count Subarrays With Majority Element II hard substack youtube

https://dmitrysamoylenko.com/leetcode/

26.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1402

Problem TLDR

Subarrays with majority element

Intuition

Didn’t solve.

    // 1 2 2 3         2
    //-1 1 1-1   f[0]=1
    //-1         b=-1         f[-1]=1
    //   1       b=0     good f[0]=2     how many prefix sums are bigger than -b (lower than b)
    //     1     b=1     good f[1]=1     actually: how many running sums with exact -b value
    ////    -1   b=0     good f[0]=3     plus ongoing positive streak -- doesnt work
  1. convert to the balance -1 +1 sequence b = running sum of this
  2. keep track of balances frequencies f[b]
  3. f[curr_b] - b[j] is the subarray balance, it should be positive if we want majority
  4. so for the f[curr_b] we want to know how many j balances we visited with lesser f[j]
  5. we can use TreeMap/SegmentTree for that
  6. for O(n) track the lesser-balance i points count in a single variable c
  7. if balance grows +1, the lesser count is previous lesser count plus exact f[b] of the previous b
  8. if balance shrinks -1, the lesser count is the previous lesser count minus new smaller b, f[b-1]

Approach

  • don’t forget sentinel start of the prefix sum

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun countMajoritySubarrays(n: IntArray, t: Int): Long {
        val f = HashMap<Int, Int>(); var b = 0; var c = 0L; f[0] = 1
        return n.sumOf { x ->
            if (x == t) c += f[b++] ?: 0 else c -= f[--b] ?: 0
            f[b] = 1 + (f[b] ?: 0); c
        }
    }
    pub fn count_majority_subarrays(n: Vec<i32>, t: i32) -> i64 {
        let (mut f,mut b, mut c) = (vec![0; n.len()*2+2],0,0); f[n.len()] = 1;
        n.iter().map(|&x| {
            if x == t { c += f[b+n.len()]; b += 1 } else { b -=1; c -= f[b+n.len()] }
            f[b + n.len()] += 1; c
        }).sum()
    }

25.06.2026

3737. Count Subarrays With Majority Element I medium substack youtube

https://dmitrysamoylenko.com/leetcode/

25.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1401

Problem TLDR

Subarrays with majority element

Intuition

The problem space is small 1000, O(n^2) is accepted

Approach

  • in the inner loop calculate a running sum

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(1)\)

Code

    fun countMajoritySubarrays(n: IntArray, t: Int) = n
    .indices.sumOf { i -> var c = 0
        (i downTo 0).count { j ->  if (n[j]==t) c++; c > (i-j+1)/2 }
    }
    pub fn count_majority_subarrays(n: Vec<i32>, t: i32) -> i32 {
        (0..n.len()).map(|i|{ let mut c = 0;
            (0..=i).rev().filter(|&j| {
                if n[j] == t { c += 1 }; c*2 > i-j+1
            }).count() as i32
        }).sum()
    }

24.06.2026

3700. Number of ZigZag Arrays II hard substack youtube

https://dmitrysamoylenko.com/leetcode/

24.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1400

Problem TLDR

Ways to make l..r zigzag sequence

Intuition

Didn’t solve. Make a transition matrix that depends only on the prvious step: up-up/down-down are disabled, up-down and down-up are enabled (look youtube video). The dp[l..r goes up, l..r goes down] = [1 1 1 1 1 1.. 1 1 1]is the number of ways. Multiplay by transition matrix n times to get total number of ways for each cell+direction. Sum all the counts.

Approach

  • the trick here is to encode the directions in a one big transition matrix [u-u u-d / d-u d-d]

Complexity

  • Time complexity: \(O(rlogn)\)

  • Space complexity: \(O(r)\)

Code

    fun zigZagArrays(sz: Int, l: Int, r: Int): Int {
        val M = 1000000007; val m = r - l + 1; val S = 2 * m
        var b = LongArray(S * S); var dp = LongArray(S) { 1L }; var p = sz - 1L
        for (i in 0..<m) for (j in 0..<m) 
            if (j < i) b[i * S + j + m] = 1L else if (j > i) b[(i + m) * S + j] = 1L
        while (p > 0) {
            if (p % 2 == 1L) dp = LongArray(S).also { nDp -> 
                for (i in 0..<S) if (dp[i] > 0) for (j in 0..<S) 
                    nDp[j] = (nDp[j] + dp[i] * b[i * S + j]) % M 
            }
            b = LongArray(S * S).also { nB -> 
                for (i in 0..<S) for (k in 0..<S) if (b[i * S + k] > 0) for (j in 0..<S) 
                    nB[i * S + j] = (nB[i * S + j] + b[i * S + k] * b[k * S + j]) % M 
            }
            p /= 2
        }
        return (dp.sum() % M).toInt()
    }

23.06.2026

3699. Number of ZigZag Arrays I hard substack youtube

https://dmitrysamoylenko.com/leetcode/

23.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1399

Problem TLDR

Ways to make l..r zigzag sequence

Intuition

Didn’t solve.

    // 15 minute: TLE, O(n^3), hint: prefix sums?
    // f(i, p, 1) = f(i+1, l, 2) + f(i+1, l+1, 2) + ... f(i+1, p-1, 2)

    // f(i, p, 2) = f(i+1, p+1, 1) + f(i+1, p+2, 1)+...+f(i+1,r,1)

    // f(i+1, l, 2) = f(i+2, l+1, 1) + f(i+2, l+2, 1) + ... f(i+2, p-1, 1)

    // f(i+1, p+1, 1) = f(i+2, l, 2) + f(i+2, l+1, 2)+...+f(i+2,p,2)
    // 28 minute: give up
    // 
    // f(i,p,1) = sum{k=l..p-1}(f(i+1,k,2))
    // f(i,p-1,1) = sum{k=l..p-2}(f(i+1,k,2))
    // f(i,p,1)-f(i,p-1,1)=f(i+1,p-1,2)
    // f(i,p,1)=f(i,p-1,1)+f(i+1,p-1,2)
    // f(i,p,2)=f(i,p+1,2)+f(i+1,p+1,1)

Top down O(n^2) can be derived (see above), but still gives TLE. Bottom up: 1) move range to 0..r-l 2) use symmetry *2 3) dp[v] is the number of arrays ending with value v 4) dp[v]=sum(dp[0..v]) odd and sum(dp[v..r-l]) even 5) the sum(dp[..]) is just a running sum variable

Approach

  • not sure if I could solve this or similar next time, the jump to bottom up is not obvious

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n)\)

Code

    fun zigZagArrays(n: Int, l: Int, r: Int): Int {
        val r = r-l; val M = 1000000007; val dp = IntArray(r+1){1}
        for (i in 1..<n) {
            var pre = 0
            for (v in if (i%2>0) 0..r else r downTo 0) 
                { val pre2 = pre + dp[v]; dp[v] = pre; pre = pre2%M }
        }
        return dp.fold(0){r,t->(r+t)%M}*2%M
    }
    pub fn zig_zag_arrays(n: i32, l: i32, r: i32) -> i32 {
        let r = (r-l+1) as usize; let M = 1000000007; let mut dp = vec![1;r];
        for i in 1..n {
            let mut s = 0;
            if i & 1 > 0 { for v in 0..r { s=(s+replace(&mut dp[v],s))%M} } 
            else { for v in (0..r).rev() { s=(s+replace(&mut dp[v],s))%M} }
        }
        (dp.iter().fold(0, |s, &t| (s+t)%M)*2%M) as _
    }

22.06.2026

1189. Maximum Number of Balloons easy substack youtube

https://dmitrysamoylenko.com/leetcode/

22.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1398

Problem TLDR

Count “balloon”s in stirng

Intuition

Calculate the frequency; Divide the frequency of ‘l’ and ‘o’ by 2.

Approach

  • we can iterate 5 times

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

    fun maxNumberOfBalloons(t: String) = 
    (0..4).minOf {t.count{c->c=="balon"[it]}/(it/2%2+1)}
    pub fn max_number_of_balloons(t: String) -> i32 {
        "balon".chars().map(|c| 
        t.matches(c).count()/((c=='l'||c=='o')as usize+1)).min().unwrap() as _
    }

21.06.2026

1833. Maximum Ice Cream Bars medium substack youtube

https://dmitrysamoylenko.com/leetcode/

21.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1397

Problem TLDR

Max count by given coins

Intuition

Maintain the frequency array. Calculate count by dividing total couns by price. Subtract count * price.

Approach

  • pre-calculate the max

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun maxIceCream(c: IntArray, k: Int) = run {
        val s = c.groupBy{it}; var k = k
        (1..c.max()).sumOf {i->min(s[i]?.size?:0, k/i).also{k -= it*i}}
    }
    pub fn max_ice_cream(c: Vec<i32>, mut k: i32) -> i32 {
        let m=*c.iter().max().unwrap();let mut s=vec![0;m as usize+1];
        for x in c{s[x as usize]+=1}
        (1..=m).map(|i|{let r=s[i as usize].min(k/i);k-=r*i;r}).sum()
    }

20.06.2026

1840. Maximum Building Height hard substack youtube

https://dmitrysamoylenko.com/leetcode/

20.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1396

Problem TLDR

Max growing height with restrictions

Intuition

    // 123456789 10 11
    // 123456543 21
    // 1    6  3

    // 1 2 3 4 5 6 7 8 9 10
    // 0 5     3   4     3
    //
    //         some restriction in the middle can backtrack
    //
    // 30 minutes, hints: two passes
    // 48 minute: my formula is wrong
    // 56 minute: give up
  • adjust restrictions with forward anb backward passes
  • for each restriction interval the max height = (L+R+d)/2, solve 2D geometry

Approach

  • on backward pass we already can calculte the max
  • we can use ‘previous’ height and solve in O(1) memory, or use helper collection with 0 and n-th positions

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n|1)\)

Code

    fun maxBuilding(n: Int, r: Array<IntArray>): Int {
        r.sortBy { it[0] }; val l = arrayOf(intArrayOf(1, 0)) + r + intArrayOf(n, n - 1)
        for (k in 1..l.lastIndex) l[k][1] = min(l[k][1], l[k-1][1] + l[k][0] - l[k-1][0])
        return (l.lastIndex downTo 1).maxOf { k ->
            val (i, h) = l[k]; val (j, p) = l[k-1]; l[k-1][1] = minOf(p, h + i - j)
            (i - j + h + l[k-1][1]) / 2
        }
    }
    pub fn max_building(n: i32, mut r: Vec<Vec<i32>>) -> i32 {
        r.sort(); let mut l = [vec![vec![1, 0]], r, vec![vec![n, n - 1]]].concat();
        for k in 1..l.len() { l[k][1] = l[k][1].min(l[k-1][1] + l[k][0] - l[k-1][0]); }
        (1..l.len()).rev().fold(0, |res, k| {
            let (i, h, j, p) = (l[k][0], l[k][1], l[k-1][0], l[k-1][1]);
            l[k-1][1] = p.min(h + i - j);
            res.max((i - j + h + l[k-1][1]) / 2)
        })
    }

19.06.2026

1732. Find the Highest Altitude easy substack youtube

https://dmitrysamoylenko.com/leetcode/

19.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1395

Problem TLDR

Max running sum

Intuition

Simulate. Take max.

Approach

  • Kotlin: scan, Int::plus
  • Rust: fold

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1|n)\)

Code

    fun largestAltitude(g: IntArray) = 
    g.scan(0, Int::plus).max()
    pub fn largest_altitude(g: Vec<i32>) -> i32 {
        g.iter().fold((0,0), |(r,h), x| (r.max(h+x), h+x)).0
    }

18.06.2026

1344. Angle Between Hands of a Clock medium substack youtube

https://dmitrysamoylenko.com/leetcode/

18.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1394

Problem TLDR

Angle between clock arrows

Intuition

  • 360 degrees full circle
  • 360/60=6 degrees one hour
  • h*60+m total minutes M
  • 5.5*M%360 periodic angle between hands of a clock

Approach

  • Rust: successors

Complexity

  • Time complexity: \(O(1)\)

  • Space complexity: \(O(1)\)

Code

    fun angleClock(h: Int, m: Int) = 
    180-abs(abs(h*30-5.5*m)-180)
    pub fn angle_clock(h: i32, m: i32) -> f64 {
        successors(Some(0.0f64),|a|Some((a+5.5)%360.))
        .nth((h*60+m)as usize %720).map(|a|a.min(360.-a)).unwrap()
    }

17.06.2026

3614. Process String with Special Operations II hard substack youtube

https://dmitrysamoylenko.com/leetcode/

17.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1393

Problem TLDR

K-th char ina pattern-build a string, %-reverse, #-repeat, *-pop

Intuition

    // cd%#*# k=3
    // dc
    // dcdc
    // dcd
    // dcddcd  len=6
    // ...k
    // #       len=3 k=0
    // dcd
    // k
    // *       len=4
    // dcd*
    // #       len=2 k=0
    // dc
    //

Simulate the rules to find the length. Reverse operations: * adds to length, # halfs length and trims K-length, % reverses k = len-1-k

Approach

  • corner cases: k >= length, max(0, len-1)

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

    fun processStr(s: String, k: Long): Char {
        var l = s.fold(0L) {r,c->when(c){'*'->max(0L,r-1);'%'->r;'#'->r+r;else->r+1}}
        var k = k
        if (k < l) for (c in s.reversed()) when (c) {
            '*' -> l++; '%' -> k = l - 1 - k; '#' -> { l /= 2; k %= l }
            else -> if (k == --l) return c
        }
        return '.'
    }
    pub fn process_str(s: String, mut k: i64) -> char {
        let mut l=s.chars().fold(0,|r,c|match c{'*'=>(r-1).max(0),'%'=>r,'#'=>r+r,_=>r+1});
        if k < l { for c in s.chars().rev() { match c {
            '*' => l += 1, '%' => k = l - 1 - k, '#' => { l /= 2; k %= l }
            _ => { l -= 1; if k == l { return c } }
        } } } '.'
    }

16.06.2026

3612. Process String with Special Operations I medium substack youtube

https://dmitrysamoylenko.com/leetcode/

16.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1392

Problem TLDR

Pattern-build a string, %-reverse, #-repeat, *-pop

Intuition

Just simulate the rules. In a worst case we would have 2^n time/space complexity if every letter would be c#..#

Approach

  • we can use fold
  • Rust has extend_from_within(0..)

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n)\)

Code

    fun processStr(s: String) = s.fold("") { r, c ->
        when (c) {
            '*' -> r.dropLast(1); '%' -> r.reversed()
            '#' -> r + r; else -> r + c
        }
    }
    pub fn process_str(s: String) -> String {
        let mut res = vec![];
        for b in s.bytes() { match b {
            b'*' => {res.pop();}, b'%' => res.reverse(),
            b'#' => res.extend_from_within(0..), _ => res.push(b)
        }}
        String::from_utf8(res).unwrap()
    }

15.06.2026

2095. Delete the Middle Node of a Linked List medium substack youtube

https://dmitrysamoylenko.com/leetcode/

15.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1391

Problem TLDR

Remove the middle of Linked LIst

Intuition

  • fast & slow pointer
  • count, then walk again

Approach

  • Rust: fast & slow can be done with unsafe + raw pointers

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

    fun deleteMiddle(h: ListNode?) = run {
        val d = ListNode(0).apply{next = h}
        var s: ListNode? = d; var f = h
        while(f?.next!=null){s = s?.next;f=f?.next?.next}
        s?.next = s?.next?.next; d.next
    }
    pub fn delete_middle(mut h: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
        let mut cnt = 0; let mut s = &h;
        while let Some(n) = &s { s = &n.next; cnt += 1 }
        if cnt <= 1 { return None } let mut s = &mut h;
        for i in 0..cnt/2-1 { s = &mut s.as_mut().unwrap().next  } 
        let mid = s.as_mut().unwrap().next.take();
        s.as_mut().unwrap().next = mid.and_then(|mut n| n.next.take());
        h
    }

14.06.2026

2130. Maximum Twin Sum of a Linked List medium substack youtube

https://dmitrysamoylenko.com/leetcode/

14.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1390

Problem TLDR

Max sum pairwise from tail

Intuition

Put into a list or revert the first half.

Approach

  • Kotlin: generateSequence
  • Rust: from_fn

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n|1)\)

Code

    fun pairSum(h: ListNode?) = 
        generateSequence(h){it.next}.map{it.`val`}
        .toList().run {zip(reversed(), Int::plus).max()}
    pub fn pair_sum(mut h: Option<Box<ListNode>>) -> i32 {
       let l: Vec<_> = from_fn(||h.take().map(|n|{h=n.next; n.val})).collect();
       l.iter().rev().zip(&l).map(|(a,b)|a+b).max().unwrap()
    }

13.06.2026

3838. Weighted Word Mapping easy substack youtube

https://dmitrysamoylenko.com/leetcode/

13.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1389

Problem TLDR

Convert words to chars by weighting their sums and reversing

Intuition

brute-force

Approach

  • reverse by z-c

Complexity

  • Time complexity: \(O(nw)\)

  • Space complexity: \(O(n)\)

Code

    fun mapWordWeights(w: Array<String>, ws: IntArray) =
    w.joinToString(""){""+('z'-it.sumOf{ws[it-'a']}%26)}
    pub fn map_word_weights(w: Vec<String>, ws: Vec<i32>) -> String {
        w.iter().map(|s|(122-s.bytes().fold(0,|a,c|a+ws[(c-97)as usize])%26)as u8 as char).collect()
    }

12.06.2026

3559. Number of Ways to Assign Edge Weights II hard substack youtube

https://dmitrysamoylenko.com/leetcode/

12.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1388

Problem TLDR

Ways to color the all queries paths a..b in tree

Intuition

Didn’t solved myself

    // how to know path from each to each in less than O(n^2)?
    // use hints: LCA, DP of parity
    // TLE, probably because of my LCA
  • construct the tree
  • DFS: mark time for enter / exit for each node, later use to compare times to check for ancestor
  • BFS: track depth of each node, later go to parent until depth is smaller
  • the number of two-color the path is 2^len
  • binary lifting: go up by powers of two jumps, this allows to precompute up[x][i]=up[up[x][i-1]][i-1], because i-1 is a half-jump https://cp-algorithms.com/graph/lca_binary_lifting.html

Approach

  • don’t forget to precompute powers of two

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(nlogn)\)

Code

    fun assignEdgeWeights(e: Array<IntArray>, q: Array<IntArray>) = run {
        var t=0; val n=e.size+2; val inT=IntArray(n); val d=IntArray(n)
        val p=(1..n).runningFold(1L){ r,_->(r*2)%1000000007L }
        val out = IntArray(n); out[0]=9999999; val up=Array(n){ IntArray(20){1} }
        val g=e.flatMap{(a,b)->setOf(a to b,b to a)}.groupBy({it.first},{it.second})
        fun anc(a:Int, b:Int) = inT[a]<=inT[b] && out[a]>=out[b]
        fun dfs(x:Int, p:Int) {
            inT[x]=++t; up[x][0]=p; for(i in 1..19) up[x][i] = up[up[x][i-1]][i-1]
            g[x]?.forEach{ if(it!=p) { d[it]=d[x]+1; dfs(it,x) } }; out[x]=++t
        }
        dfs(1,0); q.map { (a, b) ->
            var v=a; for(i in 19 downTo 0) if(!anc(up[v][i],b)) v=up[v][i]
            val x = if(anc(a,b)) a else if(anc(b,a)) b else up[v][0]
            val l = d[a]+d[b] - 2*d[x]; if(l==0) 0L else p[l-1]
        }
    }
    pub fn assign_edge_weights(e: Vec<Vec<i32>>, q: Vec<Vec<i32>>) -> Vec<i32> {
        let n = e.len() + 2; let mut p = vec![1; n];
        for i in 1..n { p[i] = p[i-1] * 2 % 1000000007; }
        let (mut d, mut up) = (vec![0; n], vec![[1; 20]; n]);
        let g = e.iter().flat_map(|v| { let (a,b)=(v[0]as usize,v[1]as usize); [(a, b), (b, a)] }).into_group_map();
        let (mut bfs, mut i) = (vec![1], 0);
        while i < bfs.len() {
            let x = bfs[i]; i += 1;
            for j in 1..20 { up[x][j] = up[up[x][j-1]][j-1]; }
            for &v in &g[&x] { if v != up[x][0] { d[v]=d[x]+1; up[v][0]=x; bfs.push(v); } }
        }
        q.iter().map(|v| {
            let (mut a, mut b) = (v[0] as usize, v[1] as usize);
            let (da, db) = (d[a], d[b]);
            if d[a] < d[b] { std::mem::swap(&mut a, &mut b); }
            for j in 0..20 { if ((d[a] - d[b]) >> j) & 1 == 1 { a = up[a][j]; } }
            let x = if a == b { a } else {
                for j in (0..20).rev() { if up[a][j] != up[b][j] { a=up[a][j]; b=up[b][j]; } }
                up[a][0]
            };
            let l = da + db - 2 * d[x]; if l == 0 { 0 } else { p[l - 1] }
        }).collect()
    }

11.06.2026

3558. Number of Ways to Assign Edge Weights I medium substack youtube

https://dmitrysamoylenko.com/leetcode/

11.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1387

Problem TLDR

Ways to color the deepest path in tree

Intuition

  • construct the tree, find the path length
  • the number of two-color the path is 2^len

Approach

  • use groupBy
  • modPow is an overkill, fold is enough

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun assignEdgeWeights(e: Array<IntArray>): Long {
        val g = e.flatMap {(a,b) -> setOf(a to b,b to a)}.groupBy({it.first},{it.second})
        fun d(i: Int, p: Int): Int = g[i]?.maxOf { j -> if (j == p) 0 else 1 + d(j, i) }?:0
        return (1..<d(1, 0)).fold(1L){r,_ -> (r*2)%1000000007}
    }
    pub fn assign_edge_weights(e: Vec<Vec<i32>>) -> i32 {
        let g = e.into_iter().flat_map(|v| [(v[0], v[1]), (v[1], v[0])]).into_group_map();
        fn d(i: i32, p: i32, g: &HashMap<i32, Vec<i32>>) -> i32 {
            g.get(&i).into_iter().flatten().map(|&j| if j == p { 0 } else { 1 + d(j, i, g) }).max().unwrap_or(0)
        }
        (1..d(1, 0, &g)).fold(1, |r, _| r * 2 % 1_000_000_007)
    }

10.06.2026

3691. Maximum Total Subarray Value II hard substack youtube

https://dmitrysamoylenko.com/leetcode/

10.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1386

Problem TLDR

sum k largest ranges max(l..r)-min(l..r)

Intuition

  • segment tree: size is 2*n, right lalf is the leafs, left half is the parents; to query look when left pointer is the right child, and right pointer is the left child

Approach

  1. Use segment tree to query max and in of range l..r
  2. The largest max-min is when the range is the widest, put all widest ranges to a sorted collection
  3. Query sorted collection and update with shrinked range l..r-1

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n)\)

Code

    fun maxTotalValue(n: IntArray, k: Int): Long {
        val s = n.size; val t0 = IntArray(s*2); val t1 = IntArray(s*2)
        for (i in n.indices) { t0[i+s] = n[i]; t1[i+s] = n[i] }
        for (i in s-1 downTo 1) { t0[i]=min(t0[i*2], t0[i*2+1]); t1[i]=max(t1[i*2], t1[i*2+1]) }
        fun q(l: Int, r: Int): IntArray {
            var a=l+s; var b=r+s; var m=Int.MAX_VALUE; var M=0
            while (a <= b) {
                if (a % 2 > 0) { m = min(m, t0[a]); M = max(M, t1[a++]) }
                if (b % 2 < 1) { m = min(m, t0[b]); M = max(M, t1[b--]) }
                a /= 2; b /= 2
            }
            return intArrayOf(l, r, M - m) 
        }
        val pq = PriorityQueue<IntArray>(compareBy { -it[2] })
        for (i in n.indices) pq += q(i, s-1)
        return (1..k).sumOf { pq.poll()?.let {(l,r,v) -> if (r>l) pq += q(l,r-1); 1L*v } ?: 0L }
    }
    pub fn max_total_value(n: Vec<i32>, k: i32) -> i64 {
        let s = n.len(); let (mut t0, mut t1) = (vec![0; s * 2], vec![0; s * 2]);
        for i in 0..s { t0[i+s] = n[i]; t1[i+s] = n[i] }
        for i in (1..s).rev() {  t0[i]=t0[i*2].min(t0[i*2+1]); t1[i]=t1[i*2].max(t1[i*2+1])}
        let q = |l: usize, r: usize| {
            let (mut a, mut b, mut m, mut M) = (l+s, r+s, i32::MAX, i32::MIN);
            while a <= b {
                if a % 2 > 0 { m = m.min(t0[a]); M = M.max(t1[a]); a += 1 }
                if b % 2 == 0 { m = m.min(t0[b]); M = M.max(t1[b]); b -= 1 }
                a /= 2; b /= 2
            }
            (M - m, l, r)
        };
        let mut pq: BinaryHeap<_> = (0..s).map(|i| q(i, s - 1)).collect();
        (0..k).filter_map(|_|pq.pop().map(|(v,l,r)|{if r>l{pq.push(q(l,r-1))};v as i64})).sum()
    }

06.06.2026

2574. Left and Right Sum Differences easy substack youtube

https://dmitrysamoylenko.com/leetcode/

06.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1382

Problem TLDR

abs(prefix sum - suffix sum)

Intuition

  • we can use math to just re-use the sum as is

Approach

Compute the sum - this is the suffix; use a single variable for prefix sum. Problem is small 1000 elements and 10^5 items, meaning we are in 32 bits

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun leftRightDifference(n: IntArray) = 
    n.run {val s = sum(); var l = 0; map {l += it; abs(2*l-it-s)}}
    pub fn left_right_difference(n: Vec<i32>) -> Vec<i32> {
        let (s, mut l) = (n.iter().sum::<i32>(), 0);
        n.iter().map(|x| { l += x; (2*l-x-s).abs()}).collect()
    }

05.06.2026

3753. Total Waviness of Numbers in Range II hard substack youtube

https://dmitrysamoylenko.com/leetcode/

05.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1381

Problem TLDR

Count hills and valleys base10 in a..b

Intuition

Didn’t solve myself. Brute-force - would not work for 10^15 elements. Digit DP: try every digit, be aware of the limit and of the leading zeros.

Approach

  • when counting valleys or hills we must add entire suffix of possible values: they will be either limited (suffix of number itself) or not (pow10)

Complexity

  • Time complexity: \(O(logn)\)

  • Space complexity: \(O(logn)\)

Code

    fun totalWaviness(a: Long, b: Long): Long {
        val P = (1..16).scan(1L) { r, _ -> r * 10L }
        fun c(x: Long): Long {
            val s = "$x"; val dp = HashMap<String, Long>()
            fun f(i: Int, pp: Int, p: Int, t: Boolean): Long =
                if (i == s.length) 0L else dp.getOrPut("$i $pp $p $t") {
                    (0..if (t) 9 else s[i] - '0').sumOf { d ->
                        val nt = t || d < s[i] - '0'
                        val w = if (pp >= 0 && (pp - p) * (d - p) > 0) 
                            if (nt) P[s.length - 1 - i] else (s.substring(i + 1).toLongOrNull() ?: 0L) + 1L else 0L
                        w + f(i + 1, if (p < 0 && d == 0) -1 else p, if (p < 0 && d == 0) -1 else d, nt)
                    }
                }
            return f(0, -1, -1, false)
        }
        return c(b) - c(a - 1)
    }
    pub fn total_waviness(a: i64, b: i64) -> i64 {
        fn c(x: i64) -> i64 {
            fn f(i: usize, u: i8, v: i8, t: bool, x: i64, s: &[u8], m: &mut HashMap<(usize, i8, i8, bool), i64>) -> i64 {
                if let Some(&r) = m.get(&(i, u, v, t)) { return r; }
                let (mut r, j, l) = (0, (s.len() - 1 - i) as u32, if t { 9 } else { (s[i] - 48) as i8 });
                for d in 0..=l {
                    let (n, z, p) = (t || d < l, v < 0 && d == 0, 10i64.pow(j));
                    if u >= 0 && (u - v) * (d - v) > 0 { r += if n { p } else { x % p + 1 }; }
                    if j > 0 { r += f(i + 1, if z { -1 } else { v }, if z { -1 } else { d }, n, x, s, m); }
                }
                m.insert((i, u, v, t), r); r
            }
            if x < 0 { 0 } else { f(0, -1, -1, false, x, &x.to_string().into_bytes(), &mut HashMap::new()) }
        }
        c(b) - c(a - 1)
    }

04.06.2026

3751. Total Waviness of Numbers in Range I medium substack youtube

https://dmitrysamoylenko.com/leetcode/

04.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1380

Problem TLDR

Count hills and valleys base10 in a..b

Intuition

Brute-force

Approach

  • Rust: itertools allows for tuple_windows

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(logn)\)

Code

    fun totalWaviness(a: Int, b: Int) = 
    (a..b).sumOf {"$it".windowed(3).count {(it[0]-it[1])*(it[2]-it[1])>0}}
    pub fn total_waviness(a: i32, b: i32) -> i32 {
        (a..=b).map(|x|x.to_string().bytes().tuple_windows()
        .filter(|(a,b,c)|a>b&&c>b||a<b&&c<b).count()as i32).sum::<i32>()
    }

03.06.2026

3635. Earliest Finish Time for Land and Water Rides II medium substack youtube

https://dmitrysamoylenko.com/leetcode/

03.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1379

Problem TLDR

Min finish time of land + water single events

Intuition

find min water and land finish times, then try all waters with finish land and try all lands with finish water

Approach

  • extract the repeating parts
  • Rust can derive the argument types in lambdas
  • Kotlin: we can extract sub-sub functions

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

    fun earliestFinishTime(lst: IntArray, ld: IntArray, wst: IntArray, wd: IntArray)= run {
        fun f(st: IntArray, d: IntArray) = {s: Int ->st.zip(d).minOf{(st,d)->max(s,st)+d}}
        val (a,b) = f(lst, ld) to f(wst, wd); min(a(b(0)), b(a(0)))
    }
    pub fn earliest_finish_time(lst: Vec<i32>, ld: Vec<i32>, wst: Vec<i32>, wd: Vec<i32>) -> i32 {
        let f = |st:&[i32],d:&[i32], s| (0..d.len()).map(|i|st[i].max(s)+d[i]).min().unwrap();
        f(&lst, &ld, f(&wst, &wd, 0)).min(f(&wst, &wd, f(&lst, &ld, 0)))
    }

02.06.2026

3633. Earliest Finish Time for Land and Water Rides I easy substack youtube

https://dmitrysamoylenko.com/leetcode/

02.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1378

Problem TLDR

Min finish time of land + water single events

Intuition

Brute-force: take every water even and compare with every land event Optimal: find min water and land finish times, then try all waters with finish land and try all lands with finish water

Approach

  • extract the repeating parts

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

    fun earliestFinishTime(lst: IntArray, ld: IntArray, wst: IntArray, wd: IntArray): Int {
        val f = { s:IntArray,d:IntArray,m:Int -> s.indices.minOf{max(m,s[it])+d[it]}}
        return min(f(wst,wd, f(lst,ld,0)),f(lst,ld,f(wst,wd,0)))
    }
    pub fn earliest_finish_time(lst: Vec<i32>, ld: Vec<i32>, wst: Vec<i32>, wd: Vec<i32>) -> i32 {
        let f = |s: &[i32], d: &[i32], m: i32| (0..s.len()).map(|i| s[i].max(m) + d[i]).min().unwrap();
        f(&wst, &wd, f(&lst, &ld, 0)).min(f(&lst, &ld, f(&wst, &wd, 0)))
    }

01.06.2026

2144. Minimum Cost of Buying Candies With Discount easy substack youtube

https://dmitrysamoylenko.com/leetcode/

01.06.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1377

Problem TLDR

Min sum taking 2 out of 3

Intuition

Sort descending, take greedily

Approach

  • if you not sure which way is better forward or backward, you can make min(forward,backward)

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n|1)\)

Code

    fun minimumCost(c: IntArray) = 
        c.sortedDescending().filterIndexed {i,_->i%3<2}.sum()
    pub fn minimum_cost(mut c: Vec<i32>) -> i32 {
        c.sort_unstable_by(|a, b| b.cmp(a));
        c.chunks(3).flat_map(|c| c.iter().take(2)).sum()
    }

31.05.2026

2126. Destroying Asteroids medium substack youtube

https://dmitrysamoylenko.com/leetcode/

31.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1376

Problem TLDR

Can consume all asteroids smaller than running sum?

Intuition

  • sort + greedy: sort, then take from smaller to larger
  • bits group: consume from smallest highest one bit group if it’s min is bigger than mass
  • quickselect: move to prefix & consume all asteroids that are not larger; the math guarantees O(n) - otherwise numbers have to grow by 2^i

Approach

  • Rust’s select_nth_unstable requires mid position, can’t be used here

Complexity

  • Time complexity: \(O(nlogn|n)\)

  • Space complexity: \(O(n|1)\)

Code

    fun asteroidsDestroyed(m: Int, a: IntArray) = 
    a.sorted().fold(1L*m){r,t->if(r<t)0L else r+t}>0
    pub fn asteroids_destroyed(m: i32, mut a: Vec<i32>) -> bool {
        let (mut c, mut s) = (m as i64, 0);
        while s < a.len() {
            let mut i = s;
            for j in s..a.len() {
                if a[j]as i64 <= c { c += a[j] as i64; a.swap(i, j); i += 1 }
            }
            if s == i { return false }; s = i
        } true
    }

30.05.2026

3161. Block Placement Queries hard substack youtube

https://dmitrysamoylenko.com/leetcode/

30.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1375

Problem TLDR

Queries ‘can place a gap after place an obstacle’

Intuition

Didn’t solved without a hint. The TreeMap solution:

  • group starting points per gap size
  • store obstacles in sorted set
  • query: fine left and right obstacle, query the gap, take first starting poing, check size
  • build: find left and right obstacle, remove old starting point from that gap, add new starting points to left and right gaps

The SegmentTree solution:

  • role: finds the max gap that starts in range 0..x
  • build: put current T[M+x] = sz, propagate to parents
  • save obstacles in a sorted set
  • query: find left obstacle, one gap is x-l, second gap is segment tree maximum in range 0..l-1 (corner case excludes l)

Approach

  • another segment tree solution is defined by role: find the max gap in range 0..x (it requires to store [start,end,max] per node)

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n)\)

Code

    fun getResults(q: Array<IntArray>) = sortedSetOf(0, 100000).run {
        val gs = TreeMap(mapOf(-100000 to sortedSetOf(0)))
        q.mapNotNull { q -> val x = q[1]
            if (q[0] > 1) gs.any { (g, s) -> -g >= q[2] && s.first() <= x-q[2] }
            else null.also { val l = lower(x); val r = higher(x); add(x)
                gs[l-r]?.let { it -= l; if (it.isEmpty()) gs -= l-r }
                gs.getOrPut(l-x, ::TreeSet) += l; gs.getOrPut(x-r, ::TreeSet) += q[1]
            }
        }
    }
    pub fn get_results(q: Vec<Vec<i32>>) -> Vec<bool> {
        let (mut o, mut t, z) = (BTreeSet::from([0, 50005]), vec![0; 100010], 50005); t[z]=z as i32;
        q.into_iter().filter_map(|c| { let x=c[1];
            if c[0]>1 { let f=*o.range(..=x).next_back()?; let (mut l, mut r, mut m)=(z, f as usize+z-1, 0);
                while l<=r { if l%2>0 {m=m.max(t[l]); l+=1} if r%2<1 {m=m.max(t[r]); r-=1} l/=2; r/=2 }
                Some((x-f).max(m) >= c[2])
            } else { let (l, r) = (*o.range(..x).next_back()?, *o.range(x..).next()?); o.insert(x);
                for (k,v) in [(l, x-l), (x, r-x)] { let mut i=k as usize+z; t[i]=v; while i>1 {i/=2; t[i]=t[i*2].max(t[i*2+1])} }
                None
            }
        }).collect()
    }

29.05.2026

3300. Minimum Element After Replacement With Digit Sum easy substack youtube

https://dmitrysamoylenko.com/leetcode/

29.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1374

Problem TLDR

Min of digits sum

Intuition

Compute the digits sum in a while loop, track the minimum.

Approach

  • you can unroll the while loop

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

    fun minElement(n: IntArray) = 
    n.minOf{"$it".sumOf{it-'0'}}
    pub fn min_element(n: Vec<i32>) -> i32 {
        n.iter().map(|x|x%10+x/10%10+x/100%10+x/1000%10+x/10000%10).min().unwrap()
    }

28.05.2026

3093. Longest Common Suffix Queries hard substack youtube

https://dmitrysamoylenko.com/leetcode/

28.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1373

Problem TLDR

Query common suffixes match

Intuition

Use Trie. Update the shortest index as you go.

Approach

  • in Rust the interesting pattern is an arena allocation

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun stringIndices(c: Array<String>, q: Array<String>) = run {
        class T(var i: Int): HashMap<Char,T>()
        val r = T(c.indexOf(c.minBy{it.length}))
        for ((i,w) in c.withIndex()) { var t = r
            for (j in w.lastIndex downTo 0) t = t.getOrPut(w[j]){T(i)}
                .also { if (w.length < c[it.i].length) it.i = i }
        }
        q.map { var t = r; for (c in it.reversed()) t = t[c] ?: break; t.i }
    }
    pub fn string_indices(c: Vec<String>, q: Vec<String>) -> Vec<i32> {
        let mut n = vec![([0; 26], (0..c.len()).min_by_key(|&i| c[i].len()).unwrap())];
        for (i, w) in c.iter().enumerate() { let mut u = 0;
            for b in w.bytes().rev() { let k = (b - b'a') as usize;
                if n[u].0[k] == 0 { n[u].0[k] = n.len(); n.push(([0; 26], i)) }
                u = n[u].0[k]; if w.len() < c[n[u].1].len() { n[u].1 = i }
            }
        }
        q.iter().map(|w| { let mut u = 0;
            for b in w.bytes().rev() {
                let v = n[u].0[(b - b'a') as usize]; if v == 0 { break } u = v 
            } n[u].1 as _
        }).collect()
    }

27.05.2026

3121. Count the Number of Special Characters II medium substack youtube

https://dmitrysamoylenko.com/leetcode/

27.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1372

Problem TLDR

Count sorted characters

Intuition

Brute-force: checkk all letters separately a..z, last index of c should be in range of 0..first index of C Optimal: bitmasks to track visited uppercase and lowercase and invalid marker

Approach

  • 0.. is essential in kotlin, because lastIndexof can be -1

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

    fun numberOfSpecialChars(w: String) = ('a'..'z')
    .count { w.lastIndexOf(it) in 0..<w.indexOf(it-32) }
    pub fn number_of_special_chars(w: String) -> i32 {
        (b'a'..=b'z').filter(|&c| w.rfind(c as char)
        .is_some_and(|l| Some(l) < w.find((c - 32) as char))).count() as _
    }

26.05.2026

3120. Count the Number of Special Characters I easy substack youtube

https://dmitrysamoylenko.com/leetcode/

26.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1371

Problem TLDR

Count letters with both cases

Intuition

Brute-force is accepted. O(n) memory: for any uniq lowercase check if uppercase present, use hashset O(1) memory: two bitmasks, for lower and for upper cases; (m & M) count bits is the result

Approach

  • regex is ugly here

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n)\)

Code

    fun numberOfSpecialChars(w: String) = 
        w.toSet().count {it-32 in w}
    pub fn number_of_special_chars(w: String) -> i32 {
        ('a'..='z').zip('A'..='Z').filter(|&(c,C)| w.contains(c)&&w.contains(C)).count() as _
    }

25.05.2026

1871. Jump Game VII medium substack youtube

https://dmitrysamoylenko.com/leetcode/

25.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1370

Problem TLDR

Can reach end jumping min..max to zeros

Intuition

  • forward: put line sweep interval start-end events, slide
  • backwards: slide window looking backwards, count reachable items inside window

Approach

  • the end should not be ‘1’

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun canReach(s: String, min: Int, max: Int): Boolean {
        val e = IntArray(s.length+max+2); e[1] = -1
        return s.last() == '0' && 0 < s.indices.fold(1) { c, i ->
            if (s[i] == '0' && c+e[i] > 0) { e[i+min]++; e[i+max+1]-- }
            c + e[i]
        }
    }
    pub fn can_reach(s: String, l: i32, h: i32) -> bool {
        let mut e = vec![0; s.len()+h as usize + 2]; e[1] = -1;
        s.ends_with('0') && 0 < s.bytes().zip(0..).fold(1, |c, (v, i)| {
            if v < 49 && c + e[i] > 0 { e[i+l as usize] += 1; e[i+h as usize+1] -= 1 }
            c + e[i]
        })
    }

24.05.2026

1340. Jump Game V hard substack youtube

https://dmitrysamoylenko.com/leetcode/

24.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1369

Problem TLDR

Max visited by jumping down in distance d

Intuition

  • Top-down DP: dfs from each index to the left and to the right by d distance, memo by i
  • Bottom-up DP: iterate in increasing value order to safely use previous results because we only jump down
  • O(N) solution: use decreasing stack, track left peak, pop smaller valleys and update m[left_peak right_peak]=max(m[popped]+1),

Approach

  • for monotonic we have to track left peaks becasue of the duplicates

Complexity

  • Time complexity: \(O(nd|n)\)

  • Space complexity: \(O(n)\)

Code

    fun maxJumps(a: IntArray, d: Int) = IntArray(a.size).let { m ->
        a.indices.sortedBy{a[it]}.maxOf { i ->
            m[i] = 1+setOf(i-1 downTo i-d,i+1..i+d).maxOf { 
                it.takeWhile{a.getOrNull(it)?:a[i]<a[i]}.maxOfOrNull{m[it]}?:0};m[i]}}
    pub fn max_jumps(a: Vec<i32>, d: i32) -> i32 {
        let(d,n)=(d as usize,a.len());let mut m=vec![1;n];let mut s:Vec<(usize,usize)>=vec![];
        for (&v,i) in a.iter().chain([&99999]).zip(0..) {
            while let Some(&(j, l)) = s.last() && a[j] < v { s.pop();
                if i < n && i - j <= d { m[i] = m[i].max(m[j] + 1) }
                if l < n && j - l <= d { m[l] = m[l].max(m[j] + 1) }
            }
            s.push((i,s.last().map_or(n,|&(k,l)|if a[k]>v {k} else {l})))
        } m.into_iter().max().unwrap()
    }

23.05.2026

1752. Check if Array Is Sorted and Rotated easy substack youtube

https://dmitrysamoylenko.com/leetcode/

23.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1368

Problem TLDR

Is array shifted and sorted?

Intuition

  • brute-force is accepted for 100 elements
  • optimal way: count unordered elements

Approach

  • the shortest Rust is n^2
  • Rust itetools has circular_tuple_windows

Complexity

  • Time complexity: \(O(n|n^2)\)

  • Space complexity: \(O(1|n)\)

Code

    fun check(n: IntArray) = 
    n.indices.count { n[it]>n[(it+1)%n.size]} < 2
    pub fn check(n: Vec<i32>) -> bool {
        n.repeat(2).windows(n.len()).any(|w|w.is_sorted())
    }

22.05.2026

33. Search in Rotated Sorted Array medium substack youtube

https://dmitrysamoylenko.com/leetcode/

22.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1367

Problem TLDR

Binary search in shifted array

Intuition

  • find the split point
  • binary search in two parts

Approach

  • insertion point: the first value is less than first part and bigger than second part
  • if target is less than first value - it is in the second part

Complexity

  • Time complexity: \(O(logn)\)

  • Space complexity: \(O(1)\)

Code

    fun search(n: IntArray, t: Int) = n.asList().run {
        val s = binarySearch { if(it < n[0])1 else -1}.inv()
        maxOf(-1, binarySearch(t, 0, s), binarySearch(t, s))
    }
    pub fn search(n: Vec<i32>, t: i32) -> i32 {
        let (s,b) = (n.partition_point(|&x| x >= n[0]), (t<n[0]) as usize);
        [&n[..s],&n[s..]][b].binary_search(&t).map_or(-1, |i|(i+s*b)as _)
    }

21.05.2026

3043. Find the Length of the Longest Common Prefix medium substack youtube

https://dmitrysamoylenko.com/leetcode/

21.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1366

Problem TLDR

Longest prefix of pairs

Intuition

  • hashset: put all prefixes of one array, query all prefixes of the second array
  • trie: put all prefixes of one array into trie, check longest path for all prefixes of the second

Approach

  • we can use strings or ints

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun longestCommonPrefix(a: IntArray, b: IntArray) = run {
        val s = a.flatMap { "$it".scan("", String::plus) }.toSet()
        b.maxOf { var v = "$it"; while (v !in s) v = v.dropLast(1); v.length }
    }
    pub fn longest_common_prefix(a: Vec<i32>, b: Vec<i32>) -> i32 {
        #[derive(Default)] struct T(HashMap<u8, T>); let mut r = T::default();
        for x in a { x.to_string().bytes().fold(&mut r, |t, c| t.0.entry(c).or_default()); }
        b.iter().map(|x| { 
            let mut t = &r;
            x.to_string().bytes().take_while(|c| t.0.get(c).map(|n| t = n).is_some()).count() as _
        }).max().unwrap()
    }

20.05.2026

2657. Find the Prefix Common Array of Two Arrays medium substack youtube

https://dmitrysamoylenko.com/leetcode/

20.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1365

Problem TLDR

Duplicates in prefixes

Intuition

Only 50 elements, brute-force works. We can use HashSets or bitmasks

Approach

  • shortest version in Kotlin is O(n^2)
  • in Rust we can use zip+scan, or a simple map

Complexity

  • Time complexity: \(O(n^2|n)\)

  • Space complexity: \(O(n)\)

Code

    fun findThePrefixCommonArray(a: IntArray, b: IntArray) = 
    (1..a.size).map {a.take(it).intersect(b.take(it)).size}
    pub fn find_the_prefix_common_array(a: Vec<i32>, b: Vec<i32>) -> Vec<i32> {
        let (mut c, mut d) = (0, 0i64);
        (0..a.len()).map(|i|{c|=1<<a[i];d|=1<<b[i];(c&d).count_ones() as _}).collect()
    }

19.05.2026

2540. Minimum Common Value easy substack youtube

https://dmitrysamoylenko.com/leetcode/

19.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1364

Problem TLDR

Min common of two sorted list

Intuition

  • two pointers: one goes forward, second tries to match
  • or hashset
  • or binary search

Approach

  • binary search is the shortest
  • rust itertools has nice way to merge sorted lists

Complexity

  • Time complexity: \(O(nlogn|n)\)

  • Space complexity: \(O(1)\)

Code

    fun getCommon(a:IntArray, b: IntArray) = 
    a.find { b.binarySearch(it) >= 0 } ?: -1
    pub fn get_common(a: Vec<i32>, b: Vec<i32>) -> i32 {
        a.into_iter().merge_join_by(b, i32::cmp).find_map(|e|
            match e {Both(a,_)=>Some(a), _=>None}).unwrap_or(-1)
    }

18.05.2026

1345. Jump Game IV hard substack youtube

https://dmitrysamoylenko.com/leetcode/

18.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1363

Problem TLDR

Min steps to reach end jumping to same value or left or right

Intuition

group by value and do BFS

Approach

  • remove visited groups
  • mark visited early

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun minJumps(a: IntArray): Int {
        val g = HashMap(a.indices.groupBy{a[it]}); var t = -1
        val q = ArrayDeque(listOf(0)); val v = hashSetOf(0)
        while (q.size > 0 && ++t>=0) for (x in 1..q.size) {
            val i = q.removeFirst(); if (i == a.size-1) return t
            for (j in (g.remove(a[i])?:setOf())+(i-1)+(i+1)) 
                if (j in a.indices && v.add(j)) q += j
        }
        return a.size-1
    }
    pub fn min_jumps(a: Vec<i32>) -> i32 {
        let mut g = (0..a.len()).into_group_map_by(|&i| a[i]);
        let (mut q, mut v, mut t) = (vec![0], vec![0;a.len()], 0);
        loop { let mut w = vec![]; for i in q { 
            if i == a.len()-1 { return t }
            for j in g.remove(&a[i]).into_iter().flatten().chain([i-1,i+1]) {
                if j < a.len() && v[j] < 1 { v[j] = 1; w.push(j) }
            }
        } q = w; t += 1 }
    }

17.05.2026

1306. Jump Game III medium substack youtube

https://dmitrysamoylenko.com/leetcode/

17.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1362

Problem TLDR

Can reach 0 by jumping +a[i] - a[i]

Intuition

  • Union-Find would not work - we have a strictly directed edges in graph
  • BFS/DFS works

Approach

  • use array itself as a visited set
  • use ‘camicadze’ value to make it out of range and make less checks

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun canReach(a: IntArray, s: Int):Boolean = s in a.indices&&
    a[s].let{x->a[s]=a.size;x==0||canReach(a,s-x)||canReach(a,s+x)}
    pub fn can_reach(mut a: Vec<i32>, s: i32) -> bool {
        let mut q = vec![s];
        while let Some(i) = q.pop() {
            let Some(x) = a.get_mut(i as usize) else {continue};
            if *x == 0 { return true }
            q.extend([i-*x,i+*x]); *x += 100000
        } false
    }

16.05.2026

154. Find Minimum in Rotated Sorted Array II hard substack youtube

https://dmitrysamoylenko.com/leetcode/

16.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1361

Problem TLDR

Binary search in shifted array with duplicates

Intuition

    // 3 4 5 6 7 1 2 3
    // 3 1
    // false false
    // 3 1 3
    // false true false
  • compare all elements with last
  • slice duplicates out in O(N)

Approach

  • use built-in functions, Rust: partition_point, position, slices [..], Kotlin: binarySearch {..}, indexOfFirst
  • x.inv() is -1-x

Complexity

  • Time complexity: \(O(n|logn)\)

  • Space complexity: \(O(1)\)

Code

    fun findMin(n: IntArray) = n[n.asList().binarySearch(
        max(0, n.indexOfFirst { it != n.last()})) { 
            if (it <= n.last()) 1 else -1 }.inv()]
    pub fn find_min(n: Vec<i32>) -> i32 {
        let n = &n[n.iter().position(|&x| x != n[n.len()-1]).unwrap_or(0)..];
        n[n.partition_point(|&x|x > n[n.len()-1])]
    }

15.05.2026

153. Find Minimum in Rotated Sorted Array medium substack youtube

https://dmitrysamoylenko.com/leetcode/

15.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1360

Problem TLDR

Binary search in shifted array

Intuition

    // 5 6 7 0 1 2 3 4
    // l     m       h
    // 6 7 0 1 2 3 4 5
    // l     m       h
    // 6 7 0 1 2 3 4 5
    // l m   h

    // 4 5 6 7 0 1 2
    // l     m     h
    //         l
  • invent the binary search from scratch
  • or notice that we can compare all elements with last

Approach

  • use built-in functions, Rust: partition_point, Kotlin: binarySearch {..}

Complexity

  • Time complexity: \(O(logn)\)

  • Space complexity: \(O(1)\)

Code

    fun findMin(n: IntArray) = 
        n[-1-n.asList().binarySearch { if (it > n.last()) -1 else 1}]
    pub fn find_min(n: Vec<i32>) -> i32 {
        n[n.partition_point(|&x|x>n[n.len()-1])]
    }

14.05.2026

2784. Check if Array is Good easy substack youtube

https://dmitrysamoylenko.com/leetcode/

14.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1359

Problem TLDR

Is combination 1..n,n

Intuition

  • no-brain solution: check every number (1..n) is in array, and count(n)==2
  • shortest solution: (1..n)+n==sorted()
  • optimal solution: use array indices as visited storage

Approach

  • n[0] can be used as extra storage for n[len-1] special case

Complexity

  • Time complexity: \(O(nlogn|n)\)

  • Space complexity: \(O(n|1)\)

Code

    fun isGood(n: IntArray) = 
    (1..<n.size) + (n.size-1) == n.sorted()
    pub fn is_good(mut n: Vec<i32>) -> bool {
        (0..n.len()).all(|i| { let x = n[i].abs() as usize;
            !(x>=n.len()||n[x]<0&&(x<n.len()-1||n[0]<0)) && {
            if n[x] < 0 { n[0] *= -1 } else { n[x] *= -1 };1>0}
        }) && n[0]<0
    }

13.05.2026

1674. Minimum Moves to Make Array Complementary medium substack youtube

https://dmitrysamoylenko.com/leetcode/

13.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1358

Problem TLDR

Min changes 1..L to make complementary pair sum equal

Intuition

    // brainteaser
    // max: we can convert all numbers to the same number
    // track pairs sums, peek the most common
    // each pair is a sum of ranges 1..l + 1..l
    // common sum should be within 2..2l
    // llll
    // aa
    //   bbbb
    //         s
    // aaaaaa
    //       bbb
    //        s
    // aa
    //   bb
    //  s
    // 28 minute wrong answer
    // 34 minute wrong answer
    // use hints: no help, difference array?
    // so looks like intersection of the intervals

Each value pair (a,b) forms a range of possible targets: 2..2L full range of targets where both ‘a’ and ‘b’ got changed; min(a,b)+1..max(a,b)+L is a range of single change either ‘a’ or ‘b’ a+b - is a single point where no change required, because target == a+b.

Merge all ranges then scan them to find maximum changes required.

Approach

  • some computations can be extracted out of line sweep

Complexity

  • Time complexity: \(O(L+N)\)

  • Space complexity: \(O(L)\)

Code

    fun minMoves(n: IntArray, l: Int): Int {
        val d = IntArray(2*l + 2); var c = 0;
        for (i in 0..<n.size/2) {
            val a = n[i]; val b = n[n.size-1-i]
            d[min(a,b)+1]--; d[max(a,b)+l+1]++; d[a+b]--; d[a+b+1]++
        }
        return (2..2*l).minOf { c += d[it]; c } + n.size
    }
    pub fn min_moves(n: Vec<i32>, l: i32) -> i32 {
        let (mut d, l) = ([0; 200002], l as usize);
        for i in 0..n.len()/2 {
            let (a, b) = (n[i] as usize, n[n.len()-1-i] as usize);
            d[a.min(b)+1]-=1;d[a.max(b)+l+1]+=1; d[a+b]-=1;d[a+b+1]+=1
        }
        (2..2*l+1).fold((0,0), |(min, c),i|(min.min(c+d[i]),c+d[i])).0 +n.len() as i32
    }

12.05.2026

1665. Minimum Initial Energy to Finish Tasks hard substack youtube

https://dmitrysamoylenko.com/leetcode/

12.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1357

Problem TLDR

Energy for all tasks (spend, limit)

Intuition

    // we can do binary search
    // but how to optimally use the energy?
    // do we know that order is always decrease t[][1]?
    //
    // i don't have any better idea, let's write bs

    // 32
    // 10-12, 10-11, 8-9, 2-4, 1-3 
    //        22     12   4    2     so this is the corner case
    //
    // 1-3 2-4 10-11 10-12 8-9
    // 32  31  29    19    9       this is the optimal order
    //
    // 26 minute, hints: Figure a sorting pattern 
    //                   is exactly what i can't do
    //
    // so this is a brainteaser about sorting 
    //

Didn’t solve without a hint. Sort by (spend-limit). Then do a binary search with forward pass and energy consumption or just a backward pass and energy max(spend, limit). The intuition behind (spend-limit): it is a greedy assumption that minimizing the consumption works. Why the pair of (spend,-limit) or (-limit, spend) doesn’t work? Because we want to maximize the “refund” (what was required - what was returned back).

Approach

  • rust itertools allows one-liner

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(1)\)

Code

    fun minimumEffort(t: Array<IntArray>) = t
        .sortedBy { it[1]-it[0] }
        .fold(0) { e, (a,b) -> max(e+a, b) }
    pub fn minimum_effort(t: Vec<Vec<i32>>) -> i32 {
        t.iter().sorted_by_key(|v|v[1]-v[0])
        .fold(0, |e, v| v[1].max(e+v[0]))
    }

11.05.2026

2553. Separate the Digits in an Array easy substack youtube

https://dmitrysamoylenko.com/leetcode/

11.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1356

Problem TLDR

LIst of numbers to list of digits

Intuition

Convert to strings or do %10 with LInkedList/ArrayDeque or do the reverse.

Approach

  • Kotlin: joinToString converts numbers to strings
  • Rust: use flat_map or to_string/bytes

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun separateDigits(n: IntArray) = 
        n.joinToString("").map{it-'0'}
    pub fn separate_digits(n: Vec<i32>) -> Vec<i32> {
        n.iter().map(|x|x.to_string()).collect::<String>()
        .bytes().map(|b|(b-b'0') as i32).collect()
    }

10.05.2026

2770. Maximum Number of Jumps to Reach the Last Index medium substack youtube

https://dmitrysamoylenko.com/leetcode/

10.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1355

Problem TLDR

Max steps to reach end by jumps n[j]-n[i] in -t..t

Intuition

Top-down DP: at each position i with previous position j choose to skip (dfs(i+1,p)) or take(1+dfs(i+1,i)) Bottom-up DP: for each index i if it is reachable update all next position if they reachable Segment tree solution: for each value X query the range X-t..X+t for maximum reachable steps in this range

Approach

  • segment tree query: if left is the right child & if right is the left child; move them sideways & update query result

Complexity

  • Time complexity: \(O(n^2|nlogn)\)

  • Space complexity: \(O(n)\)

Code

    fun maximumJumps(n: IntArray, t: Int) = IntArray(n.size).also { d ->
        d[0] = 1
        for (i in d.indices) if (d[i] > 0) for (j in i+1..<d.size)
            if (abs(n[i]-n[j]) <= t) d[j] = max(d[j], 1 + d[i])
    }.last() - 1
    pub fn maximum_jumps(n: Vec<i32>, t: i32) -> i32 {
        let mut v = n.clone(); v.sort(); v.dedup();   let m = v.len(); let mut tr = vec![-1; m*2];
        let (f,g) = (|x|v.partition_point(|&y|y<x), |x|v.partition_point(|&y|y<=x));
        (0..).zip(n).fold(0, |q, (i,x)| {
            let (mut l,mut r) = (f(x.saturating_sub(t)), g(x.saturating_add(t)).saturating_sub(1));
            let mut q = (i==0) as i32-1; l += m; r += m; 
            while l <= r { if l&1 > 0 { q = q.max(tr[l]); l += 1 };  if r&1 < 1 { q = q.max(tr[r]); r -= 1 }
                l /= 2; r /= 2
            }
            if q >= 0 { q += (i>0)as i32; let mut p = f(x)+m; tr[p] = tr[p].max(q);
                while p > 1 { p /=2; tr[p] = tr[p*2].max(tr[p*2+1])} 
            }; q
        })
    }

09.05.2026

1914. Cyclically Rotating a Grid medium substack youtube

https://dmitrysamoylenko.com/leetcode/

09.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1354

Problem TLDR

Rotate matix layers by k

Intuition

    // 4x6=16 = 2*3+2*5
    // m,n up to 50, can rotate k times by 1

n^3 time, O(1) memory: go layer by layer, then repeat k%p rotates by 1: repeat p times swaps, compute next position n^2 time, O(1) memory: go layer by layer, linearize each layer by writing get(i) function, do rotation in-place by 3-reversal trick

3-reversal trick: reverse 0..k, k..end, 0..end; the result is shifted left by k

Approach

  • solutions with O(n) memory are shorter

Complexity

  • Time complexity: \(O(n^3|n^2)\)

  • Space complexity: \(O(n)\)

Code

    fun rotateGrid(g: Array<IntArray>, k: Int) = g.also {
        val h = g.size; val w = g[0].size
        for (l in 0..<min(w, h) / 2) {
            val q =  (l..<w - l).map {l to it} +
                     (l + 1..<h - l).map {it to w - 1 - l} +
                     (w - 2 - l downTo l).map {h - 1 - l to it} +
                     (h - 2 - l downTo l + 1).map {it to l }
            val v = q.map { (r, c) -> g[r][c] }
            q.forEachIndexed {i, (r, c) ->  g[r][c] = v[(i + k) % v.size]}
        }
    }
    pub fn rotate_grid(mut g: Vec<Vec<i32>>, k: i32) -> Vec<Vec<i32>> {
        let (w, h, k) = (g[0].len(), g.len(), k as usize);
        for l in 0..w.min(h)/2 {
            let q: Vec<_> = (l..w-l).map(|i| (l,i))
                .chain((l+1..h-l).map(|i|(i,w-1-l)))
                .chain((l..w-1-l).rev().map(|i|(h-1-l,i)))
                .chain((l+1..h-1-l).rev().map(|i|(i,l))).collect();
            let mut rev = |s:usize, e:usize| { for i in 0..(e-s+1)/2 {
                        let ((a,b),(c,d)) = (q[s+i], q[e-i]);
                        let t = g[a][b]; g[a][b] = g[c][d]; g[c][d] = t
                    }};
            rev(0, k%q.len()-1); rev(k%q.len(), q.len()-1); rev(0, q.len()-1)
        }; g
    }

08.05.2026

3629. Minimum Jumps to Reach End via Prime Teleportation medium substack youtube

https://dmitrysamoylenko.com/leetcode/

08.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1353

Problem TLDR

Shortest path by prime factors

Intuition

    // brainteaser
    // 10^5 total
    // sqrt(n) to check if it is prime   O(NsqrtN)
    // check every number to be % by all primes in list O(n^2)
    // run BFS
    //
    // i'll go straigth to hints, have no idea
    // hints suggesting O(n^2) solution?
    // prime *factors* for each number, not precompute primes, but factors
    // 53 minute wrong answer
    // 54 minute TLE (as expected)
    // how to prepare primes buckets? 58 minute
    // so the missing part is prime factors?
  • prepare primes with sieve
  • factorize all numbers
  • prepare map from prime factor to eligible indices
  • bfs using this hashmap

Another way:

  • instead of preparing factors, just iterate factors inside bfs step

Approach

  • prime sieve: outer loop i = 2..n, and mark all multipliers of i with false (not prime)
  • factorization: outer loop: p = primes, and check if v % p, then add, and divide v/p until not divisible
  • iterating from prime to possible values: p..max step p

Complexity

  • Time complexity: \(O(nlogm)\)

  • Space complexity: \(O(n+m)\)

Code

    fun minJumps(n: IntArray): Int {
        val q = ArrayDeque(setOf(0)); var res = -1; val v = hashSetOf(0); var i = 1
        val s = BooleanArray(n.max()+1) {it>1}; val m = n.indices.groupBy{n[it]}
        while (++i*i<s.size) if (s[i]) for (j in i*i..<s.size step i) s[j]=false
        while (++res>=0) for (a in 1..q.size) q.removeFirst().let { i ->
            if (i == n.size-1) return res; var p = n[i]
            for (j in setOf(i-1,i+1)) if (j in n.indices && v.add(j)) q += j
            if (s[p]&&v.add(-p)) for(j in p..<s.size step p) { m[j]?.map{if(v.add(it)) q+=it}}
        }
        return 0
    }
    pub fn min_jumps(n: Vec<i32>) -> i32 {
        let (mut q, mut res, mut v, mut i) = (VecDeque::from([0]), 0, HashSet::from([0]), 2); 
        let mut s = vec![true;*n.iter().max().unwrap() as usize + 1]; s[1]=false; 
        let m = (0..n.len()).into_group_map_by(|&i|n[i] as usize);
        while i*i < s.len() { if s[i] { for j in (i*i..s.len()).step_by(i) { s[j] = false }}; i+=1}
        loop { for a in 0..q.len() {
            let i = q.pop_front().unwrap(); if i == n.len() - 1 { return res }; let p = n[i] as usize;
            for j in [i-1, i+1] { if j < n.len() && v.insert(j) { q.push_back(j); }}
            if s[p] && v.insert(n.len()+p) { 
                for &j in (p..s.len()).step_by(p).filter_map(|j|m.get(&j)).flatten() { 
                    if v.insert(j) { q.push_back(j); }}}
        } res += 1 } 0
    }

07.05.2026

3660. Jump Game IX medium substack youtube

https://dmitrysamoylenko.com/leetcode/

07.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1352

Problem TLDR

Max on path jumping left-up and right-down

Intuition

    // 2 3 1
    // *        decreasing sequence 3 1
    //
    // 1 2 3 4 3 2 1 2 3 4
    // *                       4 3 2 1
    //       j         i   
    // ok maybe jump only to the left in one pass, then only to the right in second
    // 2 3 1
    // 2
    //   3
    //     3
    //   3
    // 3
    //
    // 2 1 3
    // 2 2 3
    //     3
    //   3?
    // 
    // 3  1 5 6  4  2
    //*i  j         j
    // j* i
    //*     i    j  j
    //*       i
    //      j j* i  j
    //      j j* j  i
    //             how many jumps possible? is it possible for valid path have 3 jumps?
    //              i*
    //           i  j*  for backwards pass with want to track first lower
    //        i     j*
    //      i       j*
    //    i
    // i            j*
    //
    // 3  1 5 6  2  4
    // i
    // j  i
    //      i
    //        i
    //        j  i
    //        j     i    for forward pass only the max 
    //              i
    //           i
    //        i     j  
    //      i       j   override with max(n[i],n[j])
    //    i
    // i         j      have to find j = set.lower(3)
    //              can we do monotonic stack/queue? - no, we don't know what useful
    //                  
    // 29minute wrong answer: nums = [30,21,5,35,24]
    // my [35,30,30,35,35] Expected [35,35,35,35,35]
    //
    //  0  1 2  3  4
    // 30 21 5 35 24    max 0
    //  i                   30
    //  j  i                30
    //  j    i              30
    //          i           35
    //          j i         35
    //            i     set 24=4
    //          i j         35=3    ok my mistake was: i was taking lower, but need max distance
    //                              and second mistake: it can be more than two jumps
    // at this point let's go to hints: graph
    // 61 minute wrong answer:  989 / 1002 testcases passed, 
    // nums = [11,18,11] Output [18,18,18] Expected [11,18,18]

O(nlogn):

  • first pass left-up jumps make increasing running max array
  • second pass backwards: find the rightmost position with value less than current and use its best left-up jump res[j]
  • we can use monotonic decreasing queue and binary search it O(n): The clever iddea is based on proove: instead of finding rightmost-less, we can just use res[i+1], if we can jump right (minSoFar < res[i]).
  • res[i] - means best jump left-up
  • min < res[i] - means we can jump right-down to this min
  • no reason to jump ahead of res[i+1] because he is also sees this min’s position

Approach

  • or we can watch several examples and see that results are always perfectly sorted

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun maxValue(n: IntArray): IntArray {
        var m = 0; val res = IntArray(n.size) { m = max(m, n[it]); m }
        for (i in n.lastIndex downTo 0) {
            if (res[i] > m) res[i] = res[i+1]; m = min(m, n[i]); 
        }
        return res
    }
    pub fn max_value(n: Vec<i32>) -> Vec<i32> {
        let mut m = 0; let mut r:Vec<_> = (0..n.len()).map(|i| { m=m.max(n[i]);m}).collect();
        for i in (0..n.len()).rev() {
            if r[i] > m { r[i] = r[i+1]}; m = m.min(n[i])
        }; r
    }

06.05.2026

1861. Rotating the Box medium substack youtube

https://dmitrysamoylenko.com/leetcode/

06.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1351

Problem TLDR

Rotate and simulate gravity in matrix

Intuition

  • first simulate ‘.’ bubble left or ‘#’ bubble right
  • then rotate

Approach

  • to bubble ‘.’ left: overwrite it with ‘#’ then overwrite empty place with ‘.’
  • another solution is to split by ‘*’ chunks and sort them

Complexity

  • Time complexity: \(O(n|nlogn)\)

  • Space complexity: \(O(n)\)

Code

    fun rotateTheBox(b: Array<CharArray>) = b.map { r ->
        var j = 0
        for (i in r.indices)
            if (r[i] == '.') { r[i] = '#'; r[j++] = '.' }
            else if (r[i] == '*') j = i+1
    }.let { List(b[0].size) { i -> List(b.size) { b[b.size-1-it][i] }} }
    pub fn rotate_the_box(mut b: Vec<Vec<char>>) -> Vec<Vec<char>> {
        for r in &mut b {
            for c in r.split_mut(|&c|c=='*') { c.sort_by(|a,b|b.cmp(a)) }};
        (0..b[0].len()).map(|x|b.iter().rev().map(|r|r[x]).collect()).collect()
    }

05.05.2026

61. Rotate List medium substack youtube

https://dmitrysamoylenko.com/leetcode/

05.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1350

Problem TLDR

Rotate linked list k steps

Intuition

  1. find the length
  2. find the split point k%L
  3. connect/disconnect

More interesting idea: make a cycle-list by connecting head to tail at the end of the first loop

Approach

  • Rust doesn’t allow to make a cycle in Option<Box>
  • Rust doesn’t allow to disconnect the head while holding the reference at the last item in list

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

    fun rotateRight(h: ListNode?, k: Int): ListNode? {
        h?.next ?: return h; var len = 1; var t = h 
        while (t?.next != null) { t = t.next; len++ }
        t.next = h; for (s in 1..len - k%len) t = t?.next
        return t?.next.also { t?.next = null }
    }
    pub fn rotate_right(mut h: Option<Box<ListNode>>, k: i32) -> Option<Box<ListNode>> {
        if h.is_none() || k==0 { return h }; let (mut l, mut x) = (0, &h); 
        while let Some(n) = x { x = &n.next; l += 1 }
        if l < 2 || k % l == 0 { return h }; let mut x = &mut h;
        for _ in 0..l-(k%l) { if let Some(n) = x { x = &mut n.next }}
        let mut res = x.take(); let mut x = &mut res;
        while let Some(n) = x { x = &mut n.next }; *x = h; res
    }

04.05.2026

48. Rotate Image medium substack youtube

https://dmitrysamoylenko.com/leetcode/

04.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1348

Problem TLDR

Rotate square matrix

Intuition

Go layer by layer and do 4-swaps in place on a single side

Approach

  • reverse + transpose also works (in any order)

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

    fun rotate(m: Array<IntArray>): Unit {
        val n = m.size;
        for (l in 0..<n / 2) for (s in l..<n - l - 1) {
            val oi = n - 1 - l; val oj = n - 1 - s; val t = m[oi][oj] 
            m[oi][oj] = m[s][oi]; m[s][oi] = m[l][s]
            m[l][s] = m[oj][l]; m[oj][l] = t
        }
    }
    pub fn rotate(m: &mut Vec<Vec<i32>>) {
        m.reverse();
        for i in 0..m.len() { for j in i+1..m.len() {
            let t = m[i][j]; m[i][j]=m[j][i]; m[j][i] = t
        }}
    }

03.05.2026

796. Rotate String easy substack youtube

https://dmitrysamoylenko.com/leetcode/

03.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1347

Problem TLDR

Match strings after rotation

Intuition

Brute-force: check every possible rotation Clever idea: rotation is identical to repetition, find goal in concatenated source KMP: precompute p[] array where p[i] is the length of matching goal[0..p[i]-1] == goal[i-(p[i]-1)..i]. Jump back j = p[j-1] if chars doesn’t match.

Approach

  • the .contains in Rust has O(n) time and O(1) space complexity and based on Two-Way String Matching algo (that is alien looking and based on math

Complexity

  • Time complexity: \(O(n^2|n)\)

  • Space complexity: \(O(1|n)\)

Code

    fun rotateString(s: String, g: String) =
    s.length==g.length && g in s+s
    pub fn rotate_string(s: String, g: String) -> bool {
        let (s,g) = (s.as_bytes(), g.as_bytes());
        let (mut p, mut j) = (vec![0; g.len()], 0);
        for i in 1..p.len() {
            while j > 0 && g[i] != g[j] { j = p[j-1] }
            if g[i] == g[j] { j += 1}; p[i] = j
        }; j = 0;
        p.len() == s.len() && (0..s.len() * 2).any(|i| {
            while j > 0 && s[i%s.len()] != g[j] { j = p[j-1] }
            if s[i%s.len()] == g[j] { j += 1 }; j == p.len()
        })
    }

02.05.2026

788. Rotated Digits medium substack youtube

https://dmitrysamoylenko.com/leetcode/

02.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1346

Problem TLDR

Count numbers in 0..n with mirrored digits 2-5 6-9, 0,1,8, but not 3,4,7

Intuition

Brute-force is accepted. The logN solution:

  • each digit is a start of the subtree
  • in the subtree we have seven numbers total 0,1,2,5,6,8,9 and three numbers we should avoid to form tail from them - 0,1,8
  • the tails length is K, means total numbers count is 7^K, and to avoid is 3^K
  • if prefix has good number 2-5,6-9 then suffix can take all 7^K in its tail

Approach

  • regex [0125689]* means any good prefix, [2569] must have any of this numbers, [0125689]* any good suffix

Complexity

  • Time complexity: \(O(n|logN)\)

  • Space complexity: \(O(1)\)

Code

    fun rotatedDigits(n: Int) = (1..n).count { 
        Regex("^[0125689]*[2569][0125689]*$") in "$it"
    }
    pub fn rotated_digits(n: i32) -> i32 {
        let s = n.to_string(); let l = s.len() as u32;
        let (mut p7, mut p3, mut r, mut m) = (7_i32.pow(l), 3_i32.pow(l), 0, 0);
        for c in s.bytes() {
            p7 /= 7; p3 /= 3; let c = (c - 48) as i32;
            for d in 0..c 
                { r += (1-(152>>d&1))*(p7 - if (m | 1 << d) & 612 > 0 { 0 } else { p3 }) }
            m |= 1 << c; if m & 152 > 0 { return r; }
        } r + (m & 612 > 0) as i32
    }

01.05.2026

396. Rotate Function medium substack youtube

https://dmitrysamoylenko.com/leetcode/

01.05.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1345

Problem TLDR

Max rolling hash

Intuition

    // 0a 1b 2c 3d
    //    0b 1c 2d 3a
    // +3 -1 -1 -1
    // 3a-(b+c+d)
    //       0c 1d 2a 3b
    //    +3 -1 -1 -1

Reuse the previous hash to make a new. 0a1b2c3d converts to 0b1c2d3a=prev+3a-(b+c+d)=prev+3a-(sum-a)=prev+size*a-sum

Approach

  • Rust has a nice way to (0..).zip(&n)

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

    fun maxRotateFunction(n: IntArray) = n.run {
        val s = sum(); var a = indices.sumOf { it*n[it] }
        maxOf { x -> a.also { a += size*x - s }}
    }
    pub fn max_rotate_function(n: Vec<i32>) -> i32 {
        let (s, mut f) = (0..).zip(&n).fold((0,0), |(s,f),(i,x)|(s+x,f+i*x));
        n.iter().map(|x| (f, f+=n.len()as i32*x-s).0).max().unwrap()
    }

30.04.2026

3742. Maximum Path Score in a Grid medium substack youtube

https://dmitrysamoylenko.com/leetcode/

30.04.2026.webp

Join me on Telegram

Problem TLDR

Max right-bottom path value with at most k cost

Intuition

Recursive DP: at each cell pick max between right and bottom. Bottom-up DP: at each cell check all costs up and left.

Approach

  • return some big negative value
  • bottom-up: continue the costs c in 0..k curr[c+cost] = max(L,T) + value

Complexity

  • Time complexity: \(O(n^3)\)

  • Space complexity: \(O(n^3 | n^2)\)

Code

    fun maxPathScore(g: Array<IntArray>, k: Int): Int {
        val dp = HashMap<Int, Int>()
        fun dfs(x:Int, y:Int, c:Int): Int = dp.getOrPut(x*40000+y*200+c) {
            val nc = c+((g.getOrNull(y)?.getOrNull(x)?:4000)+1)/2; 
            if (nc > k) -99999 else g[y][x] + 
            if (x==g[0].size-1&&y==g.size-1)0 else max(dfs(x+1,y,nc),dfs(x,y+1,nc))
        }
        return dfs(0, 0, 0).takeIf{it>=0} ?:-1
    }
    pub fn max_path_score(g: Vec<Vec<i32>>, k: i32) -> i32 {
        let (k, mut dp) = (k as usize, vec![vec![-1;k as usize+1];g[0].len()]);
        for (y,r) in g.iter().enumerate() { for (x,&v) in r.iter().enumerate() {
            let (cost, mut curr) = (((v+1)/2)as usize, vec![-1; k+1]);
            for c in 0..(k+1).saturating_sub(cost) {
                let p = if x+y<1&&c<1{0} else { dp[x][c].max(if x>0{dp[x-1][c]}else{-1})};
                if p >= 0 { curr[c+cost] = v + p }
            }
            dp[x] = curr
        }} *dp[dp.len()-1].iter().max().unwrap()
    }

29.04.2026

3225. Maximum Score From Grid Operations hard substack youtube

https://dmitrysamoylenko.com/leetcode/

29.04.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1343

Problem TLDR

Max sum adjacent to marked columns

Intuition

Didn’t solve.

    // looks like DP
    // at each column peek the best index, n^2 args and n inside = n^3
    // how to add previous white when doing current black and not overcount
    // 17 minute: my result is too much / too little
    //            meaning: my dp cases are wrong
    // 1:18: TLE, O(n^4) solution
    //

The O(n^4) idea: consider previous-previous(PP), previous(P) and the current (C) columns. Peek the best C to maximize sum of previous. Use prefix sums of columns, result = max(PS(max(C,PP)) - PS(P)) The O(n^3) idea jump from n^4: submit to hard rule: can we take values from the current column or should we skip them. That allows to drop PP.

Approach

  • the idea jump is not obvious, requires graphic visualizaition of possible outcomes

Complexity

  • Time complexity: \(O(n^3)\)

  • Space complexity: \(O(n^2)\)

Code

    fun maximumScore(g: Array<IntArray>): Long {
        val dp = HashMap<Int, Long>(); val ps = Array(g.size+1){LongArray(g.size+1)}
        for (x in g.indices) for (y in 1..g.size) ps[x+1][y] += ps[x+1][y-1]+g[y-1][x]
        fun dfs(i: Int, p: Int, skip: Int):Long = if (i==g.size)0L else dp.getOrPut(i*400+p*2+skip) {
            (0..g.size).maxOf { j ->
                val a = dfs(i+1, j, 0); val b = dfs(i+1, j, 1)
                if (skip > 0 && j > p) ps[i][j]-ps[i][p] + max(a, b)
                else if (skip < 1 && j <= p) max(ps[i+1][p]-ps[i+1][j] + a, b) else 0L
        }}
        return max(dfs(0, 0, 0),dfs(0,0,1))
    }

28.04.2026

2033. Minimum Operations to Make a Uni-Value Grid medium substack youtube

https://dmitrysamoylenko.com/leetcode/

28.04.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1341

Problem TLDR

Min ops to make all numbers equal by +-X

Intuition

    // 1 4       x=3
    //+3
    //
    // 1 8 8 8 8  x=7
    //
    // is the baseline binary searchable?
    //
    // 1 1 3 5 5   x=2
    // 2 2 1 0 0
    // 1 1 0 1 1
    // 0 0 1 2 2
    //
    // 1 1 1 1 1    %2 same reminder
    // subtract reminder
    // 0 0 2 4 4, then divide by x
    // 0 0 1 2 2  this is array of counts from zero
    //            now find a median?
    // 2 4 6 8   x=2
    // 1 2 3 4 sum=10
    //          maybe consider each item as base and check
    // *
    // 1 *
    // 2 1 *
    // 3 2 1 *
    // 2 1 * 1
    // 1 * 1 2
    // * 1 2 3
    //
    // 1 4 4 5 8
    // * 3 3 4 7  right=3+3+4+7=17 left = 0
    // 3 * 0 1 4  right=  0+1+4=5=17-4*(4-1) left=0+(4-1)=3
    // 3 0 * 1 4  right= 5-3*(0-0) left=3+(0-0)
    // 4 1 1 * 3  right= 5-2*(5-4)=3 left=3+3*(5-4)=6
    // 7 4 4 3 *  right= 3-1*(8-5)=0 left=6+4*(8-5)=18
    //
  1. baseline of each value sequence is value %X
  2. number of ops is (V - V%X)/X
  3. scan from left to right, see how number of ops to the right changes after each move

Approach

  • if you know math, just use median, it is the middle of the array
  • kotlin&rust has a cool way to flatten grid

Complexity

  • Time complexity: \(O(nm)\)

  • Space complexity: \(O(nm)\)

Code

    fun minOperations(g: Array<IntArray>, v: Int) = g.reduce{a,b->a+b}
    .sorted().run{sumOf {if((it-get(0))%v>0)return-1;abs(it-get(size/2))/v}}
    pub fn min_operations(g: Vec<Vec<i32>>, x: i32) -> i32 {
        let mut a=g.concat();a.sort();let m=a[a.len()/2];
        if a.iter().any(|v|(v-a[0])%x!=0){-1}else{a.iter().map(|v|(v-m).abs()/x).sum()}
    }

27.04.2026

1391. Check if There is a Valid Path in a Grid medium substack youtube

https://dmitrysamoylenko.com/leetcode/

27.04.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1341

Problem TLDR

Path 0 to end on type-cells 2D grid

Intuition

The union-find idea: connect all cells according to their types. Check if the target type complements current type. The single path idea: each cell has a single enter/exit so just check path from the left and from the top of the 0 cell.

Approach

  • we can use transition matrix
  • it can be shortened to strings of six sections each of 4 directions: current direction changes to target direction
  • 82=2^1+w^4+2^6, 100=2^2+2^5+2^6, 466=2^1+2^4+2^6 + 2^(2+4)+2^(3+4)+2^(4+4)

Complexity

  • Time complexity: \(O(nm or path)\)

  • Space complexity: \(O(nm or 1)\)

Code

    fun hasValidPath(g: Array<IntArray>): Boolean {
        val w = g[0].size; val u = IntArray(g.size * w) { it }
        fun f(x: Int): Int = if (x == u[x]) x else {u[x]=f(u[x]);u[x]}
        for (i in u.indices) { val x = i%w; val y = i/w
            if (x+1<w&&82 shr g[y][x]and 1>0&&g[y][x+1]%2>0) u[f(i)] = f(i+1) 
            if (y+1<g.size&&g[y][x]in 2..4&&100 shr g[y+1][x]and 1>0) u[f(i)]=f(i+w)
        }
        return f(0) == f(u.size - 1)
    }
    pub fn has_valid_path(g: Vec<Vec<i32>>) -> bool {
        (0..2).any(|i| 466 >> g[0][0] + i * 4 & 1 > 0 && 
            successors(Some((0, 0, i)), |&(y, x, d)| {
                let (x,y) = ((x as i32+(1-d)%2)as usize, (y as i32+(2-d)%2)as usize);
                let d = b"....0.2..1.31..2..1032...03."[(*g.get(y)?.get(x)?*4+d)as usize]as i32-48;
                (d >= 0 && x | y > 0).then_some((y, x, d))
            }).any(|(y, x, _)| y == g.len() - 1 && x == g[0].len() - 1)
        )
    }

26.04.2026

1559. Detect Cycles in 2D Grid medium substack youtube

https://dmitrysamoylenko.com/leetcode/

26.04.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1340

Problem TLDR

Check cycle in 2D grid

Intuition

The trivial idea: start DFS from each position, mark visited cells, check neighbours, skip parent. Have to mark visited cells again with different mark to not do DFS on the same group later. The mark in post-order should be different to make a wall for the next group.

The little bit more interesting idea: use Union-Find. Walk row by row and connect items. If there is a cycle then right cell would be already connected.

Approach

  • the G is for ‘Good’
  • use path compression for Union-Find
  • do you know why we don’t searching the root for the down cell in Rust?

Complexity

  • Time complexity: \(O(nm)\)

  • Space complexity: \(O(nm)\)

Code

    fun containsCycle(g: Array<CharArray>) = IntArray(g.size*g[0].size){it}
        .let { u -> u.indices.any { i -> val w = g[0].size
            fun f(x: Int): Int = if (u[x]==x) x else {u[x]=f(u[x]);u[x]}
            fun c(j: Int, G: Boolean) = G && g[j/w][j%w] == g[i/w][i%w]
                &&(f(i) == f(j) || { u[f(i)] = f(j); !G}())
            c(i+1, i%w<w-1) || c(i+w, i+w<u.size)
        }}
    pub fn contains_cycle(g: Vec<Vec<char>>) -> bool {
        let w=g[0].len(); let z=g.len()*w; let mut u:Vec<_>=(0..z).collect();
        (0..z).any(|i|{
            if i+w<z && g[i/w+1][i%w] == g[i/w][i%w] { u[i+w] = i }
            i%w<w-1 && g[i/w][i%w+1] == g[i/w][i%w] && {
                let [a,b] = [i, i+1].map(|mut x|{while x!=u[x]{u[x]=u[u[x]];x=u[x]}x});
                a == b || {u[a] = b; 0>0}
            }
        })
    }

25.04.2026

3464. Maximize the Distance Between Points on a Square hard substack youtube

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

25.04.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1339

Problem TLDR

Max of minimum distnace between selected k points on square perimeter

Intuition

// if we use binary search the min distance:
    // how can we peek k elements?
    // how to peek first?
    // | * * * * * *     *   *  |(unrolled perimeter)
    //   |.........|             dist
    // so for every dist we should find the first item we take
    // and then check all others
    // dist - log(n)
    // every first - n
    // all others k fit? - n  (maybe this can be improved)
    // solution is n^2log(n)
    //
    // how to faster check k-fit?
    // we stop as soon as we take k elements from start
    // but what if dist is big and we have to skip n elements
    // how to jump to element by dist?
    //
    // 1 2 3   5 6   8 9 
    // *                    (dist=5, how to jump to 5?)
    //         ^ binary search to this position? 
    //        log(n)
    // so the solution now is nklog^2(n)
    // should be accepted
    //
    // now how to unroll?
    // (already 18 minutes just for thinking)
    // from 0,0 go clockwise
    // 0,0 - 0,1 - 0,2 - 1,2 - 2,2 - 2,1 - 2,0 - (1,0)?
    // or just take four edges then concat them
    // 26 minute
    // i have a doubt: the dist in binary search is not precise
    // 29 minute, lets go hints (they basically the same idea)
    //
    // except hint about selecting elements: no binary search?
    // 47 minute: wrong answer on test case side = 2 points = [[0,0],[1,2],[2,0],[2,2],[2,1]] k = 4
    // 2 instead of 1
    // 54 minute: i have error of duplicate on edges concatenations
    // 1:10 minute: gosh i spot that i can't use binary search on a cycled perimeter coordinates
    // ok let's give up, i can't spend more than 1 hour

Didn’t solved myself. Several aha-moments are required:

  1. flatten the perimeter, every point has perimeter-distance to 0,0, sort by it
  2. freeze the minimum at-most distance between points and binary search it
  3. to optimally take k points we have to scan for starting point
  4. to find next point from start we can use binary search
  5. we have to check wrap-around between first taken and last taken point, 4s-(last-first)

Approach

  • symmetry allows nice conversion to distance: top and left is (x+y), bottom and right is (perimeter - (x+y))
  • inner binary search can be from previous position
  • upper bound of distance is perimeter/k

Complexity

  • Time complexity: \(O(nklog^2(n))\)

  • Space complexity: \(O(n)\)

Code

    fun maxDistance(s: Int, p: Array<IntArray>, k: Int): Int {
        val P = 4L*s; var L = 0L; var H = P/k
        val e = p.map { (x,y) -> if (x==0||y==s)x+y+0L else P-x-y }.sorted()
        while (L <= H) {
            val M = (L + H) / 2
            if (p.indices.any { i -> var j = i; var c = 1
                do { j = e.binarySearch(e[j] + M,fromIndex=j); if (j < 0) j = -j-1 } 
                while (j < e.size && e[j] - e[i] <= P - M && ++c < k)
                c == k
            }) L = M + 1 else H = M - 1
        }
        return H.toInt()
    }
    pub fn max_distance(s: i32, p: Vec<Vec<i32>>, k: i32) -> i32 {
        let (s, P, n, mut L, mut H) = (s as i64, 4*s as i64, p.len(), 0, 4*s as i64/k as i64);
        let mut e = p.iter().map(|v| { let(x,y)=(v[0]as i64, v[1]as i64); 
                                      if x==0||y==s{x+y}else{P-x-y}}).sorted().collect_vec();
        while L <= H { 
            let M = (L+H)/2;
            if (0..n).any(|i| (1..k).try_fold(i, |j,_| {
                let x = e[j..].partition_point(|&v| v < e[j]+M)+j;
                (x < n && e[x]-e[i] <= P-M).then_some(x)
            }).is_some()) { L = M + 1 } else { H = M - 1 }
        } H as i32
    }

24.04.2026

2833. Furthest Point From Origin easy substack youtube

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

24.04.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1338

Problem TLDR

Max dist when replace _ with L or R

Intuition

The brute-force: replace all _ to R and check balance, then to L and check again. Some geometry transformation:_ + abs(R-L) = length-2*min(L,R) (see video explanation)

Approach

  • asci %5 gives perfect 0,1,2 for _,L,R, do with that what you want

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

    fun furthestDistanceFromOrigin(m: String) =
    2*"LR".maxOf{c->m.count{it!=c}}-m.length
    pub fn furthest_distance_from_origin(m: String) -> i32 {
        (m.len()-2*m.matches('L').count().min(m.matches('R').count())) as _
    }

23.04.2026

2615. Sum of Distances medium substack youtube

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html 23.04.2026.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1337

Problem TLDR

Sum of distances to each occurance

Intuition

Didn’t solved without a hint.

    // 0123456789
    // a...a....a...
    // i   j    j    4+9     
    // j   i    j    4+5
    // j   j    i    9+5
    //
    // a b c d
    // *       |a-b|+|a-c|+|a-d|=b-a + b-a+c-b + b-a+c-b+d-c=-3a+b+c+d
    //   *     |a-b|+|b-c|+|b-d|=b-a + c-b + c-b+d-c=-a-b+c+d
    //     *   |a-c|+|b-c|+|c-d|=b-a+c-b + c-b + d-c=-a-b+c+d
    //       * |a-d|+|b-d|+|c-d|= b-a+c-b+d-c + c-b+d-c + d-c=-a-b-c+3d
    // any way to shortcut this?
    //
    // a b c d e f
    //           *                        5f-e-d-c-b-a sum+4f-2e-2d-2c-2b-2a -sum+6f
    //         *   f-e + 4e-d-c-b-a     = f+3e-d-c-b-a sum+2e-2d-2c-2b-2a
    //       *     f-d+e-d + 3d-c-b-a   = f+e+d -c-b-a sum-2c-2b-2a
    //     *       f-c+e-c+d-c + 2c-b-a = f+e+d -c-b-a sum-2c-2b-2a
    //   *         f-b+e-b+d-b+c-b+b-a  = f+e+d+c-3b-a sum-4b-2a 
    // *           f-a+e-a+d-a+c-a+b-a  = f+e+d+c+b-5a sum -6a
    // ok what the rule?
    // (acceptance rate 40%)
    // from hints: freq*idx-sum
    // a b c  d
    //  +x=prev+x
    //  +x+2y=prev+2y
    //  +x+2y+3z=prev+3z

The simple working intuition:

  • consider only forward pass for now
  • each position sum is the previous positions sum plus frequency so-far count of distances to last occurence

Approach

  • we can iterate once but with two cursors: forward and backward and duplicate pairs of variables have to be tracked

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

    fun distance(n: IntArray) = LongArray(n.size).apply {
        val m = Array(2) { HashMap<Int, LongArray>() }
        for (i in n.indices) for ((j,s) in listOf(i to 2, (size - 1 - i) to 0))
            m[s/2].getOrPut(n[j]) { LongArray(2) }.let { a ->
                this[j] += (s-1) * (j * a[0] - a[1]); a[0]++; a[1] += 1L*j
            }
    }
    pub fn distance(n: Vec<i32>) -> Vec<i64> {
        let (mut r, mut m) = (vec![0; n.len()], HashMap::new());
        for i in 0..n.len() { for (j, d,s) in [(i, 1,1), (n.len() - 1 - i, 0,-1)] {
            let e = m.entry(n[j]).or_insert([(0, 0); 2]);
            r[j] += s * (j as i64 * e[d].0 - e[d].1);
            e[d].0 += 1; e[d].1 += j as i64;
        }} r
    }

22.04.2026

2452. Words Within Two Edits of Dictionary medium substack youtube

22.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1336

Problem TLDR

Words in dictionary with 2 edits #medium

Intuition

  1. We can place all single-edits of dictionary into a hash set, then check single-edits of words.
  2. Or just brute-force with the same time complexity

Approach

  • Rust has retain

Complexity

  • Time complexity: \(O(n^3)\)

  • Space complexity: \(O(n)\)

Code

// 28ms
    fun twoEditWords(q: Array<String>, d: Array<String>) = 
    q.filter { q -> d.any { d -> d.indices.count { d[it] != q[it]} < 3 }}
// 1ms
    pub fn two_edit_words(mut q: Vec<String>, d: Vec<String>) -> Vec<String> {
        q.retain(|q| d.iter().any(|d| d.bytes().zip(q.bytes()).filter(|(d,q)|d!=q).count()<3)); q
    }

21.04.2026

1722. Minimize Hamming Distance After Swap Operations medium substack youtube

21.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1335

Problem TLDR

Diff src vs target after rearrange by rules #medium #uf

Intuition

    // we can form connected islands of numbers 
    // can change only src
    // [a,b,c,d,e,f]
    //  * *   *       island, then sort or take from hashmap-with-counter by target
    // 
  1. intersected swaps form connected islands
  2. we can sort both src&target inside each island
  3. we can use counting sort

Approach

  • union-find to find islands
  • path compression
  • Rust: itertools counts()
  • Kotlin: Array of hashmaps shorter than groupBy

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 68ms
    fun minimumHammingDistance(s: IntArray, t: IntArray, a: Array<IntArray>): Int {
        val u = IntArray(s.size) { it }; val fvc = Array(s.size) { HashMap<Int,Int>() }
        fun f(x: Int): Int = { if (x != u[x]) u[x] = f(u[x]); u[x] }()
        for ((a,b) in a) u[f(a)] = f(b)
        for ((i,v) in s.withIndex()) fvc[f(i)][v] = 1 + (fvc[f(i)][v] ?: 0)
        return s.indices.count { i ->
            val c = fvc[f(i)][t[i]] ?: 0
            if (c > 0) fvc[f(i)][t[i]] = c-1; c <= 0
        }
    }
// 33ms
    pub fn minimum_hamming_distance(s: Vec<i32>, t: Vec<i32>, a: Vec<Vec<i32>>) -> i32 {
        let mut u: Vec<_> = (0..s.len()).collect();
        fn f(u: &mut [usize], x: usize) -> usize { if u[x] != x { u[x] = f(u, u[x]) } u[x] }
        for p in a { let (x, y) = (f(&mut u, p[0] as _), f(&mut u, p[1] as _)); u[x] = y; }
        let mut m = (0..s.len()).map(|i|(f(&mut u,i),s[i])).counts();
        (0..s.len()).filter(|&i| {
            let c = m.entry((f(&mut u,i),t[i])).or_default();
            if *c > 0 { *c -= 1; false } else { true }
        }).count() as _
    }

20.04.2026

2078. Two Furthest Houses With Different Colors easy substack youtube

20.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1334

Problem TLDR

Max distance between different numbers #easy

Intuition

Brute-force.

Clever solution: first or last is guaranteed to be included (if first==last its entire size, if first!=last then there is a third color in-between).

Approach

  • scan all indices, pick max to first or last
  • downsize the max length while prefix and suffix of this length is not good

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 14ms
    fun maxDistance(c: IntArray) =
    c.indices.last { c[0]!=c[it] || c.last()!=c[c.size-1-it] }
// 0ms
    pub fn max_distance(c: Vec<i32>) -> i32 {
       let n=c.len()-1; (0..n+1).rposition(|l|c[0]!=c[l]||c[n]!=c[n-l]).unwrap() as _
    }

19.04.2026

1855. Maximum Distance Between a Pair of Values medium

substack youtube

19.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1333

Problem TLDR

Max distance a[i] not greater than b[j] #medium #sliding_window

Intuition

  1. Sliding window: for each left pointer move the rigth as far as possible
  2. Max-window: always expand the window, shrink window only when condition is broken

Approach

  • the max-window is more clever
  • binary search would also work

Complexity

  • Time complexity: \(O(n)\), nlog(n) for binarysearch

  • Space complexity: \(O(1)\)

Code

// 81ms
    fun maxDistance(a: IntArray, b: IntArray) = maxOf(0, a.indices
    .maxOf { i -> -b.asList().binarySearch { if (it < a[i]) 1 else -1 }-i-2 })
// 3ms
    pub fn max_distance(a: Vec<i32>, b: Vec<i32>) -> i32 {
        let (mut i, mut j) = (0, 0);
        while i < a.len() && j < b.len() { if a[i] > b[j] { i += 1 }; j += 1}
        0.max(j as i32 - i as i32 - 1)
    }

18.04.2026

3783. Mirror Distance of an Integer easy substack youtube

18.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1332

Problem TLDR

Diff with reversal #easy

Intuition

Reverse and subtract. Can’t be done in-place, because we need to know the length of number.

Approach

  • Kotlin’s shortest is strings reversal
  • Rust doesn’t have divmod, but can use asm that will mutate ‘x’ and return reminder let d: i32; unsafe { asm!("cdq;div {0}", in(reg) 10, inout("eax") x, out("edx") d) }

Complexity

  • Time complexity: \(O(lg(n))\)

  • Space complexity: \(O(1)\)

Code

// 10ms
    fun mirrorDistance(n: Int) = 
    abs(n - "$n".reversed().toInt())
// 0ms
    pub fn mirror_distance(n: i32) -> i32 {
        let (mut r, mut x) = (0, n);
        while x > 0 { r = r*10+x%10; x/=10}; (r-n).abs()
    }

17.04.2026

3761. Minimum Absolute Distance Between Mirror Pairs medium substack youtube

17.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1331

Problem TLDR

Distance to prev mirror number #medium

Intuition

Use a hashmap, scan, put mirrors into map, check for current number.

Approach

  • Kotlin: string conversion is shorter
  • Rust: (0..).zip(n), filter_map

Complexity

  • Time complexity: \(O(m)\)

  • Space complexity: \(O(n)\)

Code

// 232ms
    fun minMirrorPairDistance(n: IntArray) = HashMap<Int, Int>().let { m ->
        n.indices.minOf { i ->
            i - (m[n[i]] ?: -n.size).also { m["${n[i]}".reversed().toInt()] = i }
        }.takeIf { it < n.size } ?: -1
    }
// 19ms
    pub fn min_mirror_pair_distance(n: Vec<i32>) -> i32 {
        let mut m = HashMap::new();
        (0..).zip(n).filter_map(|(i, mut x)| {
            let d = m.get(&x).map(|j| i-j);
            let mut r = 0; while x > 0 {r = r*10+x%10; x /= 10}
            m.insert(r, i); d
        }).min().unwrap_or(-1)
    }

16.04.2026

3488. Closest Equal Element Queries medium substack youtube

16.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1330

Problem TLDR

Shortest distances to the same values #medium

Intuition

    // [1,3,1,4,1,3,2], queries = [0,3,5]
    //  *   *   *
    // brute force is n^2
    //  0   2   4                  *
    //  for each find the closest to the right and to the left
    //  to the left
    //  ?   2   2    (and update first to (first+size-i)
    //  to the right
    //  2   2   ?    (and update last to (size-last+i))
    //

In a 2*n forward pass updated the distance to the previous value and to the current value.

Approach

  • HashMap’s put in Kotlin and insert in Rust returns the previous value

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 104ms
    fun solveQueries(n: IntArray, q: IntArray) = HashMap<Int,Int>().run {
        val z = n.size; val d = IntArray(z) { z }
        for (i in 0..<2*z) put(n[i%z], i)?.let { p ->
            d[i%z] = min(d[i%z], i-p); d[p%z] = min(d[p%z], i-p)
        }
        q.map { d[it].takeIf { it < z } ?: -1 }
    }
// 38ms
    pub fn solve_queries(n: Vec<i32>, q: Vec<i32>) -> Vec<i32> {
        let z = n.len(); let (mut p, mut d) = (HashMap::new(), vec![z;z]);
        for i in 0..2*z { if let Some(p) = p.insert(n[i%z], i) {
            d[i%z] = d[i%z].min(i-p); d[p%z] = d[p%z].min(i-p)
        }}
        q.iter().map(|&i|if d[i as usize]<z {d[i as usize] as i32}else{-1}).collect()
    }

15.04.2026

2515. Shortest Distance to Target String in a Circular Array easy substack youtube

15.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1329

Problem TLDR

Distance to target #easy

Intuition

  • (s+dist)%n forward
  • (s-dist)%n backward

Approach

  • don’t forget s
  • Kotlin has .mod that handles sign, indexOfFirst vs firstOrNull
  • Rust: find

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 14ms
    fun closestTarget(w: Array<String>, t: String, s: Int) = 
    w.indices.indexOfFirst { w[(s + it)%w.size]==t || w[(s-it).mod(w.size)]==t }
// 0ms
    pub fn closest_target(w: Vec<String>, t: String, s: i32) -> i32 {
        let n = w.len() as i32;
        (0..n).find(|i| w[((s + i) % n) as usize] == t || w[((s - i + n) % n) as usize] == t).unwrap_or(-1)
    }

14.04.2026

2463. Minimum Total Distance Traveled hard substack youtube

14.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1328

Problem TLDR

Shortest distances to travel robots to factories #hard #dp

Intuition

Didn’t solve without the hints.

    // does speed matters?
    // 
    // match each robot to each factory?
    //
    // r r f f
    //
    // the dp state can be cached by robots directions in a tail + factories
    //
    // the only thing is: does the order/speed matter?
    //
    // another idea: start BFS from each robot
    //               remove factory hits as repaired
    // but: positions are 10^9, we can't simulate travel
    //
    // can travel by entire distance at once?
    // put in a next_timestamp priority queue
    // 
    // 27 minute wrong answer, mine bigger, meaning not optimal 
    //                                      bfs didn't work here
    // [9,11,99,101] [[10,1],[7,1],[14,1],[100,1],[96,1],[103,1]]
    // 30 minute look for hint: segments
    //
    // r f r r f
    // *****
    //   

Consider each robot from left to right to pick or skip factory from left to right.

Approach

  • iterative version can save some space

Complexity

  • Time complexity: \(O(nfl)\)

  • Space complexity: \(O(nfl)\)

Code

// 254ms
    fun minimumTotalDistance(r: List<Int>, f: Array<IntArray>): Long {
        val r = r.sorted(); val dp = HashMap<Int, Long>()
        val f = f.sortedBy { it[0] }.flatMap { f -> List(f[1]) { f[0] }}
        fun dfs(i: Int, j: Int): Long = if (i == r.size) 0L else 
            if (j == f.size) Long.MAX_VALUE/2 else 
            dp.getOrPut(i*10000+j) { min(abs(r[i]-f[j]) + dfs(i+1, j+1), dfs(i, j+1)) }
        return dfs(0, 0)
    }
// 2ms
    pub fn minimum_total_distance(r: Vec<i32>, f: Vec<Vec<i32>>) -> i64 {
        let f: Vec<_> = f.into_iter().sorted_by_key(|v|v[0])
                         .flat_map(|v|vec![v[0]; v[1] as usize]).collect();
        let mut dp = vec![0; f.len() + 1];
        for p in r.into_iter().sorted() {
            let mut prev = dp[0]; dp[0] = i64::MAX/2;
            for j in 0..f.len() { 
                let t = dp[j+1]; dp[j+1] = ((p-f[j]).abs() as i64 + prev).min(dp[j]); prev = t }
        } dp[f.len()]
    }

13.04.2026

1848. Minimum Distance to the Target Element easy substack youtube

13.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1327

Problem TLDR

Distance to target from start #easy

Intuition

Iterate from left to right. Or iterate from the start.

Approach

  • Kotlin ‘zip’ doesn’t work with non-equal ranges
  • Rust itertools has ‘interleave’, abs_diff

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 16ms
    fun getMinDistance(n: IntArray, t: Int, s: Int) =
    n.indices.filter { n[it] == t }.minOf { abs(it - s) }
// 0ms
    pub fn get_min_distance(n: Vec<i32>, t: i32, s: i32) -> i32 {
        (0..=s as usize).rev().interleave(s as usize+1..n.len())
        .find(|&i| n[i] == t).unwrap().abs_diff(s as usize) as _
    }

12.04.2026

1320. Minimum Distance to Type a Word Using Two Fingers hard substack youtube

12.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1326

Problem TLDR

Min travel on keyboard to type a word #hard #dp

Intuition

    // len is 300, table = 26
    // two fingers
    // travel finger 1 + travel finger 2
    //
    // HAPPY
    // 11221
    // can be dp i, f1, f2 = dist 300*26^2
    // should work
    // 11 minute, 45/55 test case wrong answer 294 vs 295 expected
    // mine is better means my algo cheats
    //

Top down dp is accepted. (position, finger1, finger2)

The clever intuition:

  • at each step we have a situation: current target is w[i], one finger definitely at w[i-1], search for the other finger
  • dp[a] is how much maximum we saved using extra finger finally placed at a
  • dp[b] = max(A..Z -travel(a,c) +travel(b,c) + dp[a]), this finger ‘saves’ us from travel(bc) and makes us travel(ac)
  • we store in dp[b] because we place finger on c and c became b at the next step

Approach

  • write top down, its ok

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 35ms
    fun t(a: Char, b: Char) = abs((a-'A')%6-(b-'A')%6) + abs((a-'A')/6-(b-'A')/6)
    fun minimumDistance(w: String) = w.zipWithNext(::t).sum() - 
        w.zipWithNext().fold(IntArray(26)) { dp, (b,c) ->
            dp[b-'A'] = ('A'..'Z').maxOf { dp[it-'A'] - t(it,c) } + t(b,c); dp
        }.max()
// 0ms
    pub fn minimum_distance(w: String) -> i32 {
        fn t(a: i32, b: i32) -> i32 { (a%6-b%6).abs() + (a/6-b/6).abs() }
        let (s, m) = w.bytes().map(|b|(b-b'A') as i32).tuple_windows().fold((0,[0;26]), |(s, mut dp), (b,c)| {
            dp[b as usize] = (0..26).map(|a| dp[a as usize]-t(a,c)).max().unwrap() + t(b,c); (s + t(b,c), dp)
        }); s - m.into_iter().max().unwrap()
    }

11.04.2026

3741. Minimum Distance Between Three Equal Elements II medium substack youtube

11.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1325

Problem TLDR

Min sum of distances between i,j,k of the same values #medium

Intuition

Same as yesterday: keep two previous indices. Sum of abs (i,j,k) is 2*(i-k).

     fun minimumDistance(n: IntArray) = n
        .indices.groupBy{n[it]}.values
        .flatMap { it.windowed(3) { 2 * (it[2]-it[0])}}
        .minOrNull() ?: -1

    pub fn minimum_distance(n: Vec<i32>) -> i32 {
        (0..n.len()).into_group_map_by(|&i| n[i]).values()
        .flat_map(|v| v.windows(3).map(|w|2*(w[2]-w[0]) as i32))
        .min().unwrap_or(-1)
    }

Approach

  • let’s write optimized versions
  • my yesterday golfed solutiona are also accepted

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 85ms
    fun minimumDistance(n: IntArray) =
        LongArray(100001){-1}.let { p -> n.indices.minOf { i ->
            val j = p[n[i]]; p[n[i]] = j shl 32 or 1L*i
            if (j >= 0) 2L*(i-(j shr 32)) else Long.MAX_VALUE
        }.takeIf { it < Long.MAX_VALUE } ?: -1L }
// 16ms
    pub fn minimum_distance(n: Vec<i32>) -> i32 {
        let mut p = [-1i64; 100001];
        (0..n.len()).filter_map(|i| {
            let j = p[n[i] as usize]; p[n[i] as usize] = j<<32|i as i64;
            (j >= 0).then(|| 2*(i as i64 - (j>>32)) as i32)
        }).min().unwrap_or(-1)
    }

10.04.2026

3740. Minimum Distance Between Three Equal Elements I easy substack youtube

10.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1324

Problem TLDR

Min sum of distances between i,j,k of the same values #easy

Intuition

Brute-force.

Approach

  • 2*(k-i) is the math optimization
  • [101] is the space optimization

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 32ms
    fun minimumDistance(n: IntArray) = n
        .indices.groupBy{n[it]}.values
        .flatMap { it.windowed(3) { 2 * (it[2]-it[0])}}
        .minOrNull() ?: -1
// 0ms
    pub fn minimum_distance(n: Vec<i32>) -> i32 {
        (0..n.len()).into_group_map_by(|&i| n[i]).values()
        .flat_map(|v| v.windows(3).map(|w|2*(w[2]-w[0]) as i32))
        .min().unwrap_or(-1)
    }

09.04.2026

3655. XOR After Range Multiplication Queries II hard blog post youtube

09.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1323

Problem TLDR

Run stepped multiplication queries #hard #mod

Intuition

Almost solved, gave up.

    // same as yesterday
    // i learned it before: split queries by sqrt(k)
    // a^x = a^{2*(x/2 + x%2)} = (a*a)^{x/2}*(a*a)^{x%2}
    // 18 minute, there is an error somewhere
    // 28 minute, 2 errors fixes, still wrong answer
    // nums =
    //[2,3,1,5,4]
    //queries =
    //[[1,4,2,3],[0,2,1,2]]
    // 4, 18, 2, 15, 4 -- expected
    //
    // 2,  3, 1,  5, 4
    // 4,  6, 2,  5, 4   (after k=1 l..r=0..2 v=2)
    // 4, 18, 6, 15, 12 -- mine (after k=2 l..r=1..4 v=3) (looks like i multiplied all without step)
    //     *      *
    // 42 minute: how to deal with step?
    // 45 minute: another test case wrong 68/605
    // 49 minute: i don't see any error in my code
    //
    // nums =
    // [562,62]
    // queries =
    // [[0,1,2,7],[1,1,2,11],[0,1,2,2],[1,1,1,11],[1,1,2,1],[0,0,1,9],[0,1,2,4],[1,1,1,6],[0,0,2,17]]
    // Output
    // 591836426
    // Expected
    // 4839076
    // 58 minute gave up.
  1. Divide problem on slow/fast path: k = sqrt(q) is the point of separation
  2. fast path is the big k steps, can be brute forced
  3. slow path: save events of start-stop for every k in p[k][l..r] individually
  4. collect them for every k separately
  5. modulo doesnt allow 1/v operation, have to use pow(v, M-2) instead

Approach

  • my point of failure was the attention to one detail: when to cancel, it is not r+1, we have to use steps
  • the threshold of 40: ~300ms vs 400: ~1300ms

Complexity

  • Time complexity: \(O(nsqrt(q))\)

  • Space complexity: \(O(nsqrt(q))\)

Code

// 323ms
    fun xorAfterQueries(n: IntArray, q: Array<IntArray>): Int {
        val p = Array(40) { IntArray(n.size+1){1} }; val M = 1_000_000_007L
        fun pow(a: Long, b: Long): Long = if (b==0L) 1L else pow(a*a%M, b/2)*(if (b%2>0)a else 1L)%M
        for ((l,r,k,v) in q) 
            if (k >= 40) for (i in l..r step k) n[i] = (1L*n[i]*v%M).toInt() else {
                p[k][l] = (1L*p[k][l]*v%M).toInt(); val next = l + ((r-l)/k+1)*k
                if (next < n.size) p[k][next] = (1L*p[k][next]*pow(1L*v, M-2L)%M).toInt()
            }
        for (k in 1..<40) for (i in n.indices) {
            if (i >= k) p[k][i] = (1L*p[k][i]*p[k][i-k]%M).toInt()
            n[i] = (1L*n[i]*p[k][i]%M).toInt()
        }
        return n.reduce(Int::xor)
    }
// 322ms
    pub fn xor_after_queries(mut n: Vec<i32>, q: Vec<Vec<i32>>) -> i32 {
        const M: i64 = 1000000007; let z = n.len(); let mut c = vec![vec![1; z + 1]; 40];
        fn p(a: i64, b: i64) -> i64 { if b < 1 { 1 } else { p(a * a % M, b / 2) * (if b % 2 > 0 { a } else { 1 }) % M } }
        for u in q {
            let (l, r, k, v) = (u[0] as usize, u[1] as usize, u[2] as usize, u[3] as i64);
            if k < 40 { c[k][l] = c[k][l] * v % M; let x = r - (r - l) % k + k; if x < z { c[k][x] = c[k][x] * p(v, M - 2) % M } }
            else { for i in (l..=r).step_by(k) { n[i] = (n[i] as i64 * v % M) as i32 } }
        }
        for k in 1..40 { for i in 0..z {
            if i >= k { c[k][i] = c[k][i] * c[k][i - k] % M }
            n[i] = (n[i] as i64 * c[k][i] % M) as i32;
        }}
        n.into_iter().fold(0, |a, b| a ^ b)
    }

08.04.2026

3653. XOR After Range Multiplication Queries I medium blog post substack youtube

08.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1322

Problem TLDR

Run queries #medium

Intuition

Just run queries.

Approach

  • cast to long in-place

Complexity

  • Time complexity: \(O(nq)\)

  • Space complexity: \(O(1)\)

Code

// 96ms
    fun xorAfterQueries(n: IntArray, q: Array<IntArray>) = n.apply {
        for ((l,r,k,v) in q) for (i in l..r step k)
            n[i] = ((1L*n[i] * v) % 1000000007).toInt()
    }.reduce(Int::xor)
// 56ms
    pub fn xor_after_queries(mut n: Vec<i32>, q: Vec<Vec<i32>>) -> i32 {
        for v in q { for i in (v[0] as usize..=v[1] as _).step_by(v[2] as _) {
            n[i] = (n[i] as i64 * v[3] as i64 % 1000000007) as _
        }}
        n.into_iter().fold(0, |a, b| a ^ b)
    }

07.04.2026

2069. Walking Robot Simulation II medium substack youtube

07.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1321

Problem TLDR

Implement perimeter-robot #medium

Intuition

// 15 minute: so this TLE
//
// does robot always goes on perimeter? -- yes
//
// make it linear
// 
// xxxxxyyyxxxxxyyyxxxxxyyyxxxxxyyy
//  w    h   w   h 0
//
// each rotation is extra step? - no
  1. its only the perimeter
  2. w-1, h-1
  3. top-down south

Approach

  • extract separate method

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 146ms
class Robot(a: Int, b: Int, var p: Int = 0) {
    val w=a-1; val h=b-1; val wh=w+w+h+h
    val i get() = when (val m = p % wh) {
        in 0..w -> listOf(m, 0) to if(m==0 && p>0) "South" else "East"
        in 0..w+h -> listOf(w, m-w) to "North"
        in 0..wh-h -> listOf(wh-h-m, h) to "West"
        else -> listOf(0, wh-m) to "South"
    }
    fun step(n: Int) { p += n }; fun getPos() = i.first; fun getDir() = i.second
}
// 16ms
struct Robot(i32, i32, i32, i32); impl Robot {
    fn new(a: i32, b: i32) -> Self { Self(a-1, b-1, 2*a+2*b-4, 0) }
    fn step(&mut self, n: i32) { self.3 += n }
    fn i(&self) -> (Vec<i32>, &'static str) {
        let (w, h, t, p, m) = (self.0, self.1, self.2, self.3, self.3 % self.2);
        if m <= w { (vec![m, 0], if p>0 && m==0 {"South"} else {"East"}) }
        else if m <= w+h { (vec![w, m-w], "North") }
        else if m <= t-h { (vec![t-h-m, h], "West") }
        else { (vec![0, t-m], "South") }
    }
    fn get_pos(&self) -> Vec<i32> { self.i().0 }
    fn get_dir(&self) -> String { self.i().1.into() }
}

06.04.2026

874. Walking Robot Simulation medium substack youtube

06.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1320

Problem TLDR

Farthest robot movement #medium #simulation

Intuition

Just simulate the movements, 1..9 can be iterated.

Approach

  • to compress position into a single variable, we have to make coordinates positive

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(o)\)

Code

// 41ms
    fun robotSim(c: IntArray, o: Array<IntArray>): Int {
        val S = o.map { it[1]+32768 shl 16 or it[0]+32768 }.toSet()
        var d = 0; var p = -2147450880; val D = listOf(65536, 1, -65536, -1)
        return c.maxOf {
            if (it < 0) d = (d - 2*it - 1) % 4
            repeat(it) { if (p+D[d] !in S) p += D[d] }
            val x = (p and 65535) - 32768; val y = (p ushr 16) - 32768
            x*x + y*y
        }
    }
// 1ms
    pub fn robot_sim(c: Vec<i32>, o: Vec<Vec<i32>>) -> i32 {
        let s: HashSet<_> = o.iter().map(|v| v[1]+32768<<16 | v[0]+32768).collect();
        let (mut p, mut d, D) = (-2147450880,0, [65536, 1, -65536, -1]);
        c.into_iter().fold(0, |m, i| {
            if i < 0 {  d = (d + if i < -1 { 3 } else { 1 }) % 4  }
            for _ in 0..i { if !s.contains(&(p + D[d])) { p += D[d] } } 
            let (x, y) = ((p & 65535) - 32768, (p as u32 >> 16) as i32 - 32768);
            m.max(x*x + y*y)
        })
    }

05.04.2026

657. Robot Return to Origin easy

youtube

05.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1319

Problem TLDR

R,L,U,D return to 0 in XY plane #easy

Intuition

Compare counts separately for vertical and horizontal directions. Both directions can fit into a single variable h*2^16+v.

Approach

  • hash collisions of 8 make the solution extra spicy
  • do you know how %5 works?

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 38ms
    fun judgeCircle(m: String) = 
        0==m.sumOf {listOf(8,-1,1,-8)[it.code%5]}
// 0ms
    pub fn judge_circle(m: String) -> bool {
        0==m.bytes().fold(0,|a,b|a+[8,-1,1,-8][(b%5)as usize])
    }

04.04.2026

2075. Decode the Slanted Ciphertext medium substack youtube

04.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1318

Problem TLDR

Decode row-encoded string #medium

Intuition

Spaces at the end is not allowed for original string. That means we can simply decode with the end condition, then trim.

Approach

  • Kotlin: trimEnd

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 38ms
    fun decodeCiphertext(e: String, r: Int) = buildString {
        val skip = e.length/r + 1
        for (j in 0..<skip) for (i in 0..<r)
            if (j + i * skip < e.length) append(e[j + i * skip])
    }.trimEnd()
// 8ms
    pub fn decode_ciphertext(e: String, r: i32) -> String {
        let (s, mut ans) = (e.len() / r as usize + 1, String::new());
        for j in 0..s { for i in 0..r as usize {
            if j + i * s < e.len() {  ans.push(e.as_bytes()[j + i * s] as char)  }}}
        ans.trim_end().into()
    }

03.04.2026

3661. Maximum Walls Destroyed by Robots hard substack youtube

03.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1317

Problem TLDR

Max walls hit, each robot shoot left or right #hard #dp

Intuition

Didn’t solve.

    // 1       4           10
    // <  *  *   *  *  >
    // 1               7
    // 4-3..4+3
    // ranges intersection:
    //     *ab***
    //
    //   ***a*b**
    // count all walls in ranges
    //
    // 0 1 2 3 4 5 6 7 8 9 10
    //   * r *   * * * * * r
    //     w     w   w
    //
    // 27minute wrong answer 523/602 test case
    //
    // so the wrong was my understanding of the problem
    // each robot have to choose which way to shoot, not both
    //

Dp state: current robot and should it account for previous robot range.

Approach

  • sort
  • start with top-down dp

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 500ms
    fun maxWalls(r: IntArray, d: IntArray, w: IntArray): Int {
        val x = r.indices.sortedBy { r[it] }; w.sort(); val dp = HashMap<Int, Int>()
        val bs = { v: Int -> w.binarySearch(v).let { max(it.inv(), it) }}
        fun cnt(a: Int, b: Int) = if (a > b) 0 else bs(b+1)-bs(a)
        fun dfs(i: Int, clipLeft: Int): Int = if (i == r.size) 0 else dp.getOrPut(i*d.size*2+clipLeft) {
            val p = r[x[i]]; val rad = d[x[i]]
            val prev = if (i < 1) 0 else if (clipLeft>0) min(r[x[i-1]]+d[x[i-1]],p-1) else r[x[i-1]]
            val L = max(p-rad, prev + 1)
            val R = min(p+rad, if (i+1 < r.size) r[x[i+1]]-1 else Int.MAX_VALUE)
            max(cnt(L, p) + dfs(i+1, 0), cnt(p, R) + dfs(i+1, 1))
        }
        return dfs(0, 0)
    }

02.04.2026

3418. Maximum Amount of Money Robot Can Earn medium youtube

02.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1316

Problem TLDR

Max sum path, 2 skips allowed #medium #dp

Intuition

    // how to pick two optimal robbers?
    //
    // dp?
    //
    // can be greedy (min,max)? - no, we have to track all possibilites
    // and they will grow at 2^x rate
    // so should be dp
    //

The top-down DFS + memo is the simplest and robust choice without extra thinking required.

Approach

  • bottom-up: for each cell store 3 best values: (zero skips left, 1 skip left, 2 skips left)

Complexity

  • Time complexity: \(O(nm)\)

  • Space complexity: \(O(m)\)

Code

// 329ms
    fun maximumAmount(c: Array<IntArray>) = HashMap<Int, Int>().run {
        fun d(y: Int, x: Int, r: Int): Int = getOrPut(y*4000+x*4+r) {
            c.getOrNull(y)?.getOrNull(x)?.let { v ->
                fun n(k: Int) = max(d(y+1, x, k), d(y, x+1, k))
                if (v < 0 && r > 0) max(v + n(r), n(r-1)) else v + n(r)
            } ?: if (y == c.size && x == c[0].size - 1) 0 else -9999999
        }
        d(0, 0, 2)
    }
// 7ms
    pub fn maximum_amount(c: Vec<Vec<i32>>) -> i32 {
        let mut d = vec![[-9999999;3]; c[0].len()+1]; d[1] = [0;3];
        for r in c { for x in 1..d.len() {
            let (v, p) = (r[x-1], [0,1,2].map(|i| d[x-1][i].max(d[x][i])));
            d[x] = [p[0]+v, p[0].max(p[1]+v), p[1].max(p[2]+v)]
        }} d[d.len()-1][2]
    }

01.04.2026

2751. Robot Collisions hard youtube

01.04.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1315

Problem TLDR

Collide LR robots #hard #stack

Intuition

    // 1. sort by position
    // 2. simulation is too big, need a O(n) algorithm
    // 3. R R L R L
    //    2 2 1 1 3
    //    2 1 0
    //    2 1 0 0 2
    //    2 0 0 0 1
    //    1 0 0 0 0

Sort. Use stack.

Approach

  • we can re-use p array as a stack

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n)\)

Code

// 70ms
    fun survivedRobotsHealths(p: IntArray, h: IntArray, d: String) = run {
        var t = -1; for (i in p.indices.sortedBy { p[it] })
            if (d[i] == 'R') p[++t] = i else while (t >= 0 && h[i] > 0) when {
                h[p[t]] > h[i] -> { h[p[t]]--; h[i] = 0 } 
                h[p[t]] < h[i] -> { h[p[t--]] = 0; h[i]-- } 
                else -> { h[p[t--]] = 0; h[i] = 0 }
            }
        h.filter { it > 0 }
    }
// 11ms
    pub fn survived_robots_healths(p: Vec<i32>, mut h: Vec<i32>, d: String) -> Vec<i32> {
        let mut s = vec![]; 
        for i in (0..p.len()).sorted_by_key(|&i| p[i]) { 
            if d.as_bytes()[i] == b'R' { s.push(i) } else {
            while let Some(t) = s.pop() {
                if h[t] > h[i] { h[t] -= 1; h[i] = 0; s.push(t); break }
                if h[t] < h[i] { h[t] = 0; h[i] -= 1; continue }
                h[t] = 0; h[i] = 0; break
            }}}
        h.into_iter().filter(|&x| x > 0).collect()
    }

31.03.2026

3474. Lexicographically Smallest Generated String hard

youtube

31.03.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1314

Problem TLDR

String from pattern matches #hard #greedy #kmp

Intuition

Didn’t solve.

    // b
    // FFFF - aaaa
    // TFFF   baaa    F - always a
    //                T - always str2
    // 10^4 * 500 = 10^6 can be accepted
    // F - is not always 'a', if str2 can match

    // TFFF   aa
    // aa
    //  ab
    //    ab       the matching part is simple
    //             the non-matching: maybe increment it? aa-ab-ac-..-az-ba
    // maybe FFF..s create a pattern?
    //       aba
    // TFT
    // ababa

Greedy n*m solution:

  1. fill by T
  2. validate by T
  3. validate by F
  4. for matching F’s: increment rightmost letter

Approach

  • we can initialize with ‘a’
  • we can compare with ‘a’ to skip hold positions

Complexity

  • Time complexity: \(O(nm)\)

  • Space complexity: \(O(n+m)\)

Code

// 80ms
    fun generateString(a: String, b: String): String {
        val s = CharArray(a.length+b.length-1) { 'a' }
        for (i in a.indices) if (a[i] == 'T') for (j in b.indices) s[i+j] = b[j]
        for (i in a.indices) if (a[i] == 'F' && b.indices.all { s[i+it] == b[it]})  
            ++s[i+(b.indices.findLast { s[i+it] == 'a' } ?: return "")]
            else if (a[i] == 'T' && b.indices.any { s[i+it] != b[it]}) return ""
        return String(s)
    }
// 3ms
    pub fn generate_string(a: String, b: String) -> String {
        let (a, b, mut s) = (a.as_bytes(), b.as_bytes(), vec![b'a'; a.len() + b.len() - 1]);
        for i in 0..a.len() { if a[i] == b'T' { s[i..i+b.len()].copy_from_slice(b) } }
        for i in 0..a.len() { if a[i] == b'F' && &s[i..i+b.len()] == b {
                let Some(j) = s[i..i+b.len()].iter().rposition(|&c| c == b'a') else { return "".into() };
                s[i+j] += 1
            } else if a[i] == b'T' && &s[i..i+b.len()] != b { return "".into() }}
        String::from_utf8(s).unwrap()
    }

30.03.2026

2840. Check if Strings Can be Made Equal With Operations II medium

youtube

30.03.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1313

Problem TLDR

Strings equal at odd-even positions #medium #hash

Intuition

  1. compare frequencies
  2. compare hashes

Approach

  • as well as it is green its all fine! (for golf)
  • sum((c parity)^4) is the perfect hash

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 49ms
    fun checkStrings(a: String, b: String) = a.indices.sumOf { i ->
        (a[i]-' '+i%2*32.0).pow(3) - (b[i]-' '+i%2*32.0).pow(3)
    } == 0.0
// 0ms
    pub fn check_strings(a: String, b: String) -> bool {
        let h = |s: &[u8]| (0..s.len()).map(|i|
            1<<(s[i] as usize & 31 | i%2*7) ).sum::<usize>();
        h(a.as_bytes()) == h(b.as_bytes())
    }

29.03.2026

2839. Check if Strings Can be Made Equal With Operations I easy youtube

29.03.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1312

Problem TLDR

Match a and b at (0 2,1 3) positions #easy

Intuition

How short can the code be?

Approach

  • Kotlin: setOf, (0..1)
  • Rust: bitmask

Complexity

  • Time complexity: \(O(1)\)

  • Space complexity: \(O(1)\)

Code

// 24ms
    fun canBeEqual(a: String, b: String) = 
    (0..1).all { setOf(a[it],a[it+2]) == setOf(b[it],b[it+2]) }
// 0ms
    pub fn can_be_equal(a: String, b: String) -> bool {
        let f = |s: &[u8]| 1<<s[0] | 1<<s[2] | 1<<s[1]+16 | 1<<s[3]+16;
        f(a.as_bytes()) == f(b.as_bytes())
    }

28.03.2026

2573. Find the String with LCP hard

youtube

28.03.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1311

Problem TLDR

Build string from longest common prefixes matrix #hard

Intuition

  // [[4,0,2,0], 0..=4, [0..][2..]=2
    //  [0,3,0,1],
    //  [2,0,2,0],
    //  [0,1,0,1]]
    // [0][0] 4=aaaa,
    // [0][1] 0= b b
    // [0][2] 2=ab
    // [0][3] 0 a!=b
    // 6 minute:
    // i have no idea
    // diagonal 4 3 2 1 is always like this
    //                  can be ignored
    // is symmetric, look only top right corner
    //
    // [[4,0,2,0],
    //  [0,3,0,1],
    //  [2,0,2,0],
    //  [0,1,0,1]]
    //
    //  020
    // abcd
    //  *   a!=b
    //   *  ab==cd
    //    * a!=d
    //   01
    //  bcd
    //   *  b!=c
    //    * b==d
    //    0
    //   cd
    //    * c!=d
    //
    // how to use this?
    // can just increment from 'a'?
    // abcd
    // aaaa
    // a!=b: abaa
    // ab==cd: abab
    // a!=d: true
    // b!=c: true
    // b==d: true
    // c!=d: true
    // will this work? let's try
    //
    // 32 minute, corner case:
    // [[4,1,1,1],
    //  [1,3,1,1],
    //  [1,1,2,1],
    //  [1,1,1,1]]
    // 38 minute, test case "abcdefghijklmnopqrstuvwxyz{"

n^3: check matrix symmetry and diagonal properties, build string in (i,j, count) loop, validate separately n^2: build string filling the letters on vacant equal places, validate by dp property p[i][j]=s[i]==s[j] + p[i+1][j+1]

Approach

  • diagonal: 4 3 2 1 always
  • symmetry above vs below diagonal
  • letter not overflow ‘z’

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n)\)

Code

// 21ms
    fun findTheString(p: Array<IntArray>): String {
        val n = p.size-1; val s = CharArray(n+1); var c = 'a'-1
        for (i in 0..n) if (s[i] < 'a') {
            if (++c > 'z') return ""
            for (j in i..n) if (p[i][j] > 0) s[j] = c
        }
        return if ((0..n).all { i -> (0..n).all { j -> 
            val x = if (max(i,j) < n) p[i+1][j+1] else 0
            p[i][j] == if (s[i] == s[j]) 1 + x else 0 }}) String(s) else ""
    }
// 7ms
    pub fn find_the_string(p: Vec<Vec<i32>>) -> String {
        let n = p.len(); let (mut s, mut c) = (vec![0;n], 96); 
        for i in 0..n { if s[i] == 0 {
            c += 1; if c > 122 { return "".into() }
            for j in 0..n { if p[i][j] > 0 { s[j] = c }}
        }}
        ((0..n).all(|i| (0..n).all(|j| p[i][j]==(s[i]==s[j])as i32 * 
            (1 + if i.max(j) < n-1 { p[i+1][j+1] } else {0})
        ))).then(|| String::from_utf8(s).unwrap()).unwrap_or_default()
    }

27.03.2026

2946. Matrix Similarity After Cyclic Shifts easy substack youtube

27032026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1310

Problem TLDR

Shift rows k times left and right #easy #matrxi

Intuition

Brute force is accepted.

Approach

  • we can shift by k instead of by 1 k times
  • rows must be periodic or size == k, so left shift is the same as right shift
  • just check each row, don’t have to create a matrix

Complexity

  • Time complexity: \(O(nm)\)

  • Space complexity: \(O(1)\)

Code

// 15ms
    fun areSimilar(m: Array<IntArray>, k: Int) =
    m.all { r -> r.indices.all { r[it] == r[(it+k)%r.size] }}
// 0ms
    pub fn are_similar(m: Vec<Vec<i32>>, k: i32) -> bool {
        m.iter().all(|r| (0..r.len()).all(|i| r[i] == r[(i + k as usize) % r.len()]))
    }

26.03.2026

3548. Equal Sum Grid Partition II hard substack youtube

26032026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1309

Problem TLDR

Cut matrix in half sums, can remove one cell #hard

Intuition

Didn’t solve myself.

  1. rotate 4 times to simplify the logic
  2. lee intuition: store visited values in a hashset, calculate if suffix-prefix is in visited set
  3. another intuition: store visited prefixes in a hashmap to cut positions, calculate if (total-value)/2 in visited prefixes

Approach

  • reasoning about “not to disconnect” is the hardest part
  • corners are allowed to cut
  • single line grid is a corner case
  • we are making horizontal cuts
  • i==R && x%C==0 is the last row corners

Complexity

  • Time complexity: \(O(nm)\)

  • Space complexity: \(O(nm)\) can be O(max(n,m))

Code

// 286ms
    fun canPartitionGrid(g: Array<IntArray>): Boolean {
        val l=g.map{it.map{1L*it}}; val t=l.sumOf{it.sum()}
        val x=l[0].indices.map{c->l.map{it[c]}}
        fun F(m:List<List<Long>>):Boolean {
            val R=m.size-1; val C=m[0].size-1; var p=0L; val M=HashMap<Long,Int>()
            return (0..R).any { y ->
                m[y].withIndex().any{ (x,c) ->
                    val i=M[(t-c)/2]; p += c
                    (t-c)%2==0L && i!=null && (if(C<1)y==i+1||y==R else i<R-1||x%C==0)
                } || y<R && { M[p]=y; p*2 == t }()
            }
        }
        return listOf(l,l.reversed(),x,x.reversed()).any(::F)
    }
// 128ms
    pub fn can_partition_grid(g: Vec<Vec<i32>>) -> bool {
        let l: Vec<Vec<_>> = g.iter().map(|r| r.iter().map(|&v| v as i64).collect()).collect();
        let t: i64 = l.iter().flatten().sum();
        let x: Vec<Vec<_>> = (0..l[0].len()).map(|c| l.iter().map(|r| r[c]).collect()).collect();
        let (mut lr, mut xr) = (l.clone(), x.clone()); lr.reverse(); xr.reverse();
        let f = |m: &Vec<Vec<i64>>| {
            let (r, c, mut p, mut map) = (m.len() - 1, m[0].len() - 1, 0, HashMap::new());
            (0..=r).any(|y| {
                m[y].iter().enumerate().any(|(x, &v)| {
                    let i = map.get(&((t - v) / 2)); p += v;
                    (t - v) % 2 == 0 && i.map_or(false, |&i| if c < 1 { y == i + 1 || y == r } else { i < r - 1 || x % c == 0 })
                }) || y < r && { map.insert(p, y); p * 2 == t }
            })
        };
        [&l, &lr, &x, &xr].into_iter().any(|m| f(m))
    }

25.03.2026

3546. Equal Sum Grid Partition I medium blog post substack youtube

25032026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1308

Problem TLDR

Split matrix to equal sums #medium

Intuition

O(1) memory solution: calculate total, then separately check each row/column splits p+p==t, sum prefixes in a single variable

Single pass solution: use a hashset to keep track of all visited prefixes, at the end lookup for total/2

Approach

  • careful with int overflow
  • Kotlin: any, sumOf
  • Rust: flatten, any, fold

Complexity

  • Time complexity: \(O(nm)\)

  • Space complexity: \(O(1)\)

Code

// 24ms
    fun canPartitionGrid(g: Array<IntArray>) = 
    g.sumOf { it.sumOf { 1L * it }}.let { t ->
        var h = 0L; var v = 0L
        g.any { h += it.sumOf { 1L * it }; h == t - h } || 
        g[0].indices.any { x ->  v += g.sumOf { 1L * it[x] }; v == t - v }
    }
// 2ms
    pub fn can_partition_grid(g: Vec<Vec<i32>>) -> bool {
        let (mut h, mut v, t) = (0, 0, g.iter().flatten().fold(0, |s,&x| s + x as i64));
        g.iter().any(|r| { h += r.iter().sum::<i32>() as i64; h+h==t}) ||
        (0..g[0].len()).any(|c| { v += g.iter().fold(0,|s,r|s+r[c] as i64); v+v==t})
    }

24.03.2026

2906. Construct Product Matrix medium youtube

24.03.2026.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1307

Problem TLDR

Product of other cells in a matrix #medium #prefix

Intuition

    // p = a*b*c*d
    // a' = (p/a)%m
    // are we allowed to do 1/a with modulo?
    //
    // corner case: zero if we do %M locally
    //
    // this is some math theory
    //
    // 12345 is not a prime
    // if there is a group of numbers that are multiplies of 12345
    // then all elements are zero except this group (if no duplicates)
    //
    // 12  minute hint: solve without '/', hint2: suffix-prefix
    //

Division is not allowed: total product can be 0, and modulo division should be mod inverse, not allowed for 12345

Approach

  • flatten the matrix to make code shorter

Complexity

  • Time complexity: \(O(nm)\)

  • Space complexity: \(O(nm)\)

Code

```kotlin [-Kotlin 90ms] // 90ms fun constructProductMatrix(g: Array) = g.flatMap{it.toList()}.run { val p = scan(1L) { r, t -> r * t % 12345 } val s = reversed().scan(1L) { r, t -> r * t % 12345 }.reversed() indices.map { p[it] * s[it+1] % 12345 }.chunked(g[0].size) }

```rust [-Rust 20ms]
// 20ms
    pub fn construct_product_matrix(g: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
        let f = g.concat();
        let o = |a: &mut i64, &x: &i32| { let r = *a; *a = *a * x as i64% 12345; Some(r) };
        f.iter().scan(1, o).zip(f.iter().rev().scan(1, o).collect_vec().into_iter().rev())
        .map(|(p,s)| (p * s % 12345) as i32).chunks(g[0].len())
        .into_iter().map(Iterator::collect).collect()
    }

23.03.2026

1594. Maximum Non Negative Product in a Matrix medium substack youtube

05.10.2025.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1306

Problem TLDR

Max product path right-down #medium #dp

Intuition

    // 14minute wrong answer 138 / 159 testcases Output 38431730 Expected 459630706
    // 15 minute tle 152 / 159 testcases passed
    // so the full search is not allowed for 15x15 grid
    // 20 minute, use hint: dp, high+low works

The brute-force gives TLE. Local optimum max is the wrong intuition. Preserve two results for each cell: max and min.

Approach

  • only 1D array is needed to track the last row

Complexity

  • Time complexity: \(O(nm)\)

  • Space complexity: \(O(m)\)

Code

// 21ms
    fun maxProductPath(g: Array<IntArray>) =
        List(2) { LongArray(g[0].size) }.let { (h, l) -> 
            for (y in g.indices) for (x in g[0].indices) {
                if (x + y == 0) { h[x] = 1L*g[y][x]; l[x] = h[x]; continue }
                val i = if (y > 0) x else x-1; val j = if (x > 0) x-1 else x
                val a = listOf(h[i], h[j], l[i], l[j])
                h[x] = a.maxOf { it * g[y][x] }; l[x] = a.minOf { it * g[y][x] }
            }
            h.last().takeIf { it >= 0 }?.let { it%1000000007 } ?: -1L
        }
// 0ms
    pub fn max_product_path(g: Vec<Vec<i32>>) -> i32 {
        let mut h = vec![0i64; g[0].len()]; let mut l = h.clone();
        for y in 0..g.len() { for x in 0..g[0].len() {
            let (v, i, j) = (g[y][x] as _, x-(y==0) as usize, x-(x>0) as usize);
            if x+y<1 { h[x]=v; l[x]=v } else { 
            let mut a = [h[i]*v, l[i]*v, h[j]*v, l[j]*v]; a.sort(); h[x] = a[3]; l[x] = a[0] }
        }}
        match *h.last().unwrap() { n if n < 0 => -1, n => (n % 1_000_000_007) as _ }
    }

22.03.2026

1886. Determine Whether Matrix Can Be Obtained By Rotation easy substack youtube

33991ffb-8ced-4270-89c6-2c888059ee38 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1305

Problem TLDR

Rotate matrix #easy

Intuition

Rotate 4 times and check deep equals.

Approach

  • or just check 4 counters of equal values, should be n^2

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n^2)\)

Code

// 14ms
    fun findRotation(m: Array<IntArray>, t: Array<IntArray>) =
    generateSequence(m) { m ->
        Array(m.size){ y -> IntArray(m.size) { x -> m[m.size-1-x][y] }}
    }.take(4).any(t::contentDeepEquals)
// 0ms
    pub fn find_rotation(m: Vec<Vec<i32>>, t: Vec<Vec<i32>>) -> bool {
        let n = m.len(); iterate(m, |c| (0..n).map(|i| (0..n).map(|j|
        c[n-1-j][i]).collect()).collect()).take(4).any(|c| c == t)
    }

21.03.2026

3643. Flip Square Submatrix Vertically medium blog post substack youtube

c7ed576b-3e7e-4a96-bdcf-e4e9c381c632 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1304

Problem TLDR

Reverse submatrix k by k #easy

Intuition

Carefully do this in-place.

Approach

  • name variables properly
  • Rust allows to swap entire slices

Complexity

  • Time complexity: \(O(k*k)\)

  • Space complexity: \(O(1)\)

Code

// 1ms
    fun reverseSubmatrix(g: Array<IntArray>, r: Int, c: Int, k: Int)=g.also{
        for (y in 0..<k/2) for (x in c..<c+k)
            g[y+r][x] = g[r+k-1-y][x].also { g[r+k-1-y][x] = g[y+r][x] }
    }
// 0ms
    pub fn reverse_submatrix(mut g: Vec<Vec<i32>>, r: i32, c: i32, k: i32) -> Vec<Vec<i32>> {
        let (r, c, k) = (r as usize, c as usize, k as usize);
        let (top, btm) = g[r..r+k].split_at_mut(k/2);
        for (t,b) in top.iter_mut().zip(btm.iter_mut().rev()) {
            t[c..c+k].swap_with_slice(&mut b[c..c+k])
        } g
    }

20.03.2026

3567. Minimum Absolute Difference in Sliding Submatrix medium blog post substack youtube

bc90b16a-87bd-424d-aef7-2c539e5acf59 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1303

Problem TLDR

Mid diffs in k*k submatrices #medium #matrix

Intuition

Just brute-force, the size is small, 30

Approach

  • Kotlin: toSortedSet(), windowed
  • Rust: itertools allows to use sorted in a single expression, tuple_windows

Complexity

  • Time complexity: \(O(nmk^2)\)

  • Space complexity: \(O(nmk^2)\)

Code

// 86ms
    fun minAbsDiff(g: Array<IntArray>, k: Int)= 
        List(g.size-k+1) { y -> List(g[0].size-k+1) { x ->
            List(k*k){ g[y+it/k][x+it%k] }.toSortedSet()
            .windowed(2) {it[1]-it[0]}.minOrNull() ?: 0
        }}
// 2ms
    pub fn min_abs_diff(g: Vec<Vec<i32>>, k: i32) -> Vec<Vec<i32>> {
        let k = k as usize; (0..=g.len()-k).map(|y|  (0..=g[0].len()-k).map(|x| 
            (0..k*k).map(|i| g[y+i/k][x+i%k]).sorted().dedup().tuple_windows()
            .map(|(a,b)|b-a).min().unwrap_or(0)
        ).collect()).collect()
    }

19.03.2026

3212. Count Submatrices With Equal Frequency of X and Y medium blog post substack youtube

26191ddf-56db-4114-bec4-248112584d32 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1302

Problem TLDR

Count prefix freq X == freq Y #medium #matrix

Intuition

Keep two prefixes: for the X and for the Y. Freq = freq_left + freq_top

Approach

  • we can just look at balance x++ y–
  • we can store just the last row
  • to keep track ‘at least one’ rule, use a single bit per column

Complexity

  • Time complexity: \(O(nm)\)

  • Space complexity: \(O(m)\)

Code

// 18ms
    fun numberOfSubmatrices(g: Array<CharArray>) = 
        IntArray(g[0].size).let { X ->
            g.sumOf { r ->
                var x = 0; var s = 0; var j = 0
                r.count { c -> 
                    if (c > '.') { s = 1; x += 4*(c - 'X')-2 }
                    X[j] = X[j] + x or s; X[j++] == 1
                }
            }
        }
// 18ms
    pub fn number_of_submatrices(g: Vec<Vec<char>>) -> i32 {
        let mut v = vec![0; g[0].len()];
        g.iter().map(|r| {
            let (mut b, mut s) = (0, 0);
            r.iter().zip(&mut v).map(|(&c, x)| {
                if c > '.' { s = 1; b += (c as i32 - 88)*4-2 }
                *x = *x + b|s; (*x == 1) as i32
            }).sum::<i32>()
        }).sum()
    }

18.03.2026

3070. Count Submatrices with Top-Left Element and Sum Less Than k medium blog post substack youtube

c5dfe7df-4595-411f-8b72-d0b56c7e85a3 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1301

Problem TLDR

Count prefix sums less than K #medium #matrix

Intuition

Just compute and re-use prefix sum.

Approach

  • count in-place
  • use row-sum extra variable
  • rust itertools have product!
  • optimization: after sum bigger than k consider this as the limit for x

Complexity

  • Time complexity: \(O(mn)\)

  • Space complexity: \(O(1)\)

Code

// 39ms
    fun countSubmatrices(g: Array<IntArray>, k: Int) = 
        g.indices.sumOf { y -> g[0].indices.count { x ->
            g[y][x] += (if (y > 0) g[y-1][x] else 0) + 
                        (if (x > 0) g[y][x-1] else 0) - 
                        (if (x*y > 0) g[y-1][x-1] else 0)
            g[y][x] <= k
        }}
// 0ms
    pub fn count_submatrices(mut g: Vec<Vec<i32>>, k: i32) -> i32 {
        (0..g.len()).map(|y| (0..g[0].len()).fold((0,0), |(mut s, c), x| {
            s += g[y][x]; g[y][x] = s + (y>0) as i32 * g[y.max(1)-1][x];
            (s, c + (g[y][x] <= k) as i32)
        }).1).sum()
    }

17.03.2026

1727. Largest Submatrix With Rearrangements medium blog post substack youtube

13158f9f-a659-4fd4-bfdb-725ce8938b90 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1300

Problem TLDR

Max area of binary matrix, swap columns #medium

Intuition

    // columns! 
    //         6
    // ***___***___
    // __*****_____ 5
    // ______***___
    // ______*_____
    // ______*_____
    // ______*_____
    // ______*_____
    //       7
    //
    // 001
    // 112 = 1+1+1=3
    // 203 = 2+2=4
    //
    // 22223345  max(2*8,3*4, 4*2, 5)
  • subproblem: only the last row with histogram of the previous rows
  • sort the histogram, O(n) scan max(h(x)*(width-x))

Approach

  • don’t have to build histogram for the first row
  • r[x] *= prev + 1 trick

Complexity

  • Time complexity: \(O(nmlog(m))\)

  • Space complexity: \(O(m)\)

Code

// 110ms
    fun largestSubmatrix(m: Array<IntArray>) =
        m.withIndex().maxOf { (y,r) ->
            if (y>0) for (x in r.indices) r[x] *= m[y-1][x] + 1
            r.sorted().withIndex().maxOf { (x,v) -> (r.size-x)*v }
        }
// 4ms
    pub fn largest_submatrix(mut m: Vec<Vec<i32>>) -> i32 {
        (0..m.len()).map(|y| {
            if y > 0 { for x in 0..m[0].len() { m[y][x] *= m[y-1][x]+1}}
            let mut r = m[y].clone(); r.sort();
            (0..r.len()).map(|x|(r.len()-x)as i32*r[x]).max().unwrap()
        }).max().unwrap()
    }

16.03.2026

1878. Get Biggest Three Rhombus Sums in a Grid medium blog post substack youtube

6e2cf9bd-9a75-4740-9c8a-9e4299b41f05 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1299

Problem TLDR

Top 3 rhombus sums #medium

Intuition

Brute-force.

Approach

  • the distance from center to top is the exact number of steps from top to right

Complexity

  • Time complexity: \(O((mn)^2)\)

  • Space complexity: \(O((mn)^2)\), can be O(1)

Code

// 245ms
    fun getBiggestThree(g: Array<IntArray>) = buildSet {
        for (y in g.indices)  for (x in g[0].indices) {
            add(g[y][x])
            for (d in 1..minOf(x, g[0].size-1-x, y, g.size-1-y)) {
                var c = 0; var i = y-d; var j = x
                for ((dy, dx) in listOf(1 to 1, 1 to -1, -1 to -1, -1 to 1))
                    repeat(d) { c += g[i][j]; i += dy; j += dx }
                add(c)
            }
        }
    }.sortedDescending().take(3)
// 13ms
    pub fn get_biggest_three(g: Vec<Vec<i32>>) -> Vec<i32> {
        let (mut s, m, n) = (vec![], g.len(), g[0].len());
        for y in 0..m { for x in 0..n { s.push(g[y][x]);
            for d in 1..=x.min(n-1-x).min(y).min(m-1-y) {
                let (mut c, mut i, mut j) = (0, y-d, x);
                for (dx,dy) in [(1,1),(1,!0),(!0,!0),(!0,1)] { for _ in 0..d 
                    { c+=g[i][j]; i=i.wrapping_add(dx); j=j.wrapping_add(dy) }
                }
                s.push(c)
            }
        }} s.sort_unstable_by_key(|&x|-x); s.dedup(); s.truncate(3); s
    }

15.03.2026

1622. Fancy Sequence hard blog post substack youtube

f6b9d004-5aeb-4ecd-bea2-5f1c04f1d060 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1298

Problem TLDR

Design: add number, mulriply all, add all #design

Intuition

// ((x+a+b+c)*d*c+e+f)*g
//   x+abc
//  x*dc*g + abc*dc*g + ef*g
//  x*dcg + abc*dc*g + ef*g
// the problem is: not all values are here
// when appening: freeze current mul & add for this value
//
//  x*dc + abc*dc + e, then add y
//  x*dcg + abc*dc*g + ef*g + h
//  y*g + f*g + h
//
// mul = dcg
// fm = dc        y*g = y * mul / fm
//
// add = abc*dc*g + e*g + f*g + h = g(abc*dc+e)+f*g+h
// fa = abc*dc + e
// g = mul/fm
// f*g+h = add - (mul/fm)*fa
// 
// 23 minute wrong answer on some case 53/107
// 19239 vs 50
// too big (was Int overflow)
// another 65/107, value negative probably overflow
//                 now its positive, still wrong, illegal modulo?
//                 are we allowed to divide mul/fm?
// 38 minute, some overflow (or modulo) issue
// hint: modular inverse? oh-no
//

Arithmetics: x * mul / fm + add - (mul/fm)*fa, fm - frozen mul, fa - frozen add.

Approach

  • store three numbers: value, fronzen add, fronzen mul
  • or store one number: reversed value (v-add)/m
  • division modulo is not allowed, we have to use inverse modulo: x^-1%m = -M/x * (M%x)^-1 (recursive until x > 1)

Complexity

  • Time complexity: \(O(m)\)

  • Space complexity: \(O(n)\)

Code

// 80ms
class Fancy: ArrayList<Long>() {
    var x = 1L; var s = 0L; val M = 1_000_000_007L
    fun i(v: Long): Long = if (v < 2) v else M - M/v * i(M%v)%M
    fun append(v: Int) = add((v-s+M) * i(x) % M)
    fun addAll(v: Int) { s += v }
    fun multAll(v: Int) { x = x * v % M; s = s * v % M }
    fun getIndex(i: Int) = if (i < size) (get(i)*x %M + s)%M else -1
}
// 56ms
const M:i64 = 1000000007; struct Fancy(Vec<i64>, i64, i64);
fn i(x: i64) -> i64 { if x < 2 { x } else { M - M/x * i(M%x) % M }}
impl Fancy {
    fn new() -> Self { Self(vec![], 1, 0) }
    fn append(&mut self, v: i32) { self.0.push((v as i64-self.2+M)*i(self.1)%M) }
    fn add_all(&mut self, v: i32) { self.2 += v as i64 }
    fn mult_all(&mut self, v: i32) { self.1 = self.1*v as i64%M; self.2 = self.2*v as i64%M }
    fn get_index(&self, i: i32) -> i32 { self.0.get(i as usize).map_or(-1, |v| (v*self.1+self.2)%M)as _}
}

14.03.2026

1415. The k-th Lexicographical String of All Happy Strings of Length n medium blog post substack youtube

d4ce69c3-5e30-4fd4-9342-a9f803a9732a (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1297

Problem TLDR

K-th generated abc non-repeating string #medium #dfs

Intuition

    // the problem is small, just generate all, sort
    // abab
    // abac
    // abca
    // abcb
    // acab
    // acac
    // baba
    // 2^10

The simple solution: just generate all strings in DFS, sort.

Approach

  • the DFS already generates in a sorted order, no need to sort
  • no need to keep strings, just count until k
  • the math intuition: each char generates subtree with known elements count, initial a: 2^(n-1), b: 2^(n-1), c: 2^(n-1)
  • index is “abc”[k/count] at first, then {“ab”, “bc”, “ac”}[k/count], k %= count, count /= 2

Complexity

  • Time complexity: \(O(2^n)\), or O(n)

  • Space complexity: \(O(2^n)\), or O(1)

Code

// 11ms
    fun getHappyString(n: Int, k: Int, s: String = "abc", b: Int = 1 shl n-1): String =
        if (n==0 || (k-1)/b > s.lastIndex) "" else 
        s[(k-1)/b] + getHappyString(n-1, (k-1)%b+1, "abc".replace(""+s[(k-1)/b],""))
// 12ms
    pub fn get_happy_string(n: i32, k: i32) -> String {
        (0..n).map(|_| *b"abc").multi_cartesian_product()
        .filter(|s| s.windows(2).all(|w| w[0] != w[1]))
        .nth(k as usize-1).and_then(|v| String::from_utf8(v).ok()).unwrap_or_default()
    }

13.03.2026

3296. Minimum Number of Seconds to Make Mountain Height Zero medium blog post substack youtube

ff059a99-0832-43e9-a470-b09da8c22eb4 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1296

Problem TLDR

Min steps to work a mountain with arithmetic-sum-workers #medium #bs

Intuition

    // the description is brainrot
    // 1+2+3+4+5 + (n-2)+(n-1)+n = s
    // 

Binary search: freeze the number of parallel steps, test the amount of total work done. Inner binary search to answer what number of steps is the maximum allowed to be less than frozen steps.

Approach

  • S = x*(x+1)/2
  • there is a math solution possible for inner bs
  • live math in rust is slower than precomputed array in kotlin

Complexity

  • Time complexity: \(O(log(nlog(w)))\)

  • Space complexity: \(O(w)\) can be O(1)

Code

// 117ms
    fun minNumberOfSeconds(mh: Int, wt: IntArray): Long {
        val a = LongArray(mh+1) { 1L * it * (it+1)/2 }
        var lo = 0L; var hi = 1L shl 62
        while (lo <= hi) {
            val m = lo + (hi - lo) / 2
            if (mh > wt.sumOf { t -> 
                var i = a.binarySearch(m/t); if (i < 0) i = -i-2; i
            }) lo = m + 1 else hi = m - 1
        }
        return lo
    }
// 144ms
    pub fn min_number_of_seconds(mh: i32, wt: Vec<i32>) -> i64 {
        let (mut lo, mut hi) = (0i64, 1i64<<62);
        while lo <= hi {
            let m = lo + (hi - lo) / 2; let mut s = 0i64;
            for &t in &wt { 
                let (mut l, mut h) = (0, mh as i64);
                while l <= h {
                    let i = (l + h) / 2;
                    if i*(i+1)/2 * t as i64 <= m { l = i + 1 } else { h = i - 1 }
                }
                s += h
            }
            if s < mh as i64 { lo = m + 1 } else { hi = m - 1 }
        } lo
    }

12.03.2026

3600. Maximize Spanning Tree Stability with Upgrades hard blog post substack youtube

b7368096-8e84-4e37-ba9f-0e28359d9712 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1295

Problem TLDR

Max of min values in span tree of graph, 2*s at most k #hard #graph

Intuition

    // i will spend no more than 30 minutes to this until i use hints
    // the must-edges should be included
    // check for cycles
    // upgrade makes sense to always do *2 (k times)
    // the minimum is min(must, notmust_k*2)
    // the question is to remove min-value edges
    // the new edges can only worsen the situation of min(must)
    // so take as few as possible
    // now the question: how to build a spanning tree with priority?
    //
    // union-find?
    //
    // now how to take all necessary edges from others to make span tree?
    // we must visit all nodes
    // take largest s first; can be not optimal
    // necessary node can be not largest
    // how to spend k optimally?
    // and to not form cycles
    //
    // 20 minute
    //
    // go from unvisited nodes?
    //
    // a-b c  (ac=1, bc=2) k=1 (ab is must, min=0)
    //
    // honestly not sure 
    // both ac and bc are promising, both can make a cycle
    //
    // ok google how to build a span tree lol
    // 27 minute
    // let's just blindly sort by value and take largest
    // wrong answer, didn't work 30 minute, use hints
    // the missing part: binary search
    //
    // 1:03 another edge case
    //

Sort by bigger s first. Binary Search: freeze the allowed s lvl, try to greedily add everything Heap: just greedily add everything, then 2*s of k smallest added

Approach

  • heap is not needed, we have a sorted order
  • Union-Find to check cycles/added
  • we can do a single pass if we sort by m first

Complexity

  • Time complexity: \(O(n+eloge)\)

  • Space complexity: \(O(e+n)\)

Code

// 238ms
    fun maxStability(n: Int, e: Array<IntArray>, k: Int): Int {
        e.sortWith(compareBy({-it[3]}, {-it[2]}))
        val u = IntArray(n) { it }; val g = ArrayList<Int>(); g += Int.MAX_VALUE
        fun f(x: Int): Int = if (u[x]==x)x else f(u[x]).also {u[x]=it}
        for ((a,b,s,m) in e) if (f(a)!=f(b)) u[f(a)]=f(b).also{if(m>0) g[0]=min(g[0],s) else g+=s} else if(m>0) return -1
        return if ((0..<n).all {f(it) == f(0)}) minOf(g[0], g[max(0,g.size-k-1)], g.last()*2) else -1
    }
// 33ms
    pub fn max_stability(n: i32, mut e: Vec<Vec<i32>>, k: i32) -> i32 {
        e.sort_unstable_by_key(|v| (-v[3], -v[2]));
        let mut u: Vec<_> = (0..n as usize).collect(); let (mut c, mut g) = (n, vec![i32::MAX]);
        fn f(u: &mut [usize], mut x: usize) -> usize { if x == u[x] { x } else { let a = f(u, u[x]); u[x] = a; a }}
        for v in e {
            let (a, b, s, m) = (f(&mut u, v[0] as _), f(&mut u, v[1] as _), v[2], v[3]);
            if a != b { u[a] = b; c -= 1; if m > 0 { g[0] = g[0].min(s) } else { g.push(s) } } 
            else if m > 0 { return -1 }
        }
        if c > 1 { -1 } else { g[0].min(g[g.len().saturating_sub((k + 1) as usize)]).min(g[g.len() - 1]*2) }
    }

11.03.2026

1009. Complement of Base 10 Integer easy blog post substack youtube

f0a013aa-d52d-4f76-9773-52e129098a53 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1294

Problem TLDR

Invert binary #easy

Intuition

Use a bitmask of the next power of two - 1.

Approach

  • Kotlin: takeHighestOneBit, countLeadingZeroBits
  • Rust: leasing_zeros, next_power_of_two, ilog2
  • 0 case trick: use 1 to check bits count at least 1

Complexity

  • Time complexity: \(O(1)\)

  • Space complexity: \(O(1)\)

Code

// 0ms
    fun bitwiseComplement(n: Int) = 
    (n or 1).takeHighestOneBit()*2 - n - 1
// 0ms
    pub fn bitwise_complement(n: i32) -> i32 {
        n^(2<<(n|1).ilog2())-1
    }

10.03.2026

3130. Find All Possible Stable Binary Arrays II hard blog post substack youtube

86ab161b-a052-42a4-b55c-1517fb33ef65 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1293

Problem TLDR

01-array to make with z zeros, o ones, l repeats #hard #dp

Intuition

    // so this is yesterday problem, but this time should be solved in O(n^2) instead of n^3
    // this is a n^3 solution: take every possible count 1..min(z,l)
    //
    // how to speed up?
    // dp[z][o]=dp[o][z-1]+dp[o][z-2]+...+dp[o][z-min(z,l)-1]+dp[o][z-min(z,l)]
    // dp[z-1][o]=         dp[o][z-2]+dp[o][z-3]+...+dp[o][z-1-min(z-1,l)-1]+dp[o][z-1 - min(z-1,l)]
    //
    // dp[z][o] = dp[z-1][o]+dp[o][z-1]+(?? dp[o][z-min(z,l)] ) // how to deal with tail?
    //
    //    z=3,l=2  dp[3][o]=dp[o][3-1]+dp[o][3-2]
    //             dp[3-1][o]=dp[o][3-1-1]+dp[o][3-1-2]
    //             dp[3][o]=dp[3-1][o] + dp[o][3-1] - dp[o][3-1-2]
    //
    //    z=3,l=4  dp[3][o]=dp[o][3-1]+dp[o][3-2]+dp[o][3-3]
    //             dp[3-1][o]=dp[o][3-1-1]+dp[o][3-1-2]
    //             dp[3][o]=dp[3-1][o] + dp[o][3-1]
    //
    //    z=5,l=3  dp[5][o]=dp[o][5-1]+dp[o][5-2]+dp[o][5-3]=dp[o][4]+dp[o][3]+dp[o][2]
    //             dp[4][o]=dp[o][4-1]+dp[o][4-2]+dp[o][4-3]=dp[o][3]+dp[o][2]+dp[o][1]
    //             dp[5][o]=dp[4][o]+dp[o][4]-dp[o][1]
    //
    
    // so if we rewrite to bottom up we can save one dimention of iteration
    // 
  • consider batches of repeating current digit
  • alterate by swapping arguments (curr, other) = (other, curr-take)
  • can take at most min(curr, limit)
  • mathematically subtract dp[curr][other]-dp[curr-1][other] to see that for loop can be O(1)

Approach

  • the combinatorics solution consists of: stars and bars (s-1 b-1), inclusion-exclusion principle f(curr)-f(excl), f(excl)-f(excl-excl)…, Fermat little theorem a^-1=a^(m-1) %m, modulo exponentiation a^y = a^2(y/2)+a^2(y%2)

Complexity

  • Time complexity: \(O(zo)\)

  • Space complexity: \(O(zo)\)

Code

// 366ms
    fun numberOfStableArrays(z: Int, o: Int, l: Int): Int {
        val dp = HashMap<Int, Long>(); val M = 1000000007
        fun dfs(z: Int, o: Int): Long = if (z<=0||o<0) 0L 
        else if (o==0) {if (z <=l)1L else 0L} else dp.getOrPut(z*1000+o){
            (dfs(z-1,o)+dfs(o,z-1)-dfs(o,z-min(z,l)-1)+M)%M
        }
        return ((dfs(z, o) + dfs(o, z) + M) % M).toInt()
    }
// 39ms
    pub fn number_of_stable_arrays(z: i32, o: i32, l: i32) -> i32 {
        let (m,z,o,l) = (1000000007, z as usize, o as usize, l as usize);
        let (mut f, mut v) = ([1;2005], [1;2005]);
        for i in 1..2005 { f[i] = f[i-1] * i as i64 % m }
        let (mut b, mut e) = (f[2004], m-2);
        while e > 0 { if e & 1 == 1 { v[2004] = v[2004]*b%m} b=b*b%m; e/=2 }
        for i in (1..2005).rev() { v[i-1] = v[i]*i as i64 % m }
        let c = |n: usize, r: usize| if r > n {0} else {f[n]*v[r]%m*v[n-r]%m};
        let w = |n: usize, b: usize| if b == 0 {(n==0)as i64} else {
            (0..=b).take_while(|&i| n >= i*l + b).fold(0, |a,i|
                (a+[1,m-1][i&1]*c(b,i)%m*c(n-i*l-1,b-1)%m)%m )};
        (1..=z).fold(0, |a,k|
            (a + w(z,k)*(w(o,k)*2 + w(o,k-1) + w(o,k+1))%m)%m ) as _
    }

09.03.2026

3129. Find All Possible Stable Binary Arrays I medium blog post substack youtube

8a864214-ee89-4c40-85b3-f89e71cb222c (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1292

Problem TLDR

Count 01-arrays with z zeros, o ones, at most l repeat #medium

Intuition

Didn’t solve.

    // length = z+o = 400
    // consequent repeats at most l
    // this can be DFS + memo n^3
    // my solution is n^4 TLE
    // the symmetry trick didn't help 
    // lets look hints
    // MLE

The working intuition: build arrays by alterating blocks.

Approach

  • inside DFS: try at most min(l, current) to take, flip the arguments

Complexity

  • Time complexity: \(O(zol)\)

  • Space complexity: \(O(zo)\)

Code

// 218ms
    fun numberOfStableArrays(z: Int, o: Int, l: Int): Int {
        val dp = HashMap<Int, Int>()
        fun d(z: Int, o: Int): Int = 
        if (z == 0) 0 else if (o == 0) {if (z <= l) 1 else 0}
        else dp.getOrPut(z*400+o) {
            (1..min(z,l)).fold(0){ r, nz -> (r+d(o,z-nz))%1000000007}
        }
        return (d(z, o) + d(o, z))%1000000007
    }

08.03.2026

1980. Find Unique Binary String medium blog post substack youtube

d9203387-451a-452f-8f7f-0e3ae568d179 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1291

Problem TLDR

Uniq bits not in a set #medium

Intuition

Brute-force, only 16 elements. Max count is 2^16. Max count where first new appears is n+1. Cantour trick: build a new uniq by flipping exactly one uniq bit position in all bits. It would be uniq because it differs at least by one bit with each in a set.

Approach

  • xor trick “1” converts to “0”, because they even-odd

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 12ms
    fun findDifferentBinaryString(n: Array<String>) =
    n.mapIndexed{i,s -> 1-(s[i]-'0')}.joinToString("")
    //n.indices.joinToString(""){""+"10"[n[it][it]-'0']}
    //(0..16).map{it.toString(2).padStart(n.size,'0')}.find{it !in n}
    //(0..16).first{it !in n.map{it.toInt(2)}}.toString(2).padStart(n.size,'0')
// 0ms
    pub fn find_different_binary_string(n: Vec<String>) -> String {
       (0..n.len()).map(|i| (n[i].as_bytes()[i]^1)as char).join("")
    }

07.03.2026

1888. Minimum Number of Flips to Make the Binary String Alternating medium blog post substack youtube

48a41980-c2b0-494d-80ae-7e0bba337b75 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1290

Problem TLDR

Min flips to make 01 alterating string #medium #prefix_sum #sliding_window

Intuition

    // 111000
    //  0  1
    //
    // 110001
    // 100011
    //   1
    //      0
    //
    // whats the point of shifting?
    //
    // 110
    // 101 just shifted
    //
    // soo we can start from first 10 
    //
    // 011
    // 110
    // 101
    //
    // 11010
    //
    // 10110
    // 01011
    //
    // or double 00
    // 001 shift 010
    //
    // just split 11 idk if it works
    //
    // can be many splits
    // is this dp?
    // 0011
    //
    // 101|101
    //
    // not optimal
    // 10001100101000000|10001100101000000
    //  1010101010101010|1
    //   101010101010101|01
    //    10101010101010|101
    //     1010101010101|0101
    // ...
    //                10|101010101010101
    //                 1|0101010101010101
    // they are all repeating
    //
    // 011|011
    // 010|
    //  01|0
    //   0|10
    // 101|
    //  10|1
    //   1|01 match
    // a  | b
    // miss before + (len-miss) after

Prefix sum intuition:

  • split at every every index, count bitflips in prefix+suffix(inverted)
  • if string length is even return early

Sliding window intuition:

  • slide concatenation
  • if string length is even slide once
  • to move the left pointer flip the bit

Approach

  • (c+i)%2 gives a match increment

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\), or O(n) for prefix sum

Code

// 36ms
    fun minFlips(s: String): Int {
        var c = 0
        return (0..<s.length+s.length%2*s.length).minOf { i ->
            c += (s[i%s.length]-'0' + i)%2
            if (i > s.lastIndex) c -= 1-(s[i-s.length]-'0'+i)%2
            if (i < s.lastIndex) s.length else min(c, s.length-c)
        }
    }
// 2ms
    pub fn min_flips(s: String) -> i32 {
        let (n, mut a) = (s.len(), vec![0; s.len()+1]);
        for (i,b) in s.bytes().enumerate() { 
            a[i+1]=a[i]+((b+i as u8)&1)as usize }
        if n%2==0 { return a[n].min(n-a[n]) as _ }
        (0..=n).map(|i| {
            let t = a[n] + i - 2 * a[i]; t.min(n - t)
        }).min().unwrap_or(0) as _
    }

06.03.2026

1784. Check if Binary String Has at Most One Segment of Ones easy blog post substack youtube

ccfe0859-5820-4dff-8521-1e41fe93539e (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1289

Problem TLDR

1+0* pattern #easy

Intuition

  1. Regex ^1+0*$

Approach

  • or just check of 01

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 7ms
    fun checkOnesSegment(s: String) = 
    "01" !in s
// 0ms
    pub fn check_ones_segment(s: String) -> bool {
        !s.contains("01")
    }

05.03.2026

1758. Minimum Changes To Make Alternating Binary String easy blog post substack youtube

4823be9e-b115-47a6-8a53-ebca54caf6c0 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1288

Problem TLDR

Min flips to make bits alterating #easy

Intuition

Check two targets: 01-type and 10-type.

Approach

  • we can count a balance: balance = correct-wrong , L=C+W, L- B =(C+W)-(C-W)=2W, W=(L- B )/2
  • (i + s[i]) %2 is an even-odd match

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 16ms
    fun minOperations(s: String) = s.length/2-
    abs(s.indices.sumOf { 1-2*((it+s[it].code)%2) })/2
// 0ms
    pub fn min_operations(s: String) -> i32 {
        s.len()as i32/2 - s.bytes().enumerate().map(|(i,b)|(1-2*((i as u8^b)&1)as i32)).sum::<i32>().abs()/2
    }

04.08.2026

1582. Special Positions in a Binary Matrix easy blog post substack youtube

7e6d1320-c887-4b63-976e-83ef9189f37b (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1287

Problem TLDR

Count single 1-row-column #easy

Intuition

Brute-force.

Approach

  • check each cell
  • or check each row

Complexity

  • Time complexity: \(O(n^2m^2)\), can be O(nm)

  • Space complexity: \(O(1)\)

Code

// 14ms
    fun numSpecial(m: Array<IntArray>) = m.count { r ->
        r.sum()==1 && m.sumOf { it[r.indexOf(1)] }==1
    }
// 0ms
    pub fn num_special(m: Vec<Vec<i32>>) -> i32 {
        m.iter().filter(|r|r.iter().sum::<i32>()==1&&
        m.iter().map(|R|R[r.iter().position(|&x|x>0).unwrap()]).sum::<i32>()==1).count() as _
    }

03.03.2026

1545. Find Kth Bit in Nth Binary String medium blog post substack youtube

cb47841f-071e-4cef-a28c-043dba8bcf89 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1286

Problem TLDR

Kth bit in s=s+1+inv(rev(s)) sequence #medium

Intuition

    // 2^20 is 1M
    //
    //  011100110110001  15
    //  0111001 1 0110001  7-1-7
    //  a       1 inv(rev(a))
    //  011 1 001          3-1-3
    //  0 1 1              1-1-1
    //
    //  011100110110001  15
    //                   15-1-15 = 31
    //                   31-1-31 = 63
    //                   63-1-63 = 127
    // 1 3 7 15 31 63 127
    // 2^n-1
    //
    // 0
    // 0 1 1
    // 011 1 001
    // 0111001 1 0110001
    //             ^
    //     ^
    //   ^
  • current middle of K is the highest one bit, 110 - 100
  • reverse jump: k = 2*k.takeHighestOneBit()-k
  • the glue-positions are all powers of two

O(1) intuition (is just observation of the patterns): 123456789101112 0111001101 1 0 1 1 1 blue bits are powers of two 0 1 0 1 0 1 odd positions are alterating bits sequence (infinite) 3 * * even positions have all the same odd ‘core’ by dividing by 2 (+flip) 5 10

  • rule 1: odd k is alterating bits 01010101, just return k/2%2
  • rule 2: even k goes to the core by dividing /2 until odd met, then it is rule1+flip

Approach

  • start with drawing the patterns
  • look for the unique properties, how many you can spot, useful or not
  • use small examples to test theory, k = 0, 1, 2, 3
  • use one big example to prove it still works k = 11
  • spend another 2 hours asking ai to give as many other ideas as possible

Complexity

  • Time complexity: \(O(log(k))\) or O(1)

  • Space complexity: \(O(log(k))\) or O(1)

Code

// 0ms
    fun findKthBit(n: Int, k: Int): Char =
        if (k < 2) '0' else if (k and (k-1)==0) '1' else 
        '1'+ ('0'-findKthBit(n, 2*k.takeHighestOneBit()-k))
// 0ms
    pub fn find_kth_bit(n: i32, mut k: i32) -> char {
        (b'0' + if k % 2 > 0 { k/2 % 2 } else { 1-(k >> k.trailing_zeros())/2%2 }as u8) as _
    }

02.03.2026

1536. Minimum Swaps to Arrange a Binary Grid medium blog post substack youtube

13f2bfea-b565-4bcf-bae8-9497cdd67bfd (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1285

Problem TLDR

Min rows swaps to zero above diagonal #medium

Intuition

    // 62% acceptance rate, should be simple
    // 200 nxn=40000
    // count suffix zeros
    // 0
    // 1
    // 2
    // target is 
    // n-1
    // n-2
    // ...
    // 1
    // 0
    // or more
    // 012 210
    // how to rearrange optimally?
    // 201
    // 210
    //
    // 022 220
    //
    // 021 210
    //
    // only adjucent means its a bubble sort only
    //
  • count suffixes
  • bubble rows up

Approach

  • we don’t have to add them back

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n)\)

Code

// 22ms
    fun minSwaps(g: Array<IntArray>) =
        ArrayList(g.map { it.lastIndexOf(1) }).run {
            indices.sumOf { i ->
                val j = indices.find { get(it) <= i }
                removeAt(j ?: return -1); j
            }
        }
// 0ms
    pub fn min_swaps(g: Vec<Vec<i32>>) -> i32 {
        let mut s = g.into_iter().map(|r|r.into_iter().rposition(|x|x>0).unwrap_or(0)).collect_vec();
        (0..s.len()).try_fold(0, |r, i| { 
            s.iter().position(|&x| x <= i).map(|j|{ s.remove(j); r+j as i32})}).unwrap_or(-1)
    }

01.03.2026

1689. Partitioning Into Minimum Number Of Deci-Binary Numbers medium blog post substack youtube

e1f08fed-fa61-41b4-b9c2-128ee956ab97 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1284

Problem TLDR

Min 01-strings add up to target #medium

Intuition

    // 279
    // 101
    // 101
    //  11 * 7
    // 2
    //  7
    //   (2+7)
    //
    // 12345
    // 11111
    //  1111
    //   111
    //    11
    //     1
    //
    // 54321
    // 11111
    // 1111
    // 111
    // 11
    // 1
    //
    // 105
    //
    // 50
    //
    // 505

Greedy idea: take as big binary number as possible to quickly fill to target.

Approach

  • max

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 24ms
    fun minPartitions(n: String) = 
        n.max() - '0'
// 0ms
    pub fn min_partitions(n: String) -> i32 {
        (n.bytes().max().unwrap() - 48) as _
    }

28.02.2026

1680. Concatenation of Consecutive Binary Numbers medium blog post substack youtube

img

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1283

Problem TLDR

Concat binaries 1..n #medium

Intuition

Brute-force is accepted.

The log solution: r = r*2^L + x x = x + 1 repeated for distinct groups of lengths group divider is (1 shl L) - 1, count = curr-prev convert to matrix (2^L 1 0) ( 0 1 1) ( 0 0 1)

RX1 = M^count * RX1

exponentiation: a^b = a^(b/2)*2 + a^(b)%2

Approach

  • for brute-force: we can reuse previous length and increase on each 2^x
  • we can use countLeadingZeroBits()

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 127ms
    fun concatenatedBinary(n: Int) = (1..n).fold(0L) 
    { r, x -> (x + (r shl (32-x.countLeadingZeroBits())))%1000000007 }
// 2ms
    pub fn concatenated_binary(n: i32) -> i32 {
        const I: [i64; 9] = [1, 0, 0, 0, 1, 0, 0, 0, 1]; const M:i64 = 1000000007;
        let (n, mut r, mut s, mut l) = (n as i64, 0, 1, 1);
        fn mul(a: [i64; 9], b: [i64; 9]) -> [i64; 9] {
            from_fn(|i| (0..3).map(|k| a[i/3*3+k] * b[k*3+i%3]).sum::<i64>() % M)
        }
        fn pow(b: [i64; 9], p: i64) -> [i64; 9] {
            if p == 0 { I } else { mul(pow(mul(b, b), p / 2), if p % 2 > 0 { b } else { I }) }
        }
        while s <= n {
            let e = n.min((1i64 << l) - 1);
            let t = pow([(1i64 << l) % M, 1, 0, 0, 1, 1, 0, 0, 1], e - s + 1);
            r = (r * t[0] + s * t[1] + t[2]) % M;
            s = e + 1; l += 1;
        }
        r as _
    }

27.02.2026

3666. Minimum Operations to Equalize Binary String hard blog post substack youtube

img

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1282

Problem TLDR

Min steps to convert 01 stirng to ones flipping K #hard #bfs

Intuition

Didn’t solve.

 // acceptance rate 40%
    // i will give up after 30 minutes
    //
    //
    // 110    k=1
    //   1
    //
    // 0101   k=3
    // 10 0
    //  111
    // 
    // 101    k=2
    // 01
    //  00
    // 11
    // ...    -1
    //
    // there should be a law or shortcut?
    //
    // simulation - impossible
    //
    // all k should be selected
    // order doesnt matter
    // so it is just a two numbers: zeros and ones
    //
    // 00000001111111    k
    //
    // how many zeros to choose at each step?
    // dp? try all counts?
    //
    // how to detect that we can't reach the end?
    //
    // z 5 o 5 k=6
    // o += min(k,z)   o=5+5=10
    // o -= k-min(k,z) o=10-1=9
    // z = k-min(k,z)  z=1
    //
    //
    // 9minute
    //
    // z 1 o 9 k=6  so, this can loop forever
    //              any strategy that would work?
    // 5:5 - 1:9 - 7:3 - BFS? numbers up to 10^5
    //                   each round is n choices
    //                   prune with visited set
    //
    //                   i have no other ideas, let's try
    // 14 ;minute
    // 20 minute - wrong answer 0101 k=3 my is 1, expected 2
    // 26 minute - wrong answer 001 k=3 my is 2, expected -1
    // 32 minute - wrong answer 000 k = 1, my is -1, expected 3
    //             so my entire intuition doesnt work on the repeated cases
    //             how to mitigate?
    //             k=1, zeros = 3, repeats = z/k = 3
    //             so this should be dijkstra with steps?
    // anyway i can be wrong and already spent 35 minutes, lets' go hints

The TLE BFS: number of zeros are the state, next states are max(0,k-ones)..min(k,zeros). The optimization: parity hack, from z=5 k=3 we can jump to exactly any of 2,4,6,8. Same parity, continuous (steps 2), strict L..R range. Now, instead of individual state jumps consider range adjustments L..R. We want the L to be close to 0, R to be close to N. So range grows continously, peek only interesting range.

For L to reach 0, we want it be close to K, and also want L..R be wider to skip-jump to K. For R reach N, we target R-K to flip all bits.

Approach

  • use ai

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 13ms
    fun minOperations(s: String, k: Int): Int {
        var L = s.count { it == '0' }; var R = L
        for (step in 0..s.length) {
            if (L == 0) return step
            val newL = when {
                k in L..R -> (L + k) % 2
                k < L -> L - k
                else -> k - R
            }
            val targetR = s.length - k
            val newR = s.length - when {
                targetR in L..R -> (L + targetR) % 2
                targetR < L -> L - targetR
                else -> targetR - R
            }
            L = newL; R = newR
        }
        return -1
    }

26.02.2026

1404. Number of Steps to Reduce a Number in Binary Representation to One medium blog post substack youtube

22a9c953-789e-4786-8de8-7160633fdc92 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1281

Problem TLDR

Ops /2+1 to make 1 #medium #simulation

Intuition

Simulate the process, O(n^2) is accepted

Approach

  • to optimize propagate the carry to the next op instead of doing full +1 operation

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 10ms
    fun numSteps(s: String) = s.lastIndexOf('1') + 
    (if (Regex("^10*$") in s) 0 else 2) + s.count {it<'1'}
// 0ms
    pub fn num_steps(s: String) -> i32 {
        let mut c = 0;
        (1..s.len()).rev().map(|i| {
            c += (s.as_bytes()[i] - b'0') as i32;
            let r = 1 + c % 2; c = c/2+c%2; r
        }).sum::<i32>() + c
    }

25.02.2026

1356. Sort Integers by The Number of 1 Bits easy blog post substack youtube

9a58f8d1-aaaa-4b92-a674-3a6792b31633 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1280

Problem TLDR

Sort #easy

Intuition

Sort.

Approach

  • you can use 15 buckets (32 bits, and even less for 10^4 max test case)
  • still have to sort

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n)\)

Code

// 18ms
    fun sortByBits(a: IntArray) =
    a.sortedBy{it.countOneBits()*1e5+it}
// 0ms
    pub fn sort_by_bits(mut a: Vec<i32>) -> Vec<i32> {
        a.sort_by_key(|&x|(x.count_ones(),x)); a
    }

24.02.2026

1022. Sum of Root To Leaf Binary Numbers easy blog post substack youtube

ff6f701b-2549-4e1f-94d5-5e39d794d8cd (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1279

Problem TLDR

Sum of a binary numbers in a binary tree #easy

Intuition

The simplest way: helper method, global sum variable, track leafs.

Approach

  • we can skip checking the leafs
  • we can use tree itself as a storage

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(log(n))\)

Code

// 18ms
    fun sumRootToLeaf(r: TreeNode?): Int = r?.run {
        max(`val`, setOf(left,right).sumOf { it?.`val` += `val`*2; sumRootToLeaf(it) })
    } ?: 0
// 0ms
    pub fn sum_root_to_leaf(r: Option<Rc<RefCell<TreeNode>>>) -> i32 {
        r.map_or(0, |n| { let n = n.borrow_mut(); 
            [&n.left, &n.right].into_iter().flatten().map(|x| {
                x.borrow_mut().val += n.val * 2;
                Self::sum_root_to_leaf(Some(x.clone()))}).sum::<i32>().max(n.val)
        })
    }

23.02.2026

1461. Check If a String Contains All Binary Codes of Size K medium blog post substack youtube

79e0f1f4-62cc-4ab3-b79c-6b7183b02def (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1278

Problem TLDR

All numbers as substring length of k #medium #sliding_window

Intuition

Use sliding window of k. Calculate the current number, add to a set. Uniqs count should be 2^k.

Approach

  • use built-in windows, the k is small, can take substrings on the fly
  • inverted solution: number of allowed duplicates is len-k+1 - 2^k
  • return early

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 130ms
    fun hasAllCodes(s: String, k: Int) =
    s.windowed(k).toSet().size == 1 shl k 
// 87ms
    pub fn has_all_codes(s: String, k: i32) -> bool {
        s.as_bytes().windows(k as usize).unique().count() as i32 == 1 << k
    }

22.02.2026

868. Binary Gap easy blog post substack youtube

8a9d5d07-3d31-4013-9259-420ff2a0c2f6 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1277

Problem TLDR

Distance between onces in a binary #easy

Intuition

The simplest way is to convert to string, then scan the positions.

Approach

  • n & (n-1) erases the last set bit
  • trailing_zeros, count_ones
  • regex to match (?=(10*1))
  • regex to split ^0+ 1 0+$

Complexity

  • Time complexity: \(O(log(n))\) or less

  • Space complexity: \(O(log(n))\) or less

Code

// 17ms
    fun binaryGap(n: Int) = 
    (28 downTo 0).firstOrNull{("1"+"0".repeat(it)+"1") in n.toString(2)}?.plus(1)?:0
    /*
    Regex("(?=(10*1))").findAll(n.toString(2)).maxOfOrNull{it.groupValues[1].length-1}?:0
    */
// 0ms
    pub fn binary_gap(mut n: i32) -> i32 {
        (1..n.count_ones()).map(|_| { 
            n >>= n.trailing_zeros() + 1; n.trailing_zeros() as i32 + 1 }).max().unwrap_or(0)
    }

21.02.2026

762. Prime Number of Set Bits in Binary Representation easy blog post substack youtube

5f0418bb-1a61-41b3-ad9d-84bd31aafa6f (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1276

Problem TLDR

Number in l..r with prime bits count #easy #combinatorics

Intuition

Just brute force the range L..R.

Approach

  • only 2..19 primes, all can fit in bitmask 0xa28ac
  • we can solve the problem for each prime: “how many numbers up to R with the same bits count?”
  • custom solutin with combinatorics: check every set bit, how many places it can be put in a tail
  • Gosper’s hack: find next smallest number with the same set bits count

Complexity

  • Time complexity: \(O(n)\) to O(log(n)) for combinatorics

  • Space complexity: \(O(1)\)

Code

// 1ms
    fun countPrimeSetBits(l: Int, r: Int) = 
    intArrayOf(2,3,5,7,11,13,17,19).sumOf { f(r,it)-f(l-1,it) }
    companion object {
        val nCr = Array(22) { IntArray(22) }
        init { for (i in 0..20) {
            nCr[i][0] = 1
            for (j in 1..i) nCr[i][j]=nCr[i-1][j-1]+nCr[i-1][j]
        }}
        fun f(n: Int, k: Int): Int {
            var cnt = 0; var b = 0
            for (i in 20 downTo 0) if (n shr i and 1 > 0)
                if (k-b >= 0) cnt += nCr[i][k-b++]
            if (b == k) cnt++
            return cnt
        }
    }
// 86ms
    fun countPrimeSetBits(l: Int, r: Int): Int {
        var cnt = 0
        for (p in listOf(2, 3, 5, 7, 11, 13, 17, 19)) {
            var x = (1 shl p) - 1
            while (x <= r) {
                if (x >= l) ++cnt
                val c = x and -x
                val nextR = x + c
                x = (nextR xor x shr 2) / c or nextR
            }
        }
        return cnt
    }
// 0ms
    pub fn count_prime_set_bits(l: i32, r: i32) -> i32 {
       (l..=r).map(|x| 0xa28ac >> x.count_ones() & 1).sum::<i32>()
    }

20.02.2026

761. Special Binary String hard blog post substack youtube

42c4c4c5-d78e-4f1e-a571-baa88a450791 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1275

Problem TLDR

Swaps of 1M0-special substring to make string large #hard

Intuition

Didn’t solve :)

    // 30 minutes befor i go to hints
    // description unclear: prefix?
    // at least as many 1 as 0 what?
    // 11 ok
    // 01 not ok, prefix 0 has one zero and no ones
    // 1010 ok
    // 100 not ok, two zeros more than one 
    // 110 ok
    // and the first condition: numbers are equal
    // 1010 ok
    // 1100 ok
    // 101 not ok
    // 110 not ok
    // 10 ok
    // 11101 not ok
    // 11101000 ok
    //
    // now the swap operation to make largest possible
    // meaning move ones to start
    // 11011000
    //  **
    //    ****
    //
    //
    // s length is only 50
    //
    // for every zero we try to:
    // 1. find first substring
    // 2. find next substring
    //
    // from zero we should only move left
    //
    // acceptance rate is too high 73% brainteaser?
    //
    // 8 minute
    //
    // 11011000
    //  **
    //    ****
    // let's try to go only 1 position to the left
    // that means next should always by 11
    // followed by 00
    // ok this is wrong
    // 1010101100
    // 1010110010 my
    // 1100101010 correct
    // 17 minute
    // 1010101100
    //     aabbbb
    // 1010110010 one change
    //            ok this can backtrack 
    // how many times? maybe 50? what if we just repeat
    // another wrong answer
    // 110110100100
    // 110110100100 my
    // 111010010100 correct
    //              so the second chunk can be longer
    //              110100
    // 21 minute
    //              we should find the shortest chunk
    //              or should we try all of them?
    //              lets just take shortest
    // 30 minute wrong answer, go for hints
    //101110110011010000"
    //111100110100100010"
    //11101001100100010"
    // draw a line?? y coordinate?

Derived rules: starts with 1, ends with 0. Slide and compute the balance. On each b==0 go deeper by a single char: “1(substring)0”

Approach

  • why cut and then append 1..0? To go deeper.
  • why can’t cut 1..0 on the entire ‘s’? Because its not proven they are outer shell, they can be many chunks.

Complexity

  • Time complexity: \(O(n^2)\), can be O(n)

  • Space complexity: \(O(n)\)

Code

// 37ms
    fun makeLargestSpecial(s: String): String = buildList {
        var b = 0; var j = 0
        for (i in s.indices) {
            b += 2 * (s[i]-'0') - 1
            if (b == 0) { add("1" + makeLargestSpecial(s.slice(j+1..<i)) + "0"); j = i + 1 }
        }
    }.sortedDescending().joinToString("")

19.02.2026

696. Count Binary Substrings easy blog post substack youtube

ca5bca1d-de86-418b-815f-1df4df895c62 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1274

Problem TLDR

Count substrings of 01 and 10 #easy #sliding_window

Intuition

Count consequent zeros and ones. Slide pair-wise res += min(prev, curr).

Approach

  • the fun solution is to split the string
  • itertools in Rust allow nested windows without vec allocation

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 69ms
    fun countBinarySubstrings(s: String) = s
    .replace("01", "0 1").replace("10", "1 0").split(" ")
    .zipWithNext { a, b -> min(a.length, b.length)}.sum()
// 0ms
	pub fn count_binary_substrings(s: String) -> i32 {
        s.as_bytes().chunk_by(|a,b|a==b).map(|c|c.len() as i32)
        .tuple_windows().map(|(a,b)|a.min(b)).sum()
    }

18.02.2026

693. Binary Number with Alternating Bits easy blog post substack youtube

c2a476b9-d0a9-4fc9-b2d3-646f51977522 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1273

Problem TLDR

Alternating bits #easy #bits

Intuition

Check 31 bits with brute force.

The “clever solutions”:

  • shift right by 2 positions, should match; shift right by 1 positions, should be opposite
  • shift right by 1 position, do or: should be all ones

Approach

  • regex: (00 11)

Complexity

  • Time complexity: \(O(1)\)

  • Space complexity: \(O(1)\)

Code

// 0ms
    fun hasAlternatingBits(n: Int) = 
    n or n/4 == n && n and n/2 == 0
    /*
    Regex("(11|00)") !in n.toString(2)
    (n xor n/2).toString(2).all { it == '1' }
     */
// 0ms
    pub fn has_alternating_bits(mut n: i32) -> bool {
        n ^= n/2; n & n+1 == 0
    }

17.02.2026

401. Binary Watch easy blog post substack youtube

2452a5d7-dbae-4b54-95d4-3d274d7463cb (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1272

Problem TLDR

All times with count bits set #easy #brainteaser

Intuition

Not an easy problem.

    // i don't understand the description
    // is AM/PM a separate bit?
    // H: 8 4 2 1
    // M: 32 16 8 4 2 1
    // input is count of turned on bits?
    // t=1, should be 10 results - correct
    // now we need:
    // dfs to collect all possible bits permutations
    // (1 shl (t-1))
    // then a way to convert a bitmask to the time string
    // or maybe inversed problem is simpler:
    // iterate hours and minutes, convert to bits, check count
    // 
    // how to convert numbe to bits?
    // 3: 11, ITS just a binary representation

The brainteaser brute-force: check every hour-minute pair. The honest worker solution: backtrack every set bit of possible 10 bit positions. The hard solution: compute next smallest bitmask with set bits.

Approach

  • hours to bits conversion: just a binary representation
  • bits to hours conversion: just an int value of a bitmask
  • only 720 possible values (60*12)
  • we can call countOneBits once on H*64+M
  • use format or padStart
  • next smallest bitmask: mode left the first 1-bit of the ‘11..’s tail, put leftower ‘11..’s-1 tail to the end (100110 becomes 101011) Gemini_Generated_Image_ol14zlol14zlol14.webp

Complexity

  • Time complexity: \(O(h*m)\)

  • Space complexity: \(O(h*m)\)

Code

// 25ms
    fun readBinaryWatch(t: Int) = (0..719)
    .filter { (it/60 * 64 + it%60).countOneBits() == t }
    .map { "%d:%02d".format(it/60,it%60) }
// 0ms
    pub fn read_binary_watch(t: i32) -> Vec<String> {
        successors(Some((1<<t)-1), |&s:&i32| {
            let tz = s.trailing_zeros(); let to = (s >> tz).trailing_ones();
            (tz + to < 10).then(|| s + (1 << tz) + (1 << (to - 1)) - 1)
        })
        .filter_map(|s| {
            let (h,m) = (s>>6, s&63);
            (h < 12 && m < 60).then(|| format!("{}:{:02}", h, m)) 
        }).collect()
    }

16.02.2026

190. Reverse Bits easy blog post substack youtube

c4badb58-92a0-4dad-9520-04573afa0f74 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1271

Problem TLDR

Reverse bits #easy #bits

Intuition

Manually reverse all 31 positions.

Approach

  • if called many times: use built-in functions (they should be optimized and cached) and use lookup tables if memory allows

Complexity

  • Time complexity: \(O(log(n))\)

  • Space complexity: \(O(1)\)

Code

// 103ms
    fun reverseBits(n: Int) =
        Integer.reverse(n)
        /*
        (0..31).sumOf { b -> n shr b and 1 shl (31-b) }
        n.toString(2).reversed().padEnd(32,'0').toInt(2)
        (0..31).fold(0) { r, b -> n shr b and 1 shl (31-b) or r }
         */
// 2ms
    pub const reverse_bits: fn(i32) -> i32 = i32::reverse_bits;
    /*
    pub fn reverse_bits(n: i32) -> i32 {
        (0..32).map(|b| (n >> b & 1) << (31-b)).sum()
    }
    */

15.02.2026

67. Add Binary easy blog post substack youtube

63029afe-a537-444e-8e13-0761c7dbdc2a (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1269

Problem TLDR

Binary strings sum #easy

Intuition

Carry = value / base

Approach

  • ‘0’ = 48, so &1 converts char to 1 or 0
  • insert(0) is O(n^2) but only 9ms for the test cases

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 9ms
    fun addBinary(a: String, b: String) = buildString {
        var c = 0; var i = a.lastIndex; var j = b.lastIndex
        while (i >= 0 || j >= 0 || c > 0) {
            c += if (i < 0) 0 else a[i--]-'0'
            c += if (j < 0) 0 else b[j--]-'0'
            insert(0, c % 2); c /= 2
        }
    }
// 0ms
    pub fn add_binary(a: String, b: String) -> String {
        let (mut a, mut b, mut c) = (a.bytes().rev(), b.bytes().rev(), 0);
        from_fn(|| (a.len() > 0 || b.len() > 0 || c > 0).then(|| {
            c += (a.next().unwrap_or(0)&1) + (b.next().unwrap_or(0)&1);
            let v = c % 2 + 48; c /= 2; v as char
        })).collect::<Vec<_>>().iter().rev().collect()
    }

14.02.2026

799. Champagne Tower medium blog post substack youtube

77e66a34-bf79-41a8-83a6-c5e8f1976b59 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1268

Problem TLDR

Flow in a Pascal’s Triangle #medium

Intuition

    // only 100 rows, we can simulate
    // however p is 10^9, so not one-by-one
    //                             x
    //                       x/2       x/2
    //                   x/4   (x/4+x/4)    x/4
    //            x/8    (x/8+x/4) (x/4+x/8)     x/8
    //    x/16  (x/16+x/16+x/8) (x/8+x/4) (x/8+x/16+x/16)  x/16
    //
    // p=1 only first x filled
    // p=2 2-1-1/2-1/2
    // p=3 3-1-(1/2+1/2+1/2+1/2)
    // p=4 4-1-2-(1/4+1/4+1/4+1/4)
    // how to look at this problem?
    //
    // given 4 cups
    // look at x - minus 1 cup, now have 3 cups
    // look at x/2 - to make it full i need 2 cups, can i have them?
    //               so mark it full and at this row we spend 2 cups
    //               1 cup extra
    // look at x/2 - we spending 2 cups at this row, so the cup is full
    //               and our 1 extra cup stays
    // look at x/4 - to make it full we need 4 cups, but have only 1
    //               so this place is 1/4, and we spend 1 cup at this row
    // look at x/4+x/4 - 1/2
    // x/4 - 1/4
    // next row x/8  0 cups left, ok but what if we have 6 cups initially
    // x - 1 5left
    // x/2 - 1 take2 3left
    // x/2 - 1
    // x/4   3/4 take3 0left
    // (x/4+x/4) 5/4 overflows 0left and 1/4 goes under this cup
    // x/4  3/4
    // x/8 -- 0/8
    // x/8+x/4 5/8 so , should we maintain overflows individually?
    // any better angle to look at this problem?
    // 24 minute
    //            4
    //      3/2        3/2
    //  1/4    1/4+1/4    1/4
    //

Simulate the flow. Keep the flow values at cells. The next row use the (previouse-1)/2

Approach

  • use an arena allocation of a single array[r]
  • right-aligned pyramid allows to iterate only forward

Complexity

  • Time complexity: \(O(r^2)\)

  • Space complexity: \(O(r)\)

Code

// 107ms
    fun champagneTower(p: Int, r: Int, c: Int): Double {
        var o = DoubleArray(r+1); o[r] = 1.0*p
        for (j in 1..r) for (i in r-j+1..r)
            o[i] = max(0.0, (o[i]-1.0)/2).also { o[i-1] += it }
        return min(1.0, o[c])
    }
// 1ms
    pub fn champagne_tower(p: i32, r: i32, c: i32) -> f64 {
        let r = r as usize; let mut o = [0.;100]; o[r] = p as f64;
        for j in 1..=r { for i in 1+r-j..=r {
            o[i] = 0.0f64.max(o[i]-1.)/2.; o[i-1] += o[i]
        }} o[c as usize].min(1.)
    }

13.02.2026

3714. Longest Balanced Substring II medium blog post substack youtube

d842c03c-b56c-40dc-b84c-1e6598b2664c (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1267

Problem TLDR

Largest equal frequencies substring of abc-string #medium #hashmap

Intuition

Didn’t solve.

 // abbac
    // i     a:1 at i=0
    //  i    b:1 at i=1
    //   i   b:2 at i=2
    //    i  a:2 at i=3
    //     i c:1 at i=4
    //
    //   aaababbaaaa
    //a: 123 4  5678
    //b:    1 23
    //         * lookup where a==1 (4-3)
    //           *
    //           lookup where a==3 (6-3) (count of c should be 0 or 3)
    // how to deal with c?
    //
    //   aaabcabcbaaaa
    //a: 123  4   5678
    //b:  . 1  2 3
    //c:  .  1  2
    //    .   * how to deal with a=4? the valid substr bca b=1 c=1
    //    .                           look for `4-min(1,1)`
    //    .    * b=2 a=4 c=1 i=b[2-min(4,1)] `cab`
    //    i     * c=2 b=2 a=4 i=max(c[2-min(4,2)],b[0],a[2]), 
    //                               im not sure this works
    // already 17 minute
    // let's go hints
    // cases?

    // 43 minute, case "ccaca"
    //

Case 1: repeated char max(if (repeates) f++ else f = 1) Case 2: pairs (a,b)(a,c)(b,c) solve separately, max(i - hashmap(balance)) Case 3: (abc) max(i-hashmap(balance(a,b)|balance(a,c)))

Approach

  • i know that for general alphabet the problem is O(n^2)
  • that means just 3 letters should be solved individually

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 232ms
    fun longestBalanced(s: String): Int {
        var m = Array(4){mutableMapOf(0 to -1)}; var f = 0
        var c = IntArray(3); var k = IntArray(3)
        return s.indices.maxOf { i ->
            c[s[i]-'a']++; if (i > 0 && s[i] == s[i-1]) f++ else f = 1; var r = f
            for (e in 0..2) if (s[i]-'a' == e) {m[e]=HashMap(); m[e][0] = i; k[e] = 0} else {
                if ((s[i]-'a'+1)%3 == e) ++k[e] else --k[e]
                r = max(r, i - (m[e].getOrPut(k[e]){i} ?: i))
            }
            max(r, i - (m[3].getOrPut(((c[1]-c[0]) shl 16) + c[2]-c[0]){i} ?: i))
        }
    }
// 158ms
    pub fn longest_balanced(s: String) -> i32 {
        let (mut m, mut k, mut c, mut f) = (vec![Map::from([(0,-1)]);4], [0;3], [0;3], 0);
        s.bytes().enumerate().map(|(i, b)| {
            f = 1 + f * (i > 0 && b == s.as_bytes()[i-1]) as i32;
            let (i, x) = (i as i32, (b - 97) as usize); c[x] += 1; 
            (0..3).map(|e| if x == e { m[e] = Map::from([(0, i)]); k[e] = 0; 0 } else {
                k[e] += ((x + 1) % 3 == e) as i32 * 2 - 1; i - *m[e].entry(k[e]).or_insert(i)
            }).max().unwrap().max(i - *m[3].entry(((c[1]-c[0])<<16)+c[2]-c[0]).or_insert(i)).max(f)
        }).max().unwrap_or(0)
    }

12.02.2026

3713. Longest Balanced Substring I medium blog post substack youtube

8720b147-110d-40c5-83e4-c98559eb564f (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1266

Problem TLDR

Max substring with equal frequencies #medium #sliding_window

Intuition

Brute-force.

  1. Start from every index. Go to the end. Compute the frequencies, Detect when all f the same.
  2. Check every window size decreasing. Compute the frequencies in a sliding window. Stop when all f the same.

Approach

  • max(f) * uniq = window

Complexity

  • Time complexity: \(O(26n^2)\)

  • Space complexity: \(O(1)\)

Code

// 123ms
    fun longestBalanced(s: String) = (s.length downTo 1).first { w ->
        val f = IntArray(26); var u = 0
        s.indices.any { i ->
            if (f[s[i]-'a']++ < 1) ++u
            if (i - w >= 0) if (--f[s[i-w]-'a'] < 1) --u
            1 + i - w >= 0 && w == f.max() * u
        }
    }
// 16ms
    pub fn longest_balanced(s: String) -> i32 {
        let b = s.as_bytes(); (0..b.len()).map(|i| {
            let (mut f, mut u, mut m) = ([0; 26], 0, 0);
            b[i..].iter().enumerate().map(|(len, &c)| {
                let k = (c - b'a') as usize;
                if f[k] == 0 { u += 1 }; f[k] += 1; m = m.max(f[k]);
                if m * u == len + 1 { (len + 1) as i32 } else { 0 }
            }).max().unwrap_or(0)
        }).max().unwrap_or(0)
    }

11.02.2026

3721. Longest Balanced Subarray II hard blog post substack youtube

a0f6bd95-d9f3-467a-b781-d170cc970ba3 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1265

Problem TLDR

Max subarray evens count = odds count #hard #segment_tree

Intuition

Didn’t solve.

    // this is a hard version of yesterdays problem
    // O(n^2) will not be accepted
    //
    // my idea: define window size and binary search it
    // when moving the window we have to adjust count on the fly
    //
    //    3 2 2 5 4    w=2
    //    * *          f[3]=1 f[2]=1
    //      * *        f[3]=0 f[2]=2   (and count uniqs in parallel)
    //
    // stop: does this function linear from true to false?
    //     small subarray is NOT balanced
    //     and big subarray IS balanced
    //                so the binary search wouldn't work
    //
    // given the small acceptance rate i go for hints at 10 minute
    // so its a segment tree; 
  1. Convert evens and odds to +1/-1
  2. Segment Tree: manage the prefix sum up to i
  3. If sum[root] == 0, then entire prefix is balanced
  4. If sum[root] != 0, find leftmost index j with the same value of sum[root], because prefix[i]-prfix[j] = 0 means subarray is balanced
  5. Handle duplicated by updating the value to 0 in a segment tree
  6. The min[..] and right[..] are the prefix values of subtrees for the search. min[n] is the lowest possible prefix sum in this subtree

Approach

  • try to understand how this works
  • can you answer the question: why we are checking s in min[left]..right[left] to go to the left subtree? Why we are shifting min[right]+sum[left]?

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n)\)

Code

// 165ms
    fun longestBalanced(n: IntArray): Int {
        val sz=n.size; val sum = IntArray(sz*4); val min = IntArray(sz*4); val max = IntArray(sz*4)
        fun update(idx: Int, v: Int, l: Int = 0, r: Int = sz-1, n: Int = 1) {
            if (l == r) { sum[n] = v; min[n] = v; max[n] = v; return }
            if (idx <= (l+r)/2) update(idx,v,l,(l+r)/2,n*2) else update(idx,v,(l+r)/2+1,r,n*2+1)
            sum[n] = sum[n*2]+sum[n*2+1]
            min[n] = min(min[n*2], sum[n*2] + min[n*2+1])
            max[n] = max(max[n*2], sum[n*2] + max[n*2+1])
        }
        fun q(l: Int = 0, r: Int = sz-1, n: Int = 1, s: Int = 0): Int = if (l==r) l else
            if (sum[1]-s in min[n*2]..max[n*2]) q(l,(l+r)/2,n*2,s) else q((l+r)/2+1,r,n*2+1,s+sum[n*2])
        val p = IntArray(100001)
        return n.indices.maxOf { i ->
            if (p[n[i]] > 0) update(p[n[i]]-1, 0); p[n[i]] = i+1; update(i, n[i]%2*2-1)
            if (sum[1] == 0) i + 1 else i - q()
        }
    }

10.02.2026

3719. Longest Balanced Subarray I medium blog post substack youtube

a329e53f-9de6-4ee1-93ec-567f59924069 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1264

Problem TLDR

Longes even=odd subarray #medium #hashset

Intuition

    // two pointers: we can't just blindly shrink/expand the window
    // pref mid suf
    //
    // 1 3 5 6 7 9 11
    // o o o e o o o
    // which part to cut?
    // is this DP? big acceptance rate, probably brain teaser
    // the array size is small only 1500
    // we can check every subarray in O(n^2)
    // build a prefix sum array
    // ok but how to deal with duplicates?
    //
    // 1 2 3 2
    // 1 1 2 2 odds
    // 0 1 1 2 evens non-uniq
    // 0 1 1 1 evens uniq
    //     * * will give wrong count for this range
    //
    // let's try write o(n^3), can't think of an optimal solution
    // TLE
    // as expected
    // 18 minute, go for hints; brute force? i litterally did that
    // ok maybe there is an O(N^2) brute-force possible?

From every position go to the end and count evens and odds. Mark visited with hashset.

Approach

  • use array instead of hashset
  • array can be global if we mark visited values with current i

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n)\)

Code

// 263ms
    fun longestBalanced(n: IntArray) = n.indices.maxOf { i ->
        var b = 0; var m = HashSet<Int>()
        1 - i + ((i..<n.size).lastOrNull { j ->
            if (m.add(n[j])) b += 1 - n[j]%2*2; b == 0
        }?:i-1)
    }
// 16ms
    pub fn longest_balanced(n: Vec<i32>) -> i32 {
        let (mut r, mut s) = (0, [0;100001]); 
        for i in 0..n.len() { if n.len() - i <= r { break }; let mut b = 0; 
            for (j, &x) in n[i..].iter().enumerate() { let v = x as usize;
            if s[v] <= i { s[v] = i + 1; b += 1 - (v as i32 & 1) * 2 }
            if b == 0 { r = r.max(j + 1) }}} r as _
    }

09.02.2026

1382. Balance a Binary Search Tree medium blog post substack youtube

16abb998-7e00-4441-a0c6-61995998c0f3 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1263

Problem TLDR

Balance binary search tree #medium #dfs

Intuition

Collect to a list with in-order dfs. Build a new, count of left subtree is equal to the count of right subtree. Mid is current.

Approach

  • we can store nodes itself on a list
  • we can avoid building the list, just make a lazy iterator (sequence in Kotlin, or Stack and from_fn in Rust)

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\), O(log(n)) for the lazy iterator

Code

// 22ms
    fun balanceBST(r: TreeNode?): TreeNode? {
        val l = buildList {fun c(r: TreeNode?) {r?.run { c(left); add(r); c(right) }};c(r)}
        fun b(f: Int, t: Int): TreeNode? =
            if (f > t) null else l[(f+t)/2].apply {
                left = b(f, (f+t)/2-1); right = b((f+t)/2+1, t)
            }
        return b(0, l.lastIndex)
    }
// 0ms
    type Tr = Rc<RefCell<TreeNode>>; type Opt = Option<Tr>;

    pub fn balance_bst(r: Opt) -> Opt {
        fn c(n: &Opt) -> i32 { n.as_ref().map_or(0, |n| 1 + c(&n.borrow().left) + c(&n.borrow().right)) }
        let (n, mut s, mut c) = (c(&r), vec![], r);
        let mut i = std::iter::from_fn(move || {
            while let Some(t) = c.take() { c = t.borrow().left.clone(); s.push(t); }
            s.pop().map(|t| { c = t.borrow().right.clone(); t })
        });
        fn b(k: i32, i: &mut impl Iterator<Item = Tr>) -> Opt {
            if k < 1 { return None }; let l = b(k / 2, i);
            i.next().map(|t| { t.borrow_mut().left = l; t.borrow_mut().right = b(k - 1 - k / 2, i); t })
        }
        b(n, &mut i)
    }

08.02.2026

110. Balanced Binary Tree easy blog post substack youtube

a2bb7e56-105b-45cc-a303-72c60366d33c (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1262

Problem TLDR

Is tree balanced? #easy #dfs

Intuition

Solve the sub-problem for every node. Compare max depths for the left and right.

Approach

  • we can use ‘marker’ depth as a boolean
  • we can shortcircuit and don’t check the right subtree
  • we can override values in a tree to golf the solutino
  • BFS will not solve this: leafs can be at any heights, only max depths left&right for each node matters

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(log(n))\)

Code

// 0ms
    fun isBalanced(r: TreeNode?): Boolean = r?.run {
        val b = isBalanced(left) && isBalanced(right)
        val l = left?.`val`?:0; val r = right?.`val`?:0
        `val`= 1 + max(l,r); b && abs(l-r) < 2
    } ?: true
// 0ms
    pub fn is_balanced(r: Option<Rc<RefCell<TreeNode>>>) -> bool {
        fn d(r: &Option<Rc<RefCell<TreeNode>>>) -> Result<i8, ()> {
            let Some(n) = r else { return Ok(0) }; let n = n.borrow();
            let l = d(&n.left)?; let r = d(&n.right)?;
            if (l-r).abs() > 1 { Err(()) } else { Ok(1 + l.max(r)) }
        } 
        d(&r).is_ok()
    }

07.02.2026

1653. Minimum Deletions to Make String Balanced medium blog post substack youtube

f761f76d-8f1c-40ff-83bb-b0d5ee98e67a (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1261

Problem TLDR

Min removal to balance ‘ab’ #medium #greedy

Intuition

Split at each position and compare left and right counts of ‘a’ and ‘b’. The greedy intuition: count ‘b’, at each ‘a’ choose min of (remove ‘a’=d+1, keep ‘a’=b count removed)

Approach

  • the corner cases of single ‘a’ and ‘b’ should be checked

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 24ms
    fun minimumDeletions(s: String): Int {
        var b = 0
        return min(0,s.minOf { b += 2*(it - 'a')-1; b }) + s.count{it=='a'}
    }
// 10ms
    pub fn minimum_deletions(s: String) -> i32 {
        s.bytes().fold((0,0),|(b,d),c|if c>b'a'{(b+1,d)}else{(b,b.min(d+1))}).1
    }

06.02.2026

3634. Minimum Removals to Balance Array medium blog post substack youtube

388e4676-09f0-49fe-b476-f6dcf405a4a9 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1260

Problem TLDR

Min removals to make min*k not less than max #medium #sliding_window

Intuition

    // 12 18      k=2  wrong answer
    //                 why 0 instead of 1 ?
    //        ok, read description wrong
    //       it k times not k diff
    // another case is int overflow
    // 1 10 10 10 10 20

Invert the problem: maximum window that we want to keep is the answer.

Approach

  • lazy sliding window: we don’t have to shrink window, only care about expanding it
  • use longs

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(1)\)

Code

// 41ms
    fun minRemoval(n: IntArray, k: Int) = n.run {
        sort(); var w = 0; count { 1L*it > 1L*k*n[w] && ++w > 0 }
    }
// 9ms
    pub fn min_removal(mut n: Vec<i32>, k: i32) -> i32 {
        n.sort(); let mut w = 0; 
        for &x in &n { w += (x as i64 > n[w]as i64*k as i64) as usize}; w as i32
    }

05.02.2026

3379. Transformed Array easy blog post substack youtube

4e8b7ea9-79b8-45a4-b35d-bb8e83d8dfee (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1259

Problem TLDR

Shuffled list i+n[i] #easy

Intuition

It took me 8 minutes to understand the problem. i - is the index of a result array i+n[i] is the index of a value we take

Approach

  • in Kotlin & Rust we have built-in for negative mod: mod & rem_euclid
  • in-place solution possible if we store results in a left bits

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 162ms
    fun constructTransformedArray(n: IntArray) = 
    List(n.size) { n[(it + n[it]).mod(n.size)] }
// 3ms
    pub fn construct_transformed_array(n: Vec<i32>) -> Vec<i32> {
        (0..n.len()).map(|i|n[((n[i]+i as i32).rem_euclid(n.len() as i32)) as usize]).collect()
    }

03.02.2026

3637. Trionic Array I easy blog post substack youtube

6836c4d7-90a4-489e-b6b1-2efbe8b6a980 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1257

Problem TLDR

Validate inc,dec,inc sequency #easy

Intuition

Brute-Force O(n^3) is accepted.

Approach

  • we can count peaks
  • we can convert to string and use regex
  • chunk_by, eq in Rust

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 32ms
    fun isTrionic(n: IntArray) =
    n.map{it}.zipWithNext(Int::compareTo)
        .joinToString("").matches(Regex("(-1)+1+(-1)+"))
    /*
    n.map{it}.zipWithNext(Int::compareTo).let { s ->
        s[0]<0 && 0 !in s && s.windowed(2).count{(a,b)->a!=b}==2 }

    n[0]<n[1] && 2 == (2..<n.size).count {
       (n[it-2]<n[it-1])!=(n[it-1]<n[it]) } &&
       (1..<n.size).all{n[it]!=n[it-1]} 
    */
// 0ms
    pub fn is_trionic(n: Vec<i32>) -> bool {
        n.windows(2).map(|w|w[1].cmp(&w[0])as i8).collect::<Vec<_>>()
        .chunk_by(i8::eq).map(|c|c[0]).eq([1,-1,1])
    }

02.02.2026

3013. Divide an Array Into Subarrays With Minimum Cost II hard blog post substack youtube

e4bff72e-a552-41a0-b499-e1adf5145668 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1256

Problem TLDR

Min sum of k splits at max d distance #hard #sliding_window #heap

Intuition

Didn’t solve.

    // take first
    // select k-1 min-sum values at dist
    //
    // ***********
    //   * * *
    //
    // move (k-1) pointers?
    //
    // binarysearch? 
    //
    // binarysearch+dp? dp answers for sum: canSplit[i]
    //                         still should be minSplit[i] O(n^2)
    // no other ideas, lets try dp, inner cycle is d, O(nkd)
    //                       obviously deadend tle
    // somehow stuck with brute-force dp
    //   looks like i didn't understood the description
    //       dist is not between splits
    //                it is between second and last
    //
    // let's go to hints
    //
    // sliding window + heap + heap
    //
    // *|**m*|********
    //  i-d  i
    //
    // let's give up at 50 minutes
  1. Maintain sliding window of d
  2. Put k-1 best values in one sorted container (TreeSet of n[i],i)
  3. Remove overflows and d+1-distant values.
  4. Keep still-in-window values in a second storage container
  5. Balance when d+1-distant value has been removed

Approach

  • there is also a BIT solution (ask ai): sort distinct values, keep BIT-arrays of counts and sums

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n)\)

Code

// 533ms
    fun minimumCost(n: IntArray, k: Int, d: Int): Long {
        var sum = 0L; val c = compareBy<Int>({n[it]},{it}) 
        val q = TreeSet(c); val s = TreeSet(c)
        return (1..<n.size).minOf { i ->
            q += i; sum += n[i]
            if (q.size >= k) { val j = q.pollLast(); sum -= n[j]; s += j }
            if (i-d-1 > 0 && !s.remove(i-d-1) && q.remove(i-d-1)) { 
                sum -= n[i-d-1]; val j = s.pollFirst(); sum += n[j]; q += j 
            }
            if (i-d-1 >= 0) sum else 1L shl 60
        } + n[0]
    }

01.02.2026

3010. Divide an Array Into Subarrays With Minimum Cost I easy blog post substack youtube

8e018255-29fb-4bde-8fd3-fc38dbcc4632 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1255

Problem TLDR

Split on 2 min values #easy #quickselect

Intuition

Array is 50 elements. Sort and take 2. Or scan and deal with ifs.

Approach

  • bitmask solution is also possible, enabling a branchless vectorizable code

Complexity

  • Time complexity: \(O(nlog(n))\), fastest is O(n)

  • Space complexity: \(O(n)\), fastest is O(1)

Code

// 10ms
    fun minimumCost(n: IntArray) = 
    n.run{sort(1);n[0]+n[1]+n[2]}
    /*
    n.run{sort(1);n.take(3).sum()}
    n[0]+n.drop(1).sorted().take(2).sum()
    */
// 0ms
    pub fn minimum_cost(mut n: Vec<i32>) -> i32 {
        n[1..].sort();n[0]+n[1]+n[2]
    }
        /*
        n[1..].select_nth_unstable(1);n[0]+n[1]+n[2]

        n[0] + n[1..].iter().sorted().take(2).sum::<i32>()

        let (a,b)=n[1..].iter().fold((0u64,0),|(a,b),&x|(a|(1<<x),b|a&(1<<x)));
        n[0] + (a.trailing_zeros() + (b | a & a - 1).trailing_zeros()) as i32
        */

31.01.2026

744. Find Smallest Letter Greater Than Target easy blog post substack youtube

ebdac7eb-6f7b-4fa2-9204-29d66866f239 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1254

Problem TLDR

Larger letter in array #easy

Intuition

Scan. Or do a binary search.

Approach

  • or search in t+1..’z’

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 1ms
    fun nextGreatestLetter(l: CharArray, t: Char) =
    l.find{it>t}?:l[0]
    /*
    (l.filter{it>t}+l[0])[0]
    l[l.count{it<=t}%l.size]
    (l.map{it}-('a'..t)+l[0])[0]
    (t+1..'z').find{it in l}?:l[0]
    l[(-1-l.map{it}.binarySearch{if(it>t)1 else -1})%l.size]
    l[(Arrays.binarySearch(l,t+1).let{if(it<0)-1-it else it})%l.size]
    */
// 0ms
    pub fn next_greatest_letter(l: Vec<char>, t: char) -> char {
        l[l.partition_point(|&c|c<=t)%l.len()]
    }

30.01.2026

2977. Minimum Cost to Convert String II hard blog post substack youtube

c1fd649a-b247-4377-a4ae-b999f37dfc6b (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1253

Problem TLDR

Min cost to convert string with transitions of substrings #hard #dp #trie #hash #floyd-warshall

Intuition

  1. Build transitions matrix of tokens
  2. Do Floyd-Warshall for k i j ij = min(ij, ik+kj)
  3. Do DP to optimally split into substrings
  4. Do rolling hashing to do substring in O(1) ammortized
    //
    // TLE
    //
    // should i prepare all substrings?
    //
    // TLE dp as array?
    //
    // TLE
    //
    // expect me do write bottom up dp?
    // comments says Floyd-Warshall causes tle
    //
    // 100^3 = 1000000 should be in acceptable range...
    //
    // i'll try to write bottom-up then will gave up, don't want to write dijkstra
    //
    // so the substring calculation is what gaves me tle, its o(n^3), n = 1000
    // 

Approach

  • or do a Trie instead of rolling hashes, but we have to build transitions u,v from String to Trie id

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n^2)\)

Code

// 1231ms
    fun minimumCost(s: String, t: String, o: Array<String>, c: Array<String>, ct: IntArray): Long {
        val sa=o.toSet() + c; val a = sa.toList(); val ai = a.indices.associate { a[it] to it }
        val m = Array(a.size) { i -> LongArray(a.size) { if (i==it) 0L else 1L shl 60 }}
        for (i in o.indices) m[ai[o[i]]!!][ai[c[i]]!!] = min(1L*ct[i], m[ai[o[i]]!!][ai[c[i]]!!])
        for (k in a.indices) for (i in a.indices) for (j in a.indices) m[i][j]=min(m[i][j], m[i][k] + m[k][j])
        val dp = LongArray(s.length+1); val hs = a.map { it.fold(0) {h,c -> h*31+c.code }}.toSet()
        for (i in s.length-1 downTo 0) {
            dp[i] = if (s[i] == t[i]) dp[i + 1] else 1L shl 60; var sh = 0; var ht = 0
            for (j in i..<s.length) {
                sh = sh*31+s[j].code; ht = ht*31+t[j].code; if (sh !in hs || ht !in hs) continue
                val si = ai[s.substring(i,j+1)]?:continue; val ti = ai[t.substring(i,j+1)]?:continue
                dp[i] = min(dp[i], m[si][ti] + dp[j + 1])
            }
        }
        return if (dp[0] < 1L shl 60) dp[0] else -1L
    }
// 464ms
    fun minimumCost(s: String, t: String, o: Array<String>, c: Array<String>, ct: IntArray): Long {
        class T(var id: Int = -1) : HashMap<Char, T>(); val r = T(); var C = 0; val inf = 1L shl 60
        fun a(w: String) = w.fold(r) { n, c -> n.getOrPut(c, ::T) }.run { if (id < 0) id = C++; id }
        val u = o.map(::a); val v = c.map(::a); val m = Array(C) { i -> LongArray(C) { if (i == it) 0 else inf } }
        for (i in o.indices) m[u[i]][v[i]] = min(m[u[i]][v[i]], ct[i].toLong())
        for (k in 0..<C) for (i in 0..<C) for (j in 0..<C) m[i][j] = min(m[i][j], m[i][k] + m[k][j])
        val dp = LongArray(s.length + 1) { inf }; dp[0] = 0
        for (i in s.indices) {
            if (dp[i] >= inf) continue; if (s[i] == t[i]) dp[i + 1] = min(dp[i + 1], dp[i]); var x = r; var y = r
            for (j in i..<s.length) {
                x = x[s[j]]?:break; y = y[t[j]]?:break
                if (x.id >= 0 && y.id >= 0)  dp[j + 1] = min(dp[j + 1], dp[i] + m[x.id][y.id])
            }
        }
        return dp.last().takeIf { it < inf } ?: -1L
    }

29.01.2026

2976. Minimum Cost to Convert String I medium blog post substack youtube

adb99ef8-8026-4882-bd51-ff5f06585d9b (2).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1252

Problem TLDR

Min cost to convert string #medium #floyd-warshall

Intuition

Prepare transition matrix from any char to any char. Path relaxation: repeat path length, repeat(path length) a,b,c ab = min(ab,ac+cb) Floyd-Warshall: outer loop is the middle, try to update ab = min(ab, ac+cb)

    // 1. find full min cost transition matrix from any char to any char
    // 2. convert source to target sumOf { m[s[i]][t[i]] }
    //
    // 1 can be done with dfs 26^2
    //
    // floyd-warshall abc    ac = min(ab+bc,ac)
    //                      wrong answer  ? (forgot about duplicates)
    //                                  
    //

Approach

  • the costs have duplicates, use min

Complexity

  • Time complexity: \(O(n + fw)\)

  • Space complexity: \(O(n + fw)\)

Code

// 33ms
    fun minimumCost(s: String, t: String, o: CharArray, c: CharArray, ct: IntArray): Long {
        val m = Array(26) { i -> LongArray(26) { if (i == it) 0 else 1 shl 30 }}
        for (i in o.indices) m[o[i]-'a'][c[i]-'a'] = min(1L*ct[i], m[o[i]-'a'][c[i]-'a'])
        for (c in 0..25) for (a in 0..25) for (b in 0..25) m[a][b] = min(m[a][b], m[a][c] + m[c][b])
        return s.indices.sumOf { m[s[it]-'a'][t[it]-'a'].takeIf {it < 1L shl 30}?: return -1L}
    }
// 6ms
    pub fn minimum_cost(s: String, t: String, o: Vec<char>, c: Vec<char>, ct: Vec<i32>) -> i64 {
        let mut m = [[1<<30;26];26]; for i in 0..26 { m[i][i] = 0 }
        for i in 0..o.len() { let (a,b) = (o[i]as usize-97, c[i]as usize-97); m[a][b]=m[a][b].min(ct[i] as i64)}
        for c in 0..26 { for a in 0..26 { for b in 0..26 { m[a][b] = m[a][b].min(m[a][c]+m[c][b])}}}
        s.bytes().zip(t.bytes()).try_fold(0, |s, (a, b)| { let c = m[(a - 97) as usize][(b - 97) as usize];
        if c >= 1 << 30 { None } else { Some(s + c) } }).unwrap_or(-1)
    }

28.01.2026

3651. Minimum Cost Path with Teleportations hard blog post substack youtube

85e6716f-65a8-4af7-a0a6-c82521ea5836 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1251

Problem TLDR

Min cost to walk 2D grid with free teleports #hard #dijkstra #dp

Intuition

Didn’t solved.

    // BFS?
    // A*
    // Dijkstra
    //
    // store individual k for each path
    //
    // moves only right-down, 
    // can teleport backwards for some optimal paths
    //
    // we have to try all possible paths
    // 
    // visited set is x,y,k
    // 
    // to teleport we have to try all "lower" values
    //
    // 80*80=1600 or 10^3 can be O(n) scan for lowers?
    // 
    // DP=DFS+cache? - no, we can visit twice with better value, so should be Dijkstra
    //
    // TLE
    //
    // TLE TLE TLE
    // TLE

To make Dijkstra work skip already done teleportations for each lower[k], where lower is indices of all sorted values.

The dp solution: do k layered relaxations of teleportations and walks right-bottom.

Approach

  • why in Dijkstra we can skip teleportations individually for each k?
  • why in Dp solution we updating by batches of equal values the minimum value so far?
  • why in Dp solution we sort descending and going from bigger to lower value and updating min(dp)?

Complexity

  • Time complexity: \(O(n^2klog(n))\) for Dijkstra and n^2k for DP

  • Space complexity: \(O(n^2k)\) for Dijkstra, n^2 for dp

Code

// 1505ms
    fun minCost(g: Array<IntArray>, k: Int): Int {
        val q = PriorityQueue<IntArray> { a,b -> a[3]-b[3] }
        val d = Array(g.size) { Array(g[0].size) { IntArray(k+1) {1 shl 30}}}
        val sorted = (0..<g.size*g[0].size).sortedBy {g[it/g[0].size][it%g[0].size]}
        q += intArrayOf(0, 0, k, 0); val lower = IntArray(k+1)
        while (q.size > 0) {
            val (x,y,k,c) = q.poll()
            if (x==g[0].size-1&&y==g.size-1) return c
            for ((x,y) in arrayOf(x+1 to y, x to y+1))
                if (x < g[0].size && y < g.size&&d[y][x][k]>c+g[y][x]) {
                    q += intArrayOf(x,y,k,c+g[y][x]); d[y][x][k] = c+g[y][x]
                }
            if (k > 0) while (lower[k] < sorted.size) {
                val i = sorted[lower[k]]; val (ny,nx) = i/g[0].size to i%g[0].size
                if (g[ny][nx] > g[y][x]) break
                if (c < d[ny][nx][k-1]) { q += intArrayOf(nx,ny,k-1,c); d[ny][nx][k-1] = c }
                lower[k]++
            }
        }; return -1
    }
// 68ms
    pub fn min_cost(g: Vec<Vec<i32>>, k: i32) -> i32 {
        let w = g[0].len(); let g = g.concat(); let n = g.len();
        let mut d = vec![1 << 30; n]; d[0] = 0;
        let mut v: Vec<_> = (0..n).collect(); v.sort_by_key(|&i| -g[i]);
        for a in 0..=k {
            for i in 0..n {
                if i >= w { d[i] = d[i].min(d[i - w] + g[i]); }
                if i % w > 0 { d[i] = d[i].min(d[i - 1] + g[i]); }
            }
            if a == k { break; }
            let (mut m, mut s) = (1 << 30, 0);
            for i in 0..=n {
                if i == n || g[v[i]] != g[v[s]] 
                    { for &j in &v[s..i] { d[j] = m; } s = i }
                if i < n { m = m.min(d[v[i]]); }
            }
        } d[n-1]
    }

27.01.2026

3650. Minimum Cost Path with Edge Reversals medium blog post substack youtube

91f5b752-fce8-4bd7-9d94-09b6bc56809d (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1250

Problem TLDR

Min path in weighted graph with reverse 2w nodes #medium #dijkstra

Intuition

Add reversed nodes to the graph. The reverse only once rule is automatically handled by Dijkstra: the optimal path will not visit nodes twice anyway.

    // bfs? how to take reversal into account?
    //      how to choose which node to reverse?
    // dijkstra
    // 
    // how to handle immediate traversal?
    // just replace original node with reversed dest?
    //
    // how to reverse just *once*?
    //

Approach

  • we don’t have to track distance array, the visited flags + heap is enough

Complexity

  • Time complexity: \(O((v+e)logV)\)

  • Space complexity: \(O(v^2)\)

Code

// 124ms
    fun minCost(n: Int, e: Array<IntArray>): Int {
        val g = Array(n) {ArrayList<Int>()}; val v = IntArray(n)
        for ((a,b,w) in e) { g[a] += w*n+b; g[b] += 2*w*n+a }
        val q = PriorityQueue<Long>(); q += 0
        return (0..4*n).firstNotNullOfOrNull {
            val wi = q.poll()?:0; val i = (wi%n).toInt()
            if (v[i]++==0) for (cj in g[i]) q += wi-i + cj
            if (i == n-1) (wi/n).toInt() else null
        } ?: -1
    }
// 64ms
    pub fn min_cost(n: i32, e: Vec<Vec<i32>>) -> i32 {
        let (N, mut g, mut q, mut v) = (n as i64, vec![vec![]; n as usize], 
                                        BinaryHeap::from([0]), vec![0; n as usize]);
        for x in e {
            let (u, k, w) = (x[0] as usize, x[1] as usize, x[2] as i64);
            g[u].push(w * N + k as i64); g[k].push(w * 2 * N + u as i64);
        }
        while let Some(c) = q.pop() {
            let i = (-c % N) as usize;
            if i == v.len() - 1 { return (-c / N) as i32; }
            if v[i] == 0 { v[i] = 1; for x in &g[i] { q.push(c - c % N - x); }}
        } -1
    }

26.01.2026

1200. Minimum Absolute Difference easy blog post substack youtube

e7c9fdb5-0db6-4819-97ab-47f397a1bf45 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1249

Problem TLDR

Min diff pairs #easy

Intuition

Sort, compare adjucent pairs, find min, collect.

Approach

  • groupBy.min also works
  • updating the min diff and collecting can be done in a single go

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n)\)

Code

// 138ms
    fun minimumAbsDifference(a: IntArray) = a.sorted()
    .windowed(2).groupBy{(a,b)->b-a}.minBy{(k,v)->k}.value
// 3ms
    pub fn minimum_abs_difference(mut a: Vec<i32>) -> Vec<Vec<i32>> {
        a.sort(); let mut d = (1..a.len()).map(|i|a[i]-a[i-1]).min().unwrap();
        a.windows(2).filter(|w|w[1]-w[0]==d).map(Vec::from).collect()
    }

25.01.2026

1984. Minimum Difference Between Highest and Lowest of K Scores easy blog post substack youtube

92716dbf-5bfe-4f84-a465-17644c73b00b (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1248

Problem TLDR

Min k-diff #easy #sliding_window

Intuition

Sort, then do a sliding window.

Approach

  • use windows(k) or zip(skip(k))

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(n)\) or O(1)

Code

// 18ms
    fun minimumDifference(n: IntArray, k: Int) = 
        n.run{sort();(k..size).minOfOrNull{n[it-1]-n[it-k]}?:0}
// 1ms
    pub fn minimum_difference(mut n: Vec<i32>, k: i32) -> i32 {
       n.sort(); n.iter().zip(n.iter().skip(k as usize-1)).map(|(a,b)|b-a).min().unwrap_or(0)
    }

24.01.2026

1877. Minimize Maximum Pair Sum in Array medium blog post substack youtube

394c3372-ac47-4f65-9e3c-129ebc57ea97 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1247

Problem TLDR

Min max pair #medium #brainteaser

Intuition

Sort. Pair maxes with mins.

Approach

  • counting sort works too

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(n)\)

Code

// 629ms
    fun minPairSum(n: IntArray) =
    n.run{sort();zip(reversed(),Int::plus).max()}
// 13ms
    pub fn min_pair_sum(mut n: Vec<i32>) -> i32 {
        let (mut c,mut i) = ([0; 100001],0); for &x in &n { c[x as usize]+=1 }
        for v in 0..100001 { for _ in 0..c[v] { n[i]=v as i32;i+=1}}
        n.iter().zip(n.iter().rev()).map(|(a,b)|a+b).max().unwrap()
    }

23.01.2026

3510. Minimum Pair Removal to Sort Array II hard blog post substack youtube

2aaada48-9d5c-422c-a4e9-fb4df9ce90bc (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1246

Problem TLDR

Sort by removing min-sum pairs #hard

Intuition

Didn’t solve.

    // seen it yesterday
    // it's too hard
    // i'll try to do it from memory
    // 
    // the algo:
    // make a linked list
    // put pairs into sorted heap
    // remove one by one
    //
    //       LL L i R RR
    //              *
    //              remove
    // i gave up
  • put sums into heap
  • poll and remove right value of the pair
  • adjust count of unordered pairs before the removal and after

Approach

  • careful with overflow, can’t put everything in Long
  • sentinels at both sides will help to avoid some checks

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(n)\)

Code

// 805ms
    fun minimumPairRemoval(n: IntArray): Int {
        val A = LongArray(n.size) {1L*n[it]} + Long.MAX_VALUE/2
        val q = PriorityQueue<Pair<Long,Int>>(compareBy({it.first},{it.second}))
        val L = IntArray(A.size) { it-1 }; val R = IntArray(A.size) { it+1 }
        q += (0..<n.size).map {(A[it]+A[it+1]) to it}; var res = 0
        fun b(i: Int, j: Int) = if (i>=0&&A[i] > A[j]) 1 else 0
        var c = (0..<n.size).sumOf{b(it,it+1)}
        while (c > 0) {
            val (s,i) = q.poll(); if (L[R[i]] != i || s != A[i]+A[R[i]]) continue
            c -= b(L[i], i) + b(i, R[i]) + b(R[i], R[R[i]])
            A[i] = s; R[i] = R[R[i]]; L[R[i]] = i
            c += b(L[i], i) + b(i, R[i])
            if (L[i] >= 0) q += (1L*s+A[L[i]]) to L[i]
            if (R[i] <= n.size) q += (1L*s+A[R[i]]) to i
            res++
        }
        return res
    }

22.01.2026

3507. Minimum Pair Removal to Sort Array I easy blog post substack youtube

64566dd5-2f58-4333-8e15-3c6318b38b2f (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1245

Problem TLDR

Sort by removing lowest sum pairs #easy

Intuition

Simulate the process.

Approach

  • just create a new array each time
  • or in Rust we can actually remove by index in-place

Complexity

  • Time complexity: \(O(n^2)\) n^2log(n) for golfing in Kotlin

  • Space complexity: \(O(n)\)

Code

// 76ms
    fun minimumPairRemoval(l: IntArray): Int {
        val l = l.toList()
        if (l == l.sorted()) return 0
        val j = (1..<l.size).minBy { l[it-1] + l[it] }
        return 1 + minimumPairRemoval((l.take(j-1) + (l[j-1]+l[j]) + l.drop(j+1)).toIntArray())
    }
// 0ms
    pub fn minimum_pair_removal(mut l: Vec<i32>) -> i32 {
        (0..).find(|_| {
            let ok = l.windows(2).all(|w| w[0] <= w[1]);
            if let Some(j) = (1..l.len()).min_by_key(|&i| l[i-1] + l[i]) { l[j-1] += l[j];  l.remove(j); }
            ok
        }).unwrap()
    }

21.01.2026

3315. Construct the Minimum Bitwise Array II medium blog post substack youtube

72fdf644-52d3-4fde-86e4-2bdddf19affe (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1244

Problem TLDR

Reverse operation x or (x+1) #medium #bits

Intuition

Forward operation: flips first one-bit in tail of ones. Reverse: flip rightmost zero bit.

    /*
    3 : 11 -> 1 : 1
5 : 101 -> 4 : 100
7 : 111 -> 3 : 11
11 : 1011 -> 9 : 1001
13 : 1101 -> 12 : 1100
17 : 10001 -> 16 : 10000
19 : 10011 -> 17 : 10001
23 : 10111 -> 19 : 10011
29 : 11101 -> 28 : 11100
31 : 11111 -> 15 : 1111
37 : 100101 -> 36 : 100100
41 : 101001 -> 40 : 101000
43 : 101011 -> 41 : 101001
47 : 101111 -> 39 : 100111
53 : 110101 -> 52 : 110100
59 : 111011 -> 57 : 111001
61 : 111101 -> 60 : 111100
67 : 1000011 -> 65 : 1000001
71 : 1000111 -> 67 : 1000011
73 : 1001001 -> 72 : 1001000
79 : 1001111 -> 71 : 1000111
83 : 1010011 -> 81 : 1010001
89 : 1011001 -> 88 : 1011000
97 : 1100001 -> 96 : 1100000
*/
// 79 : 1001111 -> 71 : 1000111
// +1   1010000
//  &   1000000
//  +  10001111
// /2   1000111

//
// 97 : 1100001 -> 96 : 1100000
// +1   1100010
//  &   1100000
//  +                  x+x in binary is 2*x which is shift left by 1
//     11000001        but we preserve a tail as is
// /2   1100000

One way: inv, &, /2, xor Second way: +1, &, +, /2

Approach

  • or you can just manually find the rightmost zero bit and flip it

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 7ms
    fun minBitwiseArray(n: List<Int>) = n.map {
        if (it==2)-1 else it xor it.inv().takeLowestOneBit()/2
    }
// 0ms
    pub fn min_bitwise_array(n: Vec<i32>) -> Vec<i32> {
        n.iter().map(|&n|if n==2{-1}else{(n+(n&(n+1)))/2}).collect()
    }

20.01.2026

3314. Construct the Minimum Bitwise Array I easy blog post substack youtube

a4f2597c-ea61-4722-ba55-8133a91c435f (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1243

Problem TLDR

Reverse x (x+1) operation on prime numbers #easy

Intuition

The op: x|(x+1) does set rightmost 0 to 1. 100: 100 | 101 = 101 Reversing it: set first suffix 1 bit to 0. 101: 100

    // 111 +1
    //1000
    // 
    // 101 100 or 101
    // 111  11 or 100
    //  10  -
    //  11   1 or 10
    //
    //  1011 1001 or 1010
    //  1101 1100 or 1
    // 11111 1111 or 10000

Approach

  • do a brute-force
  • learn from others

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 7ms
    fun minBitwiseArray(n: List<Int>)=n.map {
        if (it == 2) -1 else it xor it.inv().takeLowestOneBit()/2
    }
// 0ms
    pub fn min_bitwise_array(n: Vec<i32>) -> Vec<i32> {
        n.iter().map(|&n| if n == 2 {-1} else {n^((n+1)&!n)/2}).collect()
    }

19.01.2025

1292. Maximum Side Length of a Square with Sum Less than or Equal to Threshold medium blog post substack youtube

4395fb37-c24d-497d-b519-7265fd6064bb (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1242

Problem TLDR

Max square with sum less than threshold #medium #prefix-sum

Intuition

    // let's try with brute-force 300^4, its 10^6
    // ok, this is TLE
    // we have to do prefix sums...

Brute-force is not accepted. Optimize with prefix sums of all rectangles with top left corner 0,0.

Approach

  • optimization: binary search the size
  • optimization: increase the size by checking size+1 is a new max
  • we only have to go +1 to the top-left, because the previous is at most S (it is not possible to “discover” bigger than s+1, otherwise we would already have the more than ‘s’)

Complexity

  • Time complexity: \(O(nm)\)

  • Space complexity: \(O(nm)\), can be in-place

Code

// 9ms
    fun maxSideLength(m: Array<IntArray>, t: Int): Int {
        var s = 0; val d = Array(301) { IntArray(301) }
        for (y in m.indices) for (x in m[0].indices) {
            d[y + 1][x + 1] = d[y][x + 1] + d[y + 1][x] - d[y][x] + m[y][x]
            if (y>=s && x>=s && t>=d[y+1][x+1]-d[y-s][x+1]-d[y+1][x-s]+d[y-s][x-s])++s
        }
        return s
    }
// 0ms
    pub fn max_side_length(m: Vec<Vec<i32>>, t: i32) -> i32 {
        let (mut d, mut s) = ([[0; 301]; 301], 0);
        for (i, j) in iproduct!(0..m.len(), 0..m[0].len()) { if { 
            d[i+1][j+1] = d[i][j+1] + d[i+1][j] - d[i][j] + m[i][j];
            i>=s && j>=s && t>=d[i+1][j+1]-d[i-s][j+1]-d[i+1][j-s]+d[i-s][j-s]}
        {s+=1}} s as i32
    }

18.01.2026

1895. Largest Magic Square medium blog post substack youtube

a0b54509-fbad-4d5b-bbab-028d42549ee3 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1241

Problem TLDR

Max magic square #medium

Intuition

Brute-force is accepted.

Approach

  • can be optimized with prefix sums: sum(a..b) = p[b]-p[a]

Complexity

  • Time complexity: \(O(n^4)\), or O(n^2) with prefix sums

  • Space complexity: \(O(1)\), or O(n^2) to store prefix sums

Code

// 54ms
    fun largestMagicSquare(g: Array<IntArray>) = (min(g[0].size,g.size) downTo 1)
        .first { s -> (0..g.size-s).any { y -> (0..g[0].size-s).any { x -> val o = 0..<s 
            val d =  o.sumOf { g[y+it][x+it] }
                d == o.sumOf { g[y+it][x-it+s-1] } && o.all { i -> 
                d == o.sumOf { g[y+i][x+it] } && 
                d == o.sumOf { g[y+it][x+i] }}}}}
// 7ms
    pub fn largest_magic_square(g: Vec<Vec<i32>>) -> i32 {
        (2..=g.len().min(g[0].len())).rev().find(|&s| 
            iproduct!(0..=g[0].len()-s, 0..=g.len()-s).any(|(x, y)| {
                let d =  (0..s).map(|i| g[y+i][x+i]).sum::<i32>();
                    d == (0..s).map(|i| g[y+i][x+s-1-i]).sum::<i32>() && (0..s).all(|j|
                    d == (0..s).map(|i| g[y+j][x+i]).sum::<i32>() &&
                    d == (0..s).map(|i| g[y+i][x+j]).sum::<i32>())})).unwrap_or(1) as _
    }

17.01.2026

3047. Find the Largest Area of Square Inside Two Rectangles medium blog post substack youtube

977a91cb-099f-459f-a51a-e709a9e03c5e (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1240

Problem TLDR

Max square in intersection #medium

Intuition

Brute-force is accepted. The intersection is max(bottom left) & min(top right)

Approach

  • we also can sort and return inner loop early
  • or freeze the result S length and binary search if it fits
  • or sort and line sweep 2d or with segment tree

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(1)\)

Code

// 350ms
    fun largestSquareArea(a: Array<IntArray>, b: Array<IntArray>) =
        (0..<b.size-1).maxOf { i -> (i+1..<b.size).maxOf { j ->
            (0..1).minOf { min(b[i][it],b[j][it])-max(a[i][it],a[j][it]) }
        }}.let { 1L*it*max(0,it) }
// 77ms
    pub fn largest_square_area(a: Vec<Vec<i32>>, b: Vec<Vec<i32>>) -> i64 {
        a.iter().zip(&b).tuple_combinations().map(|((l1, r1), (l2, r2))| 
             (0..2).map(|k| r1[k].min(r2[k]) - l1[k].max(l2[k])).min().unwrap()
        ).max().map_or(0, |x| (x.max(0) as i64).pow(2))
    }

16.01.2026

2975. Maximum Square Area by Removing Fences From a Field medium blog post substack youtube

85f3cd69-628c-42a4-9194-065e536e30a8 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1239

Problem TLDR

Max square after remove vertical or horizontal bars #medium

Intuition

    // possible horizontal widths
    // intersect
    // possible vertical heights
    //
    // 1D problem: collect possible gaps
    //
    // |*****|**|*|
    //    5    2 1
    // 1,2,5, 1+2, 2+5, 1+2+5
    //             |+1 -- all prev + x
    // 1+1,(1+2)+1,(1+2+5)+1
    // max size is 600, so O(n^2) should be acceptable

Solve 1D problem. Find all possible gaps. Intersect. Pick max.

Approach

  • to find all gaps just use 2d for loop

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n^2)\)

Code

// 648ms
    fun maximizeSquareArea(m: Int, n: Int, h: IntArray, v: IntArray) = listOf(h+1+m,v+1+n)
        .map { buildSet { for (a in it) for (b in it) if (a>b) add(a-b) }}
        .let {(a,b)->a.intersect(b).maxOrNull()}?.let {1L*it*it%1000000007} ?: -1
// 355ms
    pub fn maximize_square_area(m: i32, n: i32, mut h: Vec<i32>, mut v: Vec<i32>) -> i32 {
        let [a,b] = [(h,m),(v,n)].map(|(mut x,y)| {
            let mut s = HashSet::new(); x.extend([1,y]);
            for a in &x { for b in &x { if a > b { s.insert(a-b); }}}; s });
        a.intersection(&b).max().map_or(-1, |&x| ((x as i64*x as i64)%1000000007) as i32)
    }

15.01.2026

2943. Maximize Area of Square Hole in Grid medium blog post substack youtube

fa08aa27-6ff7-4712-a51a-bf99478a31fe (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1238

Problem TLDR

Max square area after removing bars in a grid #medium #intervals

Intuition

Count consequtive intervals separately for horizontal and vertical bars. Then min(max(h,v))^2.

One way: sort bars, count consequtive with counter Second way: use a HashMap(x, length) and update x-l, x+r with 1+m[x-1]+m[x+1]

Approach

  • do +1 or just init counter with 2
  • for the HashMap we can skip writing to the middle m[x]

Complexity

  • Time complexity: \(O(nlog(n))\), or O(n)

  • Space complexity: \(O(1)\) or O(n)

Code

// 22ms
    fun maximizeSquareHoleArea(n: Int, m: Int, h: IntArray, v: IntArray) = 
        listOf(h,v).minOf { val m = HashMap<Int, Int>()
            1 + it.maxOf { x -> val l = m[x-1]?:0; val r = m[x+1]?:0 
                (l+r+1).also{m[x-l]=it;m[x+r]=it}}
        }.let{it*it}
// 0ms
    pub fn maximize_square_hole_area(_: i32, _: i32, h: Vec<i32>, v: Vec<i32>) -> i32 {
        [h, v].map(|s| s.into_iter().sorted().collect::<Vec<_>>()
            .chunk_by(|a, b| b - a < 2).map(|c| c.len() + 1).max().unwrap_or(2)
        ).into_iter().min().unwrap().pow(2) as _
    }

14.01.2026

3454. Separate Squares II hard blog post substack youtube

69c10bcc-e8c8-4421-a110-cd3120604cb5 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1237

Problem TLDR

Min y to equal split areas exclude intersections #hard #line_sweep

Intuition

Didn’t solved.

    // sort by y
    // do a line sweep
    //
    // widths by y
    // 
    // 0 0 0 1 1 2 0 0 3 0 0
    //         i             area before & area after
    //       1*2+2*1+3*1     total
    //                       but how to find min y center?
    //
    // ok let's just start with making a widths list
    // how to merge x segments?
    // ok this is hard for me, let's go to hints
    // gave up after 15 minute

Line sweep by Y. Record (x start, x end) pairs. On each next Y line sweep elapsed x-pairs to find non-overlapping w.

Approach

  • accepted without segment tree

Complexity

  • Time complexity: \(O(nlogn)\), worst-case would be O(n^2log^2(n))

  • Space complexity: \(O(n)\)

Code

// 459ms
    fun separateSquares(s: Array<IntArray>): Double {
        val (e,xlr,slices) = List(3) {ArrayList<List<Double>>()}
        for ((x,y,l) in s) {e+=listOf(1.0*y,1.0,1.0*x,1.0*x+l);e+=listOf(1.0*y+l,0.0,1.0*x,1.0*x+l)}
        e.sortBy { it[0] }; var prev = 0.0; var total = 0.0
        for ((y,e,xl,xr) in e) {
            if (y > prev) {
                xlr.sortBy {it[0]}; var w = 0.0; var x = 0.0
                for ((l,r) in xlr) if (x<r) { w += r - max(x,l); x = r }
                slices += listOf(total, prev, y-prev, w); total += (y-prev)*w
            }
            prev = y; if (e>0) xlr += listOf(xl,xr) else xlr -= listOf(xl,xr)
        }
        val (cur,sy,h,w) = slices.first { (cur, sy,h,w) -> cur + h * w >= total/2  }
        return (total/2 - cur) / w + sy
    }
// 373ms
    pub fn separate_squares(s: Vec<Vec<i32>>) -> f64 {
        let mut ev: Vec<_> = s.iter().flat_map(|v| {
        let (x, y, l) = (v[0] as f64, v[1] as f64, v[2] as f64); [(y,1,x,x+l),(y+l,-1,x,x+l)]}).collect();
        ev.sort_by(|a, b| a.0.total_cmp(&b.0)); let (mut xlr, mut sl, mut tot, mut py) = (vec![], vec![], 0., 0.);
        for (y, op, l, r) in ev {
            if y > py {
                xlr.sort_by(|a: &(f64, f64), b| a.0.total_cmp(&b.0));
                let (mut w, mut mx) = (0., 0.);
                for &(al, ar) in &xlr { if mx < ar { w += ar - mx.max(al); mx = ar}}
                sl.push((tot, py, y - py, w)); tot += (y - py) * w; py = y
            }
            if op > 0 { xlr.push((l, r)); } 
            else { xlr.remove(xlr.iter().position(|&x| x == (l, r)).unwrap()); }
        }
        let (cur, y, _, w) = sl.into_iter().find(|&(c, _, h, w)| c + h * w >= tot / 2.).unwrap();
        (tot / 2. - cur) / w + y
    }

13.01.2026

3453. Separate Squares I medium blog post substack youtube

ff3c746d-2626-425a-bc74-3098fa8a7666 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1236

Problem TLDR

Min Y to split into equal areas #medium #bs

Intuition

    // 1. binary search, but with doubles
    // 2. idk about any other ideas
    // 3. why do we need X coordinate?
    //
    // binary search gives wrong result on big numbers
    // ok 22 minute, lets read hints - "binary search"
    // so, no extra hints
    // overflow
    // 
    // ok 50 minutes, let's gave up

Binary search on Y, compare the below and above areas.

Approach

  • carefull with overflow l*l

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 94ms
    fun separateSquares(s: Array<IntArray>): Double {
        var lo = 0.0; var hi = 1000000000.0; val t = s.sumOf {1.0*it[2]*it[2]}/2
        while (abs(lo - hi) > 0.00001) {
            val m = lo + (hi - lo) / 2.0
            if (s.sumOf{(x,y,l)->if(m>y)min(m-y,1.0*l)*l else 0.0}>=t) hi = m else lo = m
        }
        return lo
    }
// 96ms
    pub fn separate_squares(s: Vec<Vec<i32>>) -> f64 {
        let (mut l, mut h, t) = (0.,1e9, s.iter().map(|v| v[2]as f64 * v[2] as f64).sum::<f64>()/2.);
        while h - l > 1e-5 {
            let m = (l + h) / 2.;
            if t > s.iter().map(|v| {
                    let (y,s) = (v[1] as f64, v[2] as f64);
                    if m > y { (m - y).min(s) * s } else { 0. }
                }).sum::<f64>() { l = m } else { h = m }
        } l
    }

12.01.2026

1266. Minimum Time Visiting All Points easy blog post substack youtube

cf961b43-5360-4846-bd81-549443325d86 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1235

Problem TLDR

Euclid travel distance #easy #brainteaser

Intuition

D = max(dx,dy)

Approach

  • indices: [1..n)
  • zip, zipWithNext, windows, fold

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 6ms
    fun minTimeToVisitAllPoints(p: Array<IntArray>) = (1..<p.size)
    .sumOf {i->max(abs(p[i][0]-p[i-1][0]), abs(p[i][1]-p[i-1][1]))}
// 0ms
    pub fn min_time_to_visit_all_points(p: Vec<Vec<i32>>) -> i32 {
        p.iter().zip(&p[1..]).map(|(a,b)|(a[0]-b[0]).abs().max((a[1]-b[1]).abs())).sum()
    }

11.01.2026

85. Maximal Rectangle hard blog post substack youtube

c5a04d2d-e0ec-4ee9-8db9-4eed14f73561 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1234

Problem TLDR

Max all-1 rectangle in 2D matrix #hard #monotonic_stack

Intuition

The histogram solution: use monotonic increasing stack for each row. Update result when popping values from it.

Approach

  • to avoid duplicated code after the row is finished, use sentinel 0 or just one extra iteration
  • we can store heights in a separate array or just modify matrix
  • for the left x coordinate use the value before popped value

Complexity

  • Time complexity: \(O(nm)\)

  • Space complexity: \(O(m)\)

Code

// 31ms
    fun maximalRectangle(m: Array<CharArray>) = Stack<Int>().run {
        var res = 0; for (y in m.indices) for (x in 0..m[0].size) {
            if (y>0&&x<m[0].size) if (m[y][x]>'0')m[y][x]+=m[y-1][x]-'0'
            while (size > 0 && (x==m[0].size||m[y][peek()]>m[y][x])) 
                res = max(res, (m[y][pop()]-'0')*(x-if(size>0)peek()+1 else 0))
            if (x < m[0].size) this += x else clear()
        }; res
    }
// 0ms
    pub fn maximal_rectangle(mut m: Vec<Vec<char>>) -> i32 {
        let (mut q, mut r) = (vec![], 0);
        for y in 0..m.len() { for x in 0..=m[0].len() {
            if y > 0 && x < m[0].len() { if m[y][x] > '0' { m[y][x] = ('1' as u8 + (m[y-1][x] as u8 -b'0'))as char}}
            while q.len() > 0 && (x == m[0].len() || m[y][q[q.len()-1]] > m[y][x]) {
                r = r.max((m[y][q.pop().unwrap()]as u8 -b'0')as i32 * if q.len()>0 {x-q[q.len()-1]-1} else {x}as i32)}
            if x < m[0].len() { q.push(x) } else { q.clear() }
        }} r
    }

10.01.2026

712. Minimum ASCII Delete Sum for Two Strings medium blog post substack youtube

2beff096-6071-468f-934f-c4137d076ed3 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1233

Problem TLDR

Min removed sum to make strings equal #medium #dp

Intuition

One way: DP[i][j] is the removed sum for suffix a[i..],b[j..], take a[i] or b[j] when a[i]!=b[j].

Second way: DP[i][j] is the Longest Common Substring for suffix a[i..],b[j..], take a[i] when a[i]==b[j].

Approach

  • the DFS top-down is easier to write
  • space optimize with i%2 trick: only the last row is needed
  • forward write to simplify indices dp[i+1][j+1] = … a[i],b[j]

Complexity

  • Time complexity: \(O(nm)\)

  • Space complexity: \(O(m)\)

Code

// 30ms
    fun minimumDeleteSum(a: String, b: String): Int {
        val d = Array(2) { IntArray(b.length+1) }
        for (i in a.indices) for (j in b.indices) d[(i+1)%2][j+1] = 
            if (a[i] == b[j]) a[i].code + d[i%2][j] else max(d[i%2][j+1], d[(i+1)%2][j])
        return a.sumOf{it.code}+b.sumOf{it.code}-2*d[a.length%2][b.length]
    }
// 3ms
    pub fn minimum_delete_sum(a: String, b: String) -> i32 {
        let (a, b, mut d) = (a.as_bytes(), b.as_bytes(), vec![vec![0; b.len() + 1]; 2]);
        for j in 0..b.len() { d[0][j + 1] = d[0][j] + b[j] as i32 }
        for i in 0..a.len() { for j in 0..=b.len() { d[(i + 1) & 1][j] =
            if j < 1 { d[i & 1][0] + a[i] as i32 } else if a[i] == b[j - 1] { d[i & 1][j - 1] }
            else { (a[i] as i32 + d[i & 1][j]).min(b[j - 1] as i32 + d[(i + 1) & 1][j - 1]) }
        }}
        d[a.len() & 1][b.len()]
    }

09.01.2026

865. Smallest Subtree with all the Deepest Nodes medium blog post substack youtube

70318a61-7859-48b4-9d91-94eef697bd89 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1232

Problem TLDR

Lowest common ancestor of the deepest nodes #medium

Intuition

Do a DFS. One way: propagate depth down, compare on the way up. Second way: return both depth & result on the way up.

Approach

  • how to use uniqness?

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(logn)\)

Code

// 1ms
    fun subtreeWithAllDeepest(r: TreeNode?): TreeNode? {
        fun dfs(n: TreeNode?): Pair<Int, TreeNode?> = n?.run {
            val (l, a) = dfs(left); val (r, b) = dfs(right)
            (1 + max(l, r)) to if (l > r) a else if (l < r) b else n
        } ?: 0 to null
        return dfs(r).second
    }
// 0ms
    pub fn subtree_with_all_deepest(r: Option<Rc<RefCell<TreeNode>>>) -> Option<Rc<RefCell<TreeNode>>> {
        fn dfs(ro: &Option<Rc<RefCell<TreeNode>>>, d: i32, max: &mut i32, res: &mut Option<Rc<RefCell<TreeNode>>>) -> i32 {
            let Some(n) = ro else { return d }; let n = n.borrow();
            let (l,r) = (dfs(&n.left, d+1, max, res), dfs(&n.right, d+1, max, res));  *max = l.max(r).max(*max);
            if l == *max && r == *max { *res = ro.clone() }; l.max(r)
        }
        let (mut max, mut res) = (0, None); dfs(&r, 0, &mut max, &mut res); res
    }

08.01.2026

1458. Max Dot Product of Two Subsequences hard blog post substack youtube

f5ec9834-1013-4da3-bdd2-385fe23dd48d (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1231

Problem TLDR

Max product of 2 subsequencies #hard #dp

Intuition

The solution is stable for every suffix (a[i..],b[j..]), memoize by the key of (i,j).

Approach

  • use forward trick to not check the bounds dp[i+1]=dp[i]…
  • use ‘stop here’ trick to handle negatives a[i]*b[j] + 0 instead of calling dfs(i+1,j+1)
  • as we only accessing +-1, we can store just one recent row of dp instead of a full table

Complexity

  • Time complexity: \(O(nm)\)

  • Space complexity: \(O(m)\)

Code

// 17ms
    fun maxDotProduct(a: IntArray, b: IntArray): Int {
        val d = Array(2) { IntArray(b.size+1) { -1000000 }}
        for (i in a.indices) for (j in b.indices) d[(i+1)%2][j+1] = 
            maxOf(d[(i+1)%2][j], d[i%2][j+1], a[i]*b[j], a[i]*b[j]+d[i%2][j])
        return d[a.size%2][b.size]
    }
// 0ms
    pub fn max_dot_product(a: Vec<i32>, b: Vec<i32>) -> i32 {
        let mut d = vec![vec![-1000000;b.len()+1];2];
        for i in 0..a.len() { for j in 0..b.len() {
            d[(i+1)&1][j+1] = d[(i+1)&1][j].max(d[i&1][j+1]).max(a[i]*b[j]).max(a[i]*b[j]+d[i&1][j])
        }} d[a.len()&1][b.len()]
    }

07.01.2026

1339. Maximum Product of Splitted Binary Tree medium blog post substack youtube

cc4ddd10-55f6-4511-819b-97e43c288f51 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1230

Problem TLDR

Max sumA*sumB of a tree split #medium

Intuition

Find the total sum, then subtract each subtree to find the other sum.

Approach

  • we can calculate in 32 bit if use extemum of x = s/2
  • we can collect visited sums into a hashset
  • we can skip sums that are smaller than max/2
  • the fastest runtime speed is still calculation of x*(max-x) in-place

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(logn)\)

Code

// 11ms
    fun maxProduct(r: TreeNode?): Long {
        val a = ArrayList<Int>()
        fun s(r: TreeNode?): Int = r
            ?.run {val s = s(left)+s(right)+`val`; a += s; s}?:0
        val s = s(r); return a.maxOf {1L*it*(s-it)}%1000000007
    }
// 3ms
    pub fn max_product(r: Option<Rc<RefCell<TreeNode>>>) -> i32 {
        fn s(r: &Option<Rc<RefCell<TreeNode>>>, res: &mut i64, max: &mut i32) -> i32 {
            let Some(n) = r else { return 0 }; let n = n.borrow();
            let s = s(&n.left,res,max)+s(&n.right,res,max)+n.val; *max = s.max(*max);
            *res = (*res).max(s as i64*(*max - s)as i64); s
        }
        let (mut res,mut max) = (0,0); for _ in 0..2 {s(&r, &mut res, &mut max);} (res%1000000007) as i32
    }

06.01.2026

1161. Maximum Level Sum of a Binary Tree medium blog post substack youtube

142eb616-0647-486f-ae28-ff010de3fe01 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1229

Problem TLDR

Min level max sum in tree #medium

Intuition

Use BFS or DFS.

Approach

  • compute max only after all number are added in this level

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 34ms
    fun maxLevelSum(r: TreeNode?) = ArrayDeque<TreeNode>().let { q ->
        q += r!!; (1..25).maxBy { if (q.size < 1) -100001 else
            (1..q.size).sumOf { q.removeFirst().run {
                left?.let { q += it }; right?.let { q += it }; `val`
            }}
        }
    }
// 6ms
    pub fn max_level_sum(r: Option<Rc<RefCell<TreeNode>>>) -> i32 {
        let (mut m, mut ml) = ([0;27],0);
        fn dfs(m: &mut[i32], ml: &mut usize, l: usize, n: &Option<Rc<RefCell<TreeNode>>>) {
            let Some(n) = n else { return }; if l > 25 { return }; let n = n.borrow();
            m[l] += n.val; *ml = l.max(*ml); dfs(m, ml, l+1, &n.left); dfs(m, ml, l+1, &n.right)
        }
        dfs(&mut m, &mut ml, 0, &r); -(0..=ml).map(|i|(m[i],-(i as i32)-1)).max().unwrap().1
    }

05.01.2026

1975. Maximum Matrix Sum medium blog post substack youtube

6f7a2399-202e-420c-a2f8-a9ea9b74892d (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1226

Problem TLDR

Max sum after multiply -1 adjacent cells #medium #brainteaser

Intuition

Notice that we can move “-“ to any cell in the matrix. Count “-“, find sum and find minimum value to subtract.

    // we can propagate - to any cell
    // if even -- count then all positive
    // otherwise make it the smallest abs

Approach

  • don’t forget to subtract 2*min

Complexity

  • Time complexity: \(O(m)\)

  • Space complexity: \(O(1)\)

Code

// 9ms
    fun maxMatrixSum(m: Array<IntArray>): Long {
        var cnt = 0; var min = Int.MAX_VALUE
        return m.sumOf { it.sumOf { v ->
            if (v < 0) cnt++
            min = min(min, abs(v)); abs(v).toLong()
        }} - (cnt%2)*2*min
    }
// 0ms
    pub fn max_matrix_sum(m: Vec<Vec<i32>>) -> i64 {
        let (mut c, mut min) = (0, i64::MAX);
        m.iter().map(|r| r.iter().map(|&x|{ let v = x.abs() as i64;
            min = min.min(v); c += (x < 0) as i64; v
        }).sum::<i64>()).sum::<i64>() - 2*min*(c&1)
    }

04.12.2025

1390. Four Divisors medium blog post substack youtube

55965326-ca03-4961-b37a-c13ca29fecc8 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1225

Problem TLDR

Sum of exactly four-divisors of each number #medium #math

Intuition

Brute-force divisors up to sqrt(n) for each number.

    // math problem
    // lets brute-force?
    // two is 1 and number itself; two others we should find
    //
    // strange case: [7286,18704,70773,8224,91675] 10932
    // 10932 = 8224 + 1 + a + b
    // a*b = 10932
    //
    // 10932 = 8224 + 1 + 10932/b + b
    //
    // divisors are uniq    for 4: 1 2 4, 2 is collapsed
    //
    // ok 27 minute looking for hints
    // ok they suggest brute-force O(nsqrt(n))
    //

Approach

  • another way: pre-find all divisors for 1..max

Complexity

  • Time complexity: \(O(nsqrt(n))\)

  • Space complexity: \(O(1)\)

Code

// 33ms
    fun sumFourDivisors(n: IntArray) = n.sumOf { n ->
        var f = 0; var x = 1; var s = 1+n
        while (++x*x <= n) if (n%x==0) {++f;s += x+n/x}
        if (f==1&&--x*x<n) s else 0
    }
// 31ms
    pub fn sum_four_divisors(n: Vec<i32>) -> i32 {
        let m = *n.iter().max().unwrap() as usize;
        let (mut c, mut s, mut r) = (vec![0; m+1], vec![0;m+1], 0);
        for a in 1..=m { for v in (a..=m).step_by(a) {c[v]+=1; s[v]+=a as i32}}
        n.iter().map(|&n|if (c[n as usize]==4) {s[n as usize]}else{0}).sum::<i32>()
    }

03.12.2026

1411. Number of Ways to Paint N × 3 Grid hard blog post substack youtube

9d53a2e8-6017-47e7-aa21-83a85dfd80e1 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1224

Problem TLDR

Ways to color 3xN grid #hard #dp

Intuition

Do DFS + dp. The state is current cell and 3 previous colors.

Approach

  • optimization 1: there are only two patterns A -> 2A+2B, B -> 2A+3B
  • optimization 2: exponentiation matrix for O(log(n)) solution. Skipped this, too hard to implement

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 1ms
    fun numOfWays(n: Int): Long {
        var a = 6L; var b = a; val M = 1000000007
        for (i in 2..n) { a += (a+b+b)%M; b += a }
        return (a+b)%M
    }
// 20ms
    pub fn num_of_ways(n: i32) -> i32 {
        let mut dp = vec![-1;(n*192) as usize];
        fn dfs(dp: &mut [i32], i: i32, m: i32, n: i32) -> i32 {
            if i == n { return 1 }; let k = ((i<<6)|m) as usize; if dp[k] != -1 { return dp[k] }
            let res = ((0..3).map(|c|
                if i%3>0 && c==m&3 || i>=3&&c==m>>4 {0} else { dfs(dp,i+1,((m<<2)|c)&63,n)as i64}
            ).sum::<i64>()%1000000007) as i32; dp[k] = res; res
        }
        dfs(&mut dp, 0, 0, 3*n)
    }

02.01.2026

961. N-Repeated Element in Size 2N Array easy blog post substack youtube

050f42ea-ddaf-4223-be5b-5384a627223e (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1223

Problem TLDR

Duplicate majority element #easy

Intuition

The easy intuition is just to count frequencies.

Approach

  • frequency of 2 is enough
  • if first element skipped then majority voting solution applicable
  • another fun solution is to look at sum and uniq’s sum

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 35ms
    fun repeatedNTimes(n: IntArray) =
        (n.sum() - n.toSet().sum())/(n.size/2-1)
// 0ms
    pub fn repeated_n_times(n: Vec<i32>) -> i32 {
        let (mut j, mut f) = (0, 0);
        n[(1..n.len()).find(|&i| {
            if f == 0 { j = i }
            f += (n[0]==n[i]||n[i]==n[j]) as i32 * 2 -1; f > 1
        }).unwrap_or(j)]
    }

01.01.2026

66. Plus One easy blog post substack youtube https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html c9513975-0f11-4aac-af43-cf8d3f5dbf95 (1).webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1222

Problem TLDR

Increment big number #easy

Intuition

The simplest and robust solution is a separate container for result digits and a counter for carry.

Approach

  • optimization: stop at first non-nine
  • optimization: count suffix nines in a forward cache-friendly pass

    Complexity

  • Time complexity: \(O(n)\)
  • Space complexity: \(O(n)\)

    Code

    // 0ms
      fun plusOne(d: IntArray): IntArray {
          for (i in d.size-1 downTo 0) if (d[i]<9) {++d[i]; return d} else d[i]=0 
          return IntArray(d.size+1).also {it[0]=1}
      }
    
    // 0ms
      pub fn plus_one(mut d: Vec<i32>) -> Vec<i32> {
          let (mut c,n) = (0,d.len()); for &d in &d {if d < 9 {c=0} else {c+=1}}
          if c==n { let mut r = vec![0;c+1];r[0]=1; return r}
          d[n-c..n].fill(0); d[n-c-1] += 1; d
      }
    

31.12.2025

1970. Last Day Where You Can Still Cross hard blog post substack youtube

8e112f71-96d8-43bf-bc42-2dc7f46a2be2 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1221

Problem TLDR

Last day top connected to bottom in 2D matrix #hard #uf

Intuition

Invert the problem: go from back and the list becames a “rain of the ground cells”.

Approach

  • we can store ground bits inside union-find jump array as an extra bit

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 68ms
    val u=IntArray(21000){it*2}; fun f(a:Int):Int=if(u[a]/2==a)a else f(u[a]/2).also{u[a]=it*2+u[a]%2}
    fun latestDayToCross(r: Int, c: Int, cs: Array<IntArray>) = (cs.lastIndex downTo 0).first { i ->
        val (y,x)=cs[i]; val s = 1+2*f(if(y==1)0 else if(y==r)2 else y*c+x); u[y*c+x]=s
        for ((x1,y1) in arrayOf(x-1 to y, x+1 to y, x to y-1, x to y+1)) 
            if (y1 in 1..r && x1 in 1..c && u[y1*c+x1]%2>0) u[f(y1*c+x1)] = s
        f(0) == f(2)
    }
// 14ms
    pub fn latest_day_to_cross(r: i32, c: i32, cs: Vec<Vec<i32>>) -> i32 {
        let (r, c) = (r as usize, c as usize); let mut u: Vec<_> = (0..r*c+c+1).map(|i| i * 2).collect();
        fn f(u: &mut Vec<usize>, a: usize)->usize{if u[a]/2==a{a}else{let t=f(u,u[a]/2);u[a]=t*2+u[a]%2;t}}
        (0..cs.len()).rev().find(|&i| {
            let (y, x) = (cs[i][0] as usize, cs[i][1] as usize);
            let s = 1+2*f(&mut u,if y==1 {0} else if y == r {2} else {y * c + x}); u[y * c + x] = s;
            for (dx, dy) in [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)] {
                if dy >= 1 && dy <= r && dx >= 1 && dx <= c && u[dy * c + dx] % 2 > 0 
                    { let r = f(&mut u, dy * c + dx); u[r] = s }}
            f(&mut u, 0) == f(&mut u, 2)
        }).map(|i| i as i32).unwrap_or(-1)
    }

30.12.2025

840. Magic Squares In Grid medium blog post substack youtube

5252578a-5336-4593-b996-35ed7a689f29 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1220

Problem TLDR

Count ‘magic’ 3x3 squares #medium

Intuition

Brute-force.

Approach

  • we can enumerate each cell and translate into original matrix m[y-1][x-1] shift by y1,x1 of the magic cell

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 24ms
    fun numMagicSquaresInside(g: Array<IntArray>) =
        (1..<g.size-1).sumOf { y -> (1..<g[0].size-1).count { x ->
            "012345678036147258048246".map { g[y-1+(it-'0')/3][x-1+(it-'0')%3] }
            .run {toSet().size==9 && all{it in 1..9} && chunked(3).all{it.sum()== 15}}
        }}
// 0ms
    pub fn num_magic_squares_inside(g: Vec<Vec<i32>>) -> i32 {
        (1..g.len()-1).map(|y|(1..g[0].len()-1).filter(|&x|{
            let v=[0,1,2,3,4,5,6,7,8,0,3,6,1,4,7,2,5,8,0,4,8,2,4,6]
                .map(|i| g[y-1+i/3][x-1+i%3]); let mut m=0u16; 
            v[..9].iter().all(|&t|0<t&&t<=9&&{m&1<<t<1&&{m|=1<<t;true}})
            && v.chunks(3).all(|c|c.iter().sum::<i32>()==15)
        }).count()as i32).sum()
    }

29.12.2025

756. Pyramid Transition Matrix medium blog post substack youtube

a2c53c7b-0476-42f6-8094-e3142145e06c (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1219

Problem TLDR

Can build a pyramid from transitions? #medium #backtracking

Intuition

DFS for each row. DFS with backtracking for each transition character in the row.

Approach

  • speedup with arena allocation
  • speedup with Int keys: A«16 B
  • speedup with transitions matrix bitset: M[A][B] = bitmask
  • speedup with HashSet of bad keys

Complexity

  • Time complexity: \(O(b^a)\)

  • Space complexity: \(O(b^2)\)

Code

// 15ms
    fun pyramidTransition(b: String, a: List<String>): Boolean {
        val m = IntArray(26 * 26); var j = b.length; val bad = HashSet<Long>()
        val r = IntArray(j * (j + 1) / 2) { b[it % j] - 'A' }
        for (s in a) { val x = s[0]-'A'; val y = s[1]-'A'; m[x*26+y] = m[x*26+y] or (1 shl (s[2]-'A'))}
        fun dfs(st: Int, sz: Int, key: Long): Boolean {
            if (j == r.size) return true; if (key in bad) return false
            if (j == st + sz + 1 + sz) return dfs(j - sz, sz - 1, key)
            var mask = m[r[j - sz - 1] * 26 + r[j - sz]]
            while (mask > 0) {
                val c = mask.countTrailingZeroBits(); mask = mask and (mask - 1); r[j++] = c
                if (dfs(st, sz, key or (c.toLong() shl ((j-st-sz)*5)))) return true; --j
            }
            bad.add(key); return false
        }
        return dfs(0, j - 1, 0)
    }
// 400ms
    fun pyramidTransition(b: String, a: List<String>): Boolean {
        val a = a.groupBy({ it.take(2) },{it[2]})
        fun dfs(b: List<Char>): Boolean {
            val r = ArrayList<Char>()
            fun dfs2(i: Int): Boolean = if (i == b.size) dfs(r) else a["${b[i-1]}${b[i]}"]
                ?.any { r += it; val n = dfs2(i+1); r.removeLast(); n } == true
            return b.size == 1 || dfs2(1)
        }
        return dfs(b.toList())
    }
// 0ms
    pub fn pyramid_transition(b: String, a: Vec<String>) -> bool {
        let (mut m, mut j, mut bad) = ([0u32; 26 * 26], b.len(), HashSet::<u64>::new());
        for s in a { let t = s.as_bytes(); m[(t[0]-b'A')as usize*26 + (t[1]-b'A')as usize] |= 1u32<<(t[2]-b'A')}
        let mut r = vec![0u8; j*(j+1)/2]; for (i,&c) in b.as_bytes().iter().enumerate() {r[i] = c - b'A'}
        fn dfs(m: &[u32; 26 * 26], r: &mut [u8], j: &mut usize, st: usize, sz: usize, key: u64, bad: &mut HashSet<u64>) -> bool {
            if *j == r.len() { return true }; if *j == st+sz+1+sz { return dfs(m, r, j, *j-sz, sz-1, key, bad)}
            if bad.contains(&key) { return false }
            let mut mask = m[r[*j - sz - 1] as usize * 26 + r[*j - sz] as usize];
            while mask != 0 {
                let c = mask.trailing_zeros() as u8; mask &= mask - 1; r[*j] = c; *j += 1;
                if dfs(m, r, j, st, sz, key | ((c as u64) << ((*j-st-sz-2)*5)), bad) { return true }; *j -= 1;
            }
            bad.insert(key); false
        }
        dfs(&m, &mut r, &mut j, 0, b.len() - 1, 0, &mut bad)
    }

28.12.2025

1351. Count Negative Numbers in a Sorted Matrix easy blog post substack youtube

6740ea68-029c-43e8-a7e2-f5ebb31cbb30 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1218

Problem TLDR

Count negatives in 2D sorted matrix #easy

Intuition

Brute force. Improve with either:

  • binary search
  • n+m walk on border of negatives

Approach

  • use list.binarySearch {..} in Kotlin or partition_point in Rust

Complexity

  • Time complexity: \(O(nlogm)\)

  • Space complexity: \(O(nm)\)

Code

// 15ms
    fun countNegatives(g: Array<IntArray>) =
        g.sumOf { g[0].size+1+it.asList().binarySearch { if (it < 0) 1 else -1 } }
// 0ms
    pub fn count_negatives(g: Vec<Vec<i32>>) -> i32 {
        g.iter().map(|r| { (r.len() - r.partition_point(|&x| x >= 0)) as i32 }).sum()
    }

27.12.2025

2402. Meeting Rooms III hard blog post substack youtube

cc702986-a82b-4991-85ce-33ea0204d7ae (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1217

Problem TLDR

Most frequent room 0..n for meetings [s,e] #hard #heap

Intuition

    // 0 1 2 3 4 5 6 7 8 9 10
    // * * * * * * * * * * *   a
    //   * * * * *             b
    //           * * * * * *   b
    //                     * * a
    //
    // time is complicated
    //
    // some corner case i didn't see
    //
    // 0 1 2 3 4 5 6 7 8 9 10
    //   * * * * * * * * * *  a
    //     * * * * * * * * *  b
    //                     * * * * * * * *  a 
    //                       * * * * * * *  b
    //                                   * * * * * * a 
    //                                     * * * * * b

Approach

Complexity

  • Time complexity: \(O(nmlogm)\)

  • Space complexity: \(O(n)\)

Code

// 269ms
    fun mostBooked(n: Int, m: Array<IntArray>): Int {
        m.sortBy { it[0] }; val f = IntArray(n); val t = LongArray(n)
        for ((s,e) in m) {
            val room = (0..<n).firstOrNull { t[it] <= s } ?: t.indexOf(t.min())
            t[room] = 1L*e + max(0, t[room]-s)
            ++f[room]
        }
        return f.indexOf(f.max())
    }
// 33ms
    pub fn most_booked(n: i32, mut m: Vec<Vec<i32>>) -> i32 {
        m.sort(); let (mut f, mut t, n) = ([0; 100], [0; 100], n as usize);
        for m in m { 
            let (s, e, mut i, mut j, mut m) = (m[0] as i64, m[1] as i64, -1, -1, i64::MAX); 
            for r in 0..n { if t[r] <= s { j = r as i32; break }; if t[r] < m { i = r as i32; m = t[r] }}
            let room = i.max(j) as usize; t[room] = e + 0.max(t[room] - s); f[room] += 1
        } 
        (0..n).max_by_key(|&i| (f[i],Reverse(i))).unwrap() as _
    }

26.12.2025

2483. Minimum Penalty for a Shop medium blog post substack youtube

cc090fff-c7c3-4399-aa61-414eaa4ba39f (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1216

Problem TLDR

Min close time by customers max volune #medium #counting

Intuition

Track of the customers volune running sum. YN pairs didn’t change the volume.

Approach

  • ‘Y’-‘N’=11
  • baseline can be anything

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 19ms
    fun bestClosingTime(c: String): Int {
        var v = 1337 
        return (0..c.length).maxBy { v += 2*(c[max(0,it-1)]-'N')/10-1; v }
    }
// 0ms
    pub fn best_closing_time(c: String) -> i32 {
        let mut v = 404;
        (0..=c.len()as i32).max_by_key(|&i|{
            v += 2 * (c.as_bytes()[0.max(i-1) as usize]==b'Y')as i32-1; (v,-i)
        }).unwrap()
    }

25.12.2025

3075. Maximize Happiness of Selected Children medium blog post substack youtube

75aecedd-9c48-4d4c-8be0-6480c83821ea (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1215

Problem TLDR

K max values, decreas each pick #medium #quickselect

Intuition

Sort and pick K largest.

Approach

  • optimize with quickselect
  • we still have to sort K items to check 0 overflow

Complexity

  • Time complexity: \(O(n + klog(k))\), for optimal; the simplest is O(nlogn)

  • Space complexity: \(O(1)\)

Code

// 693ms
    fun maximumHappinessSum(h: IntArray, k: Int) =
        h.sortedDescending().take(k).withIndex().sumOf {(i,h)->max(0,1L*h-i)}
// 12ms
    pub fn maximum_happiness_sum(mut h: Vec<i32>, k: i32) -> i64 {
        h.sort_unstable_by(|a,b|b.cmp(a));
        h.iter().zip(0..k).map(|(h,i)|0.max(h-i)as i64).sum()
    }
// 18ms
    pub fn maximum_happiness_sum(mut h: Vec<i32>, k: i32) -> i64 {
        let (l,m,_) = h.select_nth_unstable_by_key(k as usize-1, |h|-h); 
        l.sort_unstable_by(|a,b|b.cmp(a));
        l.iter().chain(once(&*m)).zip(0..).map(|(h,i)|0.max(h-i)as i64).sum()
    }

24.12.2025

3074. Apple Redistribution into Boxes easy blog post substack youtube

b4baba22-df27-4293-96e0-a74d93d0bb8d (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1214

Problem TLDR

Min containers for all apples #easy #counting_sort

Intuition

Sum all apples. Take largest containers first.

Approach

  • (1..51).first for number of containers
  • sort by counting

Complexity

  • Time complexity: \(O(sort)\), the sort can be NlogN or N for counting

  • Space complexity: \(O(sort)\), Kotlin’s IntArray.sort is O(1) space complexity

Code

// 29ms
    fun minimumBoxes(a: IntArray, c: IntArray) =
        (1..c.size).first { a.sum() <= c.sortedDescending().take(it).sum() }
// 0ms
    pub fn minimum_boxes(a: Vec<i32>, c: Vec<i32>) -> i32 {
        let mut s = a.iter().sum::<i32>(); let mut f = [0;51];
        for c in c { f[c as usize] += 1 }; let mut j = 50;
        (1..51).find(|i| { while f[j] < 1 { j-=1 }; s -= j as i32; f[j] -= 1; s <= 0}).unwrap() as _
    }

23.12.2025

2054. Two Best Non-Overlapping Events medium blog post substack youtube

f7189f0f-5937-475d-86fd-2483ce267166 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1213

Problem TLDR

Max at most two non-overlapping events #medium #prefix_max #bs #pq

Intuition

    // ************
    // *****
    //  *****
    //   *****
    //    *****
    //     *****
    //     .*****
    //     . *****
    //
    // need a way to map[time][maxv]
  • One way: sort by starts, put visited into PriorityQueue, poll by ends
  • Another way: sort by ends, put visited into prefix-max list, binary search start in ends

Approach

  • the prefix-max requires initial (0,0) value
  • there is also a suffix-max solution

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n)\)

Code

// 135ms
    fun maxTwoEvents(e: Array<IntArray>): Int {
        var max = 0; val q = PriorityQueue<Int>(compareBy{e[it][1]})
        return e.indices.sortedBy { e[it][0]}.maxOf { i ->
            while (q.size > 0 && e[q.first()][1] < e[i][0])
                max = max(max, e[q.poll()][2])
            q += i; e[i][2] + max
        }
    }
// 10ms
    pub fn max_two_events(mut e: Vec<Vec<i32>>) -> i32 {
        let mut max = vec![(0,0)]; e.sort_unstable_by_key(|e|e[1]);
        e.iter().map(|e|{
            max.push((max[max.len()-1].0.max(e[2]), e[1])); 
            e[2] + max[max.partition_point(|m| m.1 < e[0]) - 1].0
        }).max().unwrap()
    }

22.12.2025

960. Delete Columns to Make Sorted III hard blog post substack youtube

d2dae9ed-5e4f-4520-87e5-b73d466bacf1 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1212

Problem TLDR

Remove columns to sort strings #hard #dp

Intuition

    // a b c
    // c b c
    // c a b
    //
    // i think just removing column greedily is not optimal
    //
    // a b c d e a
    // e a b c d e

    // **..*** we have sorted and usorted parts
    // *.**... they can overlap
    // abxycde find minimum to remove to make sorted? LIS?
    //         acceptance rate is 67% am i overthinking it?
    //
    // maybe it is dp, the tail should be all sorted
    // 28minute; look at hints; ok it is a LIS and is a DP

Top down dp: take i or skip it, compare with previous j.

Approach

  • 1-D dp, build longest substring: lookup prefixes to increase the length dp[j]+1
  • 1-D dp, minimum removals: lookup prefixes to find min removals dp[j]+i-j-1 (more tricky with initial conditions)

Complexity

  • Time complexity: \(O(n^3)\)

  • Space complexity: \(O(n^2)\) or n^2 optimized

Code

// 20ms
    fun minDeletionSize(s: Array<String>): Int {
        val d = HashMap<Int, Int>()
        fun dfs(i: Int, j: Int): Int = if (i == s[0].length) 0 else d.getOrPut(i*100+j) {
            val skip = 1 + dfs(i + 1, j)
            val take = if (j < 0 || s.all {it[j] <= it[i]}) dfs(i+1,i) else 100
            min(skip, take)
        }
        return dfs(0, -1)
    }
// 1ms
    pub fn min_deletion_size(s: Vec<String>) -> i32 {
        let m = s[0].len(); let mut d: Vec<_> = (0..m+2).collect();
        for i in 2..m+2 { for j in 1..i {
            if i > m || s.iter().all(|r| r[j-1..=j-1] <= r[i-1..=i-1]) {
                d[i] = d[i].min(d[j] + i - j - 1);
        }}} d[m+1] as i32 -1
    }

21.12.2025

955. Delete Columns to Make Sorted II medium blog post substack youtube

189f24be-def7-4a1c-9ebe-7cdf61e00950 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1211

Problem TLDR

Remove columns to sort strings #medium

Intuition

The brute-force works. Build the strings column by column and either accept the current column or not.

Approach

  • optimization: keep only rows that have equal chars

Complexity

  • Time complexity: \(O(n^3)\) or n^2 optimized

  • Space complexity: \(O(n^2)\) or n oprimized

Code

// 32ms
    fun minDeletionSize(s: Array<String>): Int {
        var res = List(s.size) { "" }
        return s[0].indices.count { i ->
            val r = res.zip(s).map { (a,b) -> a + b[i] }
            (1..<s.size).any { r[it-1] > r[it] }.also { if (!it) res = r }
        }
    }
// 0ms
    pub fn min_deletion_size(s: Vec<String>) -> i32 {
        let mut js: Vec<_> = (1..s.len()).collect();
        (0..s[0].len()).filter(|&i| {
            let rm = js.iter().any(|&j| s[j-1].as_bytes()[i] > s[j].as_bytes()[i]);
            if !rm { js.retain(|&j| s[j-1].as_bytes()[i] == s[j].as_bytes()[i]) }; rm
        }).count() as _
    }

20.12.2025

944. Delete Columns to Make Sorted easy blog post substack youtube

67d1f3d5-cce9-4f1d-8679-a72de527fec3 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1210

Problem TLDR

Count unsorted columns #easy

Intuition

Compare column with its sorted variant.

Approach

  • or compare adjucent rows in a column

Complexity

  • Time complexity: \(O(nm)\) or nmlogn

  • Space complexity: \(O(n)\) or O(1)

Code

// 84ms
    fun minDeletionSize(s: Array<String>) = 
        s[0].indices.map{i -> s.map{it[i]}}.count { it != it.sorted() }
// 1ms
    pub fn min_deletion_size(s: Vec<String>) -> i32 {
        (0..s[0].len()).filter(|&i| (1..s.len()).any(|j| s[j-1].as_bytes()[i]>s[j].as_bytes()[i])).count() as _

19.12.2025

2092. Find All People With Secret hard blog post substack youtube

5285f48e-521e-486a-a8cb-3436dfe7a340 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1209

Problem TLDR

Time based secret spread in a graph #hard #uf

Intuition

Union-Find works, but naive gives TLE. Use path compression.

Approach

  • to disconnect nodes collect them by time groups, then short-circuit uf[x]=x
  • or collect mini-graphs by time and walk DFS from connected to 0

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 145ms
    fun findAllPeople(n: Int, m: Array<IntArray>, f: Int): List<Int> {
        m.sortBy { it[2] }; val u = HashMap<Int, Int>(); u[f] = 0
        fun f(x: Int): Int = u[x]?.let { if (it==x) x else f(it).also { u[x] = it }} ?: x
        val curr = ArrayList<Int>(); var prev = 0
        for ((x,y,t) in m) {
            if (t > prev) for (x in curr) if (f(x) != f(0)) u[x] = x
            if (t > prev) curr.clear()
            u[f(x)] = f(y); curr += x; curr += y; prev = t
        }
        return (0..<n).filter { f(it) == f(0) }
    }
// 20ms
    pub fn find_all_people(n: i32, mut m: Vec<Vec<i32>>, fst: i32) -> Vec<i32> {
        m.sort_unstable_by_key(|v| v[2]); let mut u: Vec<_> = (0..n as usize).collect(); 
        let mut c = vec![]; let mut p = 0; u[fst as usize] = 0;
        fn f(u: &mut [usize], x: usize) -> usize { if x != u[x] { u[x] = f(u, u[x])} u[x]}
        for v in m {
            let (x, y, t) = (v[0] as usize, v[1] as usize, v[2]);
            if t > p { for &x in &c { if f(&mut u, x) != f(&mut u, 0) { u[x] = x }}; c.clear() }
            let rx = f(&mut u, x); u[rx] = f(&mut u, y); c.extend([x,y]); p = t
        }
        (0..n).filter(|&i| f(&mut u, i as usize) == f(&mut u, 0)).collect()
    }

18.12.2025

3652. Best Time to Buy and Sell Stock using Strategy medium blog post substack youtube

ab32cad1-a3a3-4a93-9514-929e96c0fb18 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1208

Problem TLDR

Max Profit by modifying a sliding window sum #medum

Intuition

Use two separate sliding window sums. The total max profit is sum + (modified window - original window)`

    // 0 1 2 i
    // 4 2 8
    //-1 0 1    k=2
    //   i

    // 9 2 9 5
    //-1 0 1 1    k=4
    //       i

Approach

  • use a single variable to hold sliding window sum

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 22ms
    fun maxProfit(p: IntArray, st: IntArray, k: Int): Long {
        var sm = 0L; var so = 0L; var diff = 0L
        return p.indices.sumOf { i ->
            sm += p[i] - if (i-k/2 >= 0) p[i-k/2] else 0
            so += st[i] * p[i] - if (i-k >= 0) st[i-k] * p[i-k] else 0
            if (i+1-k >= 0) diff = max(diff, sm - so)
            1L * st[i] * p[i]
        } + diff
    }
// 0ms
    pub fn max_profit(pr: Vec<i32>, st: Vec<i32>, k: i32) -> i64 {
        let (mut sm, mut so, mut diff, k) = (0,0,0,k as usize);
        pr.iter().zip(&st).enumerate().map(|(i, (&p, &s))|{
            sm += (p - if i >= k/2 { pr[i-k/2] } else { 0 }) as i64;
            so += (s*p - if i >= k { st[i-k] * pr[i-k] } else { 0 }) as i64;
            if i + 1 >= k { diff = diff.max(sm - so) }
            (s * p) as i64
        }).sum::<i64>() + diff
    }

17.12.2025

3573. Best Time to Buy and Sell Stock V medium blog post substack youtube

81ebf892-5407-48cf-b3ef-044f06651049 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1207

Problem TLDR

K best deals buy/short/sell stocks #medium #dp

Intuition

  • the O(n^3) is accepted in Kotlin, dp state is (i,k) and inner loop to close the deal
  • optimized version: use (i,k,s) as a state, s=0 -free, s=1 - bought, s=1 - short the stoks

Approach

  • write DFS, then rewrite to iterative version
  • then we can space optimize if necessary

Complexity

  • Time complexity: \(O(n^2)\), or O(n^3) with inner search

  • Space complexity: \(O(n^2)\)

Code

// 3791ms
    fun maximumProfit(p: IntArray, k: Int): Long {
        val dp = Array(p.size) { LongArray(p.size)}
        fun dfs(i: Int, k: Int): Long = if (i==p.size || k==0)0L else
        dp[i][k].takeIf { it > 0}?:{
            val skip = dfs(i+1, k)
            val start = (i+1..<p.size).maxOfOrNull { j -> abs(p[i]-p[j]) + dfs(j+1, k-1) }?:0L
            dp[i][k] = max(start, skip); dp[i][k]
        }()
        return dfs(0,k)
    }
// 61ms
    pub fn maximum_profit(p: Vec<i32>, k: i32) -> i64 {
        let n = p.len(); let k = k as usize;
        let mut dp = vec![vec![vec![0i64; n+1]; k+1]; 3];
        for i in (0..=n).rev() { for kk in 0..=k { for s in -1..=1 {
            let idx = (s + 1) as usize;
            dp[idx][kk][i] = if i == n || kk == 0 { 0 } else {
                let skip = dp[idx][kk][i+1];
                if s == 0 {
                    let buy = dp[2][kk][i+1] - p[i] as i64;
                    let sell = dp[0][kk][i+1] + p[i] as i64;
                    if i == n - 1 { skip } else { buy.max(sell).max(skip) }
                } else {
                    let close = dp[1][kk-1][i+1] + (s * p[i] as i64);
                    if i == n - 1 { close } else { close.max(skip) }
                }
        }}}} dp[1][k][0]
    }

16.12.2025

3562. Maximum Profit from Trading Stocks with Discounts hard blog post substack youtube

13ac0576-627a-49fc-a4f0-8b7776c87171 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1206

Problem TLDR

Max profit in a tree #hard

Intuition

    // can't understand the description
    // is the 'stock' a single or many?
    // where are the stocks?
    // why example 1 can buy by both
    // and example 2 can not?
    //
    // why example two: 
    // boss: buy at 3 sell at 5: 5-3=2
    // employee: buy at (4/2) sell at 8: 8-2=6
    // profit: 6+2=8, budget (2+3) - ok, its out of budget=4
    // ok, have some understanding: example 2 is out of budget
    // 
    // so we have to pick either buy as a boss
    //                        or buy as a subordinate
    //
    // it can be: dp + graph DFS
    // 
    // ok but how to spread budget between children?
    //
    // interesting that the prices are so low 1..50
    //
    // 30 minute, look for hints; the main difficulty is how to pick the best children and how many?
    // still the question: how to account to budget?
    //
    // just picking a single child is not working
    // 
    // put children in a PriorityQueue by profit and update the tree?
    //
    // ok we have only 160 nodes; it is 2^160 ways of take/not take
    //
    // ok i kind of solved it, TLE is from kotlin slowness and usage of a HashMap

Approach

Complexity

  • Time complexity: \(O(n^2b^2)\)

  • Space complexity: \(O(n^2b^2)\)

Code

// 2822ms
    fun maxProfit(n: Int, p: IntArray, f: IntArray, h: Array<IntArray>, b: Int): Int {
        val ch = Array(n) { ArrayList<Int>() }; for ((p,c) in h) ch[p-1] += c-1
        val dp = HashMap<Int, Int>(); val d = HashMap<Int, Int>()
        fun dfs(i: Int, half: Int, budget: Int): Int = 
            dp.getOrPut(i * 10000000 + half*10000 + budget) {
                fun maxp(j: Int, hf: Int, bgt: Int): Int = if (j == ch[i].size) 0 else
                    d.getOrPut(i * 100000000 + j * 100000 + hf*1000 + bgt) {
                        (0..bgt).maxOf { takeB -> dfs(ch[i][j], hf, takeB) + maxp(j+1, hf, bgt-takeB) }
                    }
                val p1 = maxp(0, 0, budget); val spend = if (half==0) p[i] else p[i]/2
                if (spend > budget) p1 else max(f[i] - spend + maxp(0, 1, budget-spend), p1)
            }
        return dfs(0, 0, b)
    }

15.12.2025

2110. Number of Smooth Descent Periods of a Stock medium blog post substack youtube

d210a905-4fd3-482d-a2a6-97376705d4cb (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1205

Problem TLDR

Decreasing subarrays #medium

Intuition

Just count them like and arithmetic progression.

Approach

  • res += count++

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 40ms
    fun getDescentPeriods(p: IntArray) =
    p.indices.fold(0 to 0L) { (cnt, res), i ->
        val c = 1 + if (i > 0 && p[i] == p[i-1] - 1) cnt else 0
        c to (res + c)
    }.second
// 0ms
    pub fn get_descent_periods(p: Vec<i32>) -> i64 {
        (0..p.len()).fold((0,0), |(cnt,res), i| {
            let c = 1 + if i > 0 && p[i] == p[i-1]-1 { cnt } else { 0 };
            (c, res + c)
        }).1
    }

14.12.2025

2147. Number of Ways to Divide a Long Corridor hard blog post substack youtube

895a38fb-0bef-4120-80b5-a786aa620ac5 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1204

Problem TLDR

Ways to split pairs of S #hard

Intuition

    // p p s p p s p p 

Chunk by pairs of ‘s’, multiply counts of in-between ‘p’.

Approach

  • or, rearrange the problem and add the accumulated value on each new ‘p’

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 34ms
    fun numberOfWays(c: String): Int {
        var a = 0; var b = 1; var s = 1
        for (c in c) if (c == 'P') b = (a * (s%2) + b) % 1000000007
            else if (++s%2>0) a = b
        return a * (s%2)
    }
// 3ms
    pub fn number_of_ways(c: String) -> i32 {
        let (mut a, mut b, mut even) = (0, 1, true);
        for c in c.as_bytes().chunk_by(|x, y| x == y) {
            if c[0] == b'P' {
                if even && a > 0 { b = (b + c.len()* a) % 1_000_000_007 }
            } else {
                if !even || c.len() > 1 { a = b }
                if c.len() & 1 > 0 { even = !even }
            }
        } even as i32 * a as i32
    }

13.12.2025

3606. Coupon Code Validator easy blog post substack youtube

fd4f17a4-698f-410e-9dd9-1d3d56a1caf3 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1203

Problem TLDR

Filter a,b,c accroding to rules #easy

Intuition

Just read the rules.

Approach

  • some rules can be hacked around
  • the regex in koglin faster than in rust

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(n)\)

Code

// 57ms
    fun validateCoupons(c: Array<String>, b: Array<String>, a: BooleanArray) =
    c.indices.filter { a[it] && Regex("\\w+") matches c[it] && b[it][0] in "egpr" }
    .sortedBy { b[it][0] + c[it] }.map { c[it] }
// 0ms
    pub fn validate_coupons(c: Vec<String>, b: Vec<String>, a: Vec<bool>) -> Vec<String> {
        b.iter().map(|b|b.as_bytes()[0]).zip(c).zip(a).filter(|((b,c),a)| 
            *a && b"egrp".contains(b) && c != "" && c.chars().all(|c|c.is_alphanumeric() || c == '_'))
        .sorted().map(|((_,c),_)|c).collect()
    }

12.12.2025

3433. Count Mentions Per User medium blog post substack youtube

2e36944c-7c92-45bc-8c37-d8b28e165d51 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1201

Problem TLDR

Count messages and track online users #medium #simulation

Intuition

The problem is not that big. Sort by timestamp and put queries after offline modifications.

Approach

  • use queue of coming online or just array of coming online times for all users

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n)\)

Code

// 61ms
    fun countMentions(n: Int, e: List<List<String>>): IntArray {
        val r = IntArray(n); val on = IntArray(n)
        for ((type, ts, ids) in e.sortedBy { it[1].toInt()*100-it[0][0].toInt() })
            if (type[0] == 'O') on[ids.toInt()] = ts.toInt() + 60
            else if (ids[0] == 'A') for (i in 0..<n) ++r[i]
            else if (ids[0] == 'i') for (i in ids.split(" ")) ++r[i.drop(2).toInt()]
            else for (i in 0..<n) if (on[i]<=ts.toInt()) ++r[i]
        return r
    }
// 0ms
    pub fn count_mentions(n: i32, mut e: Vec<Vec<String>>) -> Vec<i32> {
        let n = n as usize; let (mut r, mut o) = (vec![0; n], vec![0; n]);
        e.sort_unstable_by_key(|v| v[1].parse::<i32>().unwrap()*100-v[0].as_bytes()[0] as i32);
        for v in &e {
            let (tp, ts) = (v[0].as_bytes()[0], v[1].parse::<i32>().unwrap());
            if tp == b'O' { o[v[2].parse::<usize>().unwrap()] = ts + 60 }
            else if v[2].as_bytes()[0] == b'A' { for i in &mut r { *i += 1 }}
            else if v[2].as_bytes()[0] == b'i' { for i in v[2].split(" ") { r[i[2..].parse::<usize>().unwrap()] += 1 }}
            else { for i in 0..n { if o[i] <= ts { r[i] += 1 }}}
        } r
    }

11.12.2025

3531. Count Covered Buildings medium blog post substack youtube

9328c4f5-787e-4249-9694-cf67f91a8579 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1200

Problem TLDR

Count surrounded dots on XY plane #medium

Intuition

    // idea line sweep Y then X, collect in-betweens, intersect them

Line sweep: collect lines, sort each line, drop first and last, intersect with orthogonal sweep.

Approach

  • optimization: instead of collecting, just look max and min on each line.

Complexity

  • Time complexity: \(O(nlog(n))\), or O(n) for min-max

  • Space complexity: \(O(n)\)

Code

// 463ms
    fun countCoveredBuildings(n: Int, b: Array<IntArray>) =
        listOf(b.indices.groupBy { b[it][0] }.values.map { it.sortedBy { b[it][1] }},
               b.indices.groupBy { b[it][1] }.values.map { it.sortedBy { b[it][0] }})
        .map { it.fold(HashSet<Int>()) { r, t -> r += t.drop(1).dropLast(1); r }}
        .reduce(Set<Int>::intersect).size
// 17ms
    pub fn count_covered_buildings(n: i32, b: Vec<Vec<i32>>) -> i32 {
        let (mut minY, mut maxY) = (vec![100000; n as usize+1], vec![0; n as usize+1]);
        let (mut minX, mut maxX) = (minY.clone(), maxY.clone());
        for b in &b { let (x,y) = (b[0] as usize, b[1] as usize);
            minY[x] = minY[x].min(y); maxY[x] = maxY[x].max(y);
            minX[y] = minX[y].min(x); maxX[y] = maxX[y].max(x);
        }
        b.iter().filter(|&b| { let (x,y) = (b[0] as usize, b[1] as usize);
            minX[y] < x && x < maxX[y] && minY[x] < y && y < maxY[x] }).count() as _
    }

10.12.2025

3577. Count the Number of Computer Unlocking Permutations medium blog post substack youtube

cd2d2aa9-4cd2-401c-832d-247fbec96810 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1199

Problem TLDR

Permutations to unlock all c[j] right and bigger than c[i] #medium #combinatorics

Intuition

    // 123456
    // 1 then take all values bigger as second position
    // 1 p[23456]
    // 12 p[3456]
    // 13 p[2456], the number is n!
    // what if we have duplicates?
    // 1223456
    // we are not allowed to sort
    // 1654223
    // 1 [654223] but every number can be at any place
    //           so it doesnt matter
    // so it is (n-1)!
    // how to  calc factorial of 10^5?
    //
    //
  • first should be the smallest
  • other numbers doesn’t matter

Approach

  • use longs

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 9ms
    fun countPermutations(c: IntArray) = (1..<c.size)
    .fold(1L) { r, t -> if (c[t] > c[0]) (r*t) % 1000000007 else 0 }
// 0ms
    pub fn count_permutations(c: Vec<i32>) -> i32 {
        (1..c.len()).fold(1, |r,t|
        if c[t] > c[0] {(r*t)%1000000007} else { 0 })as _
    }

09.12.2025

3583. Count Special Triplets medium blog post substack youtube

e1399961-8558-4ab5-aa10-3dc1d63323b9 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1198

Problem TLDR

Count a[i]==a[j]*2==a[k] #medium #prefix_sum

Intuition

    // 8 4 2 8 4
    //   *        look for all 8 left and right
    //   

Count total frequency F. Count frequency so-far L. Add for each middle: L * (F - L)

Approach

  • or a single pass solution from lee: count frequency so-far F, count pairs (2x,x) so-far C+=F[x], add each C[x/2]

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 176ms
    fun specialTriplets(n: IntArray) = {
        val f = LongArray(200002); val c = f.clone()
        n.sumOf { x -> val r = 1L*c[x/2]*(1 - x%2); c[x] += f[x*2]; f[x]++; r }
    }() % 1000000007
// 36ms
    pub fn special_triplets(n: Vec<i32>) -> i32 {
        let mut f = [0i32; 200002]; let mut c = f.clone();
        n.iter().fold(0, |r, &x|{ let x = x as usize;
            let rx = c[x>>1] * ((x&1)^1)as i32;
            c[x] = (c[x] + f[x<<1])%1000000007;
            f[x] += 1; (r + rx)%1000000007
        })
    }

08.12.2025

1925. Count Square Sum Triples easy blog post substack youtube

1a7fcc8f-43cd-4f69-94d4-012239f197d7 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1197

Problem TLDR

Count a^2+b^2=c^2 in 1..n range #easy

Intuition

O(n^3) is accepted O(n^2): precompute n^2 numbers, lookup (a+b) in them

Approach

  • we have to be in range 1..n, not in 1..250
  • or check sqrt(aa+bb)

Complexity

  • Time complexity: \(O(n^3)\) or O(n^2)

  • Space complexity: \(O(n)\)

Code

// 49ms
    fun countTriples(n: Int): Int {
        val s = (1..n).map { it * it }.toSet()
        return s.sumOf { a-> s.count { b-> (a+b) in s}}
    }
// 5ms
    pub fn count_triples(n: i32) -> i32 {
        (1..=n).map(|a| 2*(a..=n).filter(|b| { 
        let c = (a*a+b*b).isqrt(); c <= n && c*c==a*a+b*b}).count() as i32).sum::<i32>()
    }

07.12.2025

1523. Count Odd Numbers in an Interval Range easy blog post substack youtube

ff0763dc-acf5-46ba-a96b-cd897810f634 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1196

Problem TLDR

Odds l..h #easy

Intuition

Look at total numbers count d:

  • even d - just divide by 2
  • odd d - divide by 2 plus look at first number if it is odd
    // 1 2      2-1+1=2,  l=o, h = e, 2/2
    // 1 2 3 4  4, l=o h=e 4/2
    // 1 2 3    3   l=o h=o   1+3/2
    // 2 3      2   l=e    2/2
    // 2 3 4 5  4   l=e    4/2
    // 3 4 5    3   l=o    1+3/2
    // 2 3 4    3   l=e    3/2
    // 3 4 5 6  4   l=o    4/2

Approach

  • or brillian lee compression of this logic: (h+1)/2-l/2

Complexity

  • Time complexity: \(O(1)\)

  • Space complexity: \(O(1)\)

Code

// 76ms
    fun countOdds(l: Int, h: Int) =
        (h-l+1)/2 + (l%2)*((h-l+1)%2)
// 0ms
    pub fn count_odds(l: i32, h: i32) -> i32 {
       (h+1)/2 - l/2 
    }

06.12.2025

3578. Count Partitions With Max-Min Difference at Most K medium blog post substack youtube

bc2b490c-f8ed-4c2c-b10b-7605dcde8233 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1195

Problem TLDR

Ways to partition into parts (max-min) at most k #medium #dp #monotonic_queue

Intuition

Didn’t solve.

   // at most means 0..k
    // so for each position i 
    // look for all possible positions j
    // abs(n[j]-n[i]) at most k
    // or it is every position j..i 
    // and move j if n[j] is not in n[i]-k..n[i]+k
    //
    // corner case 3 3 4    k=0/1
    // completely wrong solution
    //
    // 4 1 3 7
    // j i
    // j     i    when i goes to 7 it is out of bounds with 1
    //            but j stays at 4 and is ok
    //
    // from '1' look at ..0 and 5.. left and right
    // let's only look left
    // 9 4 1 3 7  k=4     TreeMap lookup? have to check all ranges 5+,0-
    // i          1
    //   * i      2 1*2=2
    //   * * i    3 1*3
    //       * i  2 2*3
    //             
    // 24 minute lets' look for hints, ok its dp
    // f(9 4 1 3) = f(9)*f(4 1 3)
    // 1 2 3 4 5 6    k=2
    // * * *
    //   * * *                         
    //     * * *                         
    //       * * *   24=6x4     * * * = 6 = 3*4/2                      
    // 32 minute hint 2&3, so the second trick is running min/max
    //                                            this is a hard problemm
    // 1 hour mark
    // my algo correclty detects j
    // but i don't know how to count ways, tests are not passing
    // look for solutions
    // from lee solution, its not just about detecting j position
    //                    we should track accumulated values
    //                    and subtract them while we moving j

  • i is the end of the window
  • j is the left position, such that max - min at most k
  • dp[i] = dp[j] + dp[j+1] + dp[j+2] + … + dp[i-1]
  • use prefix sum of dp to calculate sum(dp[j..i])
  • use decreasing queue to find max
  • use increasing queue to find min
  • pop both queues together while moving j

Approach

  • this problem is hard

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 105ms
    fun countPartitions(n: IntArray, k: Int): Int {
        val dp = IntArray(n.size+1); dp[0] = 1; val M = 1000000007
        val ps = IntArray(n.size+1); ps[0] = 1; var j = 0
        val qmax = ArrayDeque<Int>(); val qmin = ArrayDeque<Int>()
        for (i in n.indices) {
            while (qmax.size > 0 && n[qmax.last()] < n[i]) qmax.removeLast()
            while (qmin.size > 0 && n[qmin.last()] > n[i]) qmin.removeLast()
            qmax += i; qmin += i
            while (n[qmax.first()]-n[qmin.first()] > k) {
                if (qmax.first() < ++j) qmax.removeFirst()
                if (qmin.first() < j) qmin.removeFirst()
            }
            dp[i+1] = (M + ps[i] - if (j > 0) ps[j-1] else 0) % M
            ps[i+1] = (ps[i] + dp[i + 1]) % M
        }
        return dp[n.size]
    }

05.12.2025

3432. Count Partitions with Even Sum Difference easy blog post substack youtube

9d93b705-13db-48c9-9709-31ab503779dd (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1194

Problem TLDR

Count Left sum - Right sum % 2 #easy

Intuition

Just brute-force.

Approach

  • a more interesting solution: A-B %2 == 0 only if both odd or both even.
  • step i+0, […….even_sum][……….even_sum]
  • step i+1, […….even_sum,odd][……….even_sum-odd]
  • step i+1, […….even_sum,even][……….even_sum-even]
  • basically, the even-ness will be the same for every partition
  • same proof for odd-ness

Complexity

  • Time complexity: \(O(n^2)\), or O(n) for clever solution

  • Space complexity: \(O(1)\)

Code

// 11ms
    fun countPartitions(n: IntArray) =
        (n.size-1)* (1-n.sum()%2)
// 0ms
    pub fn count_partitions(n: Vec<i32>) -> i32 {
       (n.len()as i32-1)*(1-n.iter().sum::<i32>()%2)
    }

04.12.2025

2211. Count Collisions on a Road medium blog post substack youtube

95c23113-c2d5-4f60-8fd7-6d1c65dc353a (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1193

Problem TLDR

Collisions R vs L #medium

Intuition

Do separate pass for R, then backwards pass for L. Drop counter every time opposite meets.

Approach

  • notice, only the prefix L and suffix R are excluded.

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\), can be O(1)

Code

// 42ms
    fun countCollisions(d: String) =
        d.trimStart('L').trimEnd('R').count { it != 'S' }
// 0ms
    pub fn count_collisions(d: String) -> i32 {
       d.trim_start_matches('L').trim_end_matches('R').bytes()
       .filter(|&b| b != b'S').count() as _
    }

03.12.2025

3625. Count Number of Trapezoids II hard blog post substack youtube

4936712f-8071-4c9b-aa99-2728efa40b4e (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1192

Problem TLDR

Count trapezoids from points #hard #geometry

Intuition

    // i really don't like this problem
    //
    // line y = (dy/dx)x + b
    //      y*(x2-x1) = x*(y2-y1)
    //
    // how to track parallel lines?
    // we have only 500 points, can be O(n^2)
    //
    // for each point pair: count same slope others
    //

    // the key should be the line, not the slope
    //
    // (y-y0)= (x-x0)*(y2-y1)/(x2-x1), slope + point of intersection of x and y coordinates
    // line intersect X coordinate at x = x0, y = 0, Y coordinate at y0
    //
    // i don't have a time to remember geometry
    //
    // how to check y-intercept?; y = kx+b; b = y -kx
    //
    // ok the double is not precise enough, have false positive match
    // -24,-89  42,11      and     -75,-89  -9,11     (or maybe it is symmetrical)
    //
    // let's go for answer, feels pointless, how to use gcd here?
  • key slopes by normalized dy/gcd(dx,dy) dx/gcd(dx,dy)
  • key parallelogram by equal distances between points (they are pairly-equal for parallelogram) dy dx
  • then count subprolem with points on parallel lines: sum+count, res += sum*count

Approach

  • parallelogram’s keyed points gives exactly 2x for parallelograms and 1x otherwise, so /2 would gives only duplicates

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n^2)\)

Code

// 578ms
    fun countTrapezoids(p: Array<IntArray>): Int {
        val m = HashMap<Int, HashMap<Int, Int>>(); val d = m.toMutableMap()
        fun gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b)
        for (i in p.indices) for (j in i+1..<p.size) {
            val (x1,y1) = p[i]; val (x2,y2) = p[j]; var dx = x2-x1; var dy = y2-y1
            if (dx < 0 || dx == 0 && dy < 0) { dx = -dx; dy = -dy }
            val g = gcd(dx, dy); val sx = dx / g; val sy = dy / g; val line = sx*y1-sy*x1
            val slope = (sx shl 12) or (sy+2000); val dist = (dx shl 12) or (dy+2000)
            m.getOrPut(slope) { HashMap() }.merge(line, 1, Int::plus)
            d.getOrPut(dist) { HashMap() }.merge(line, 1, Int::plus)
        }
        fun cnt(m: Map<Int, Map<Int, Int>>): Int =  m.values.sumOf { 
            it.values.fold(0 to 0) { (sum, r), t -> (sum + t) to (r + sum*t)}.second }
        return cnt(m) - cnt(d)/2
    }

02.12.2025

3623. Count Number of Trapezoids I medium blog post substack youtube

321670b3-31c5-41bb-bee4-2f630f5c5a78 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1191

Problem TLDR

Trapezoids count #medium

Intuition

    //         *              *          2
    //    *           *           *      3     2,3= 3
    //       *            *              2     2,2=1 + 2,3=3 = 4
    //             *                     1     skip
    //  *       *      *        *        4     2,4=6 + 3,4=(6+6+6)=18 + 2,4=6 = 6*5=30
    //     *       *     *       *       4     prev(30)+f(4,4)
    //        *       *      *           3     2*(3,2) + 3,3 + 2*(3,4)
    // 1 - 0
    // 2 - 1
    // 3 - 3
    // 4 - 6
    // 5 - 4+3+2+1=10 5*(5-1)/2       * * * * *
    // TLE? - yes, this is O(N^2), previous are too many
    // 35 minute, look for hints: they propose n^2 algo, there are too many groups
    //                            ugly math trick to solve this

Approach

  • group by level Y
  • each level count adds as c*(c-1)/2
  • use previous levels sum

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 81ms
    fun countTrapezoids(p: Array<IntArray>) =
        p.groupingBy {it[1]}.eachCount().values.fold(0L to 0L){ (res,sum),c -> 
        val ways = 1L*c*(c-1)/2; res + ways*sum to ways+sum }.first % 1000000007
// 63ms
    pub fn count_trapezoids(p: Vec<Vec<i32>>) -> i32 {
        (p.iter().map(|v| v[1]).counts().values().fold((0,0), |(r,s),&c|{
        let w = (c*(c-1)/2); (r+w*s,w+s) }).0 % 1000000007) as _
    }

01.12.2025

2141. Maximum Running Time of N Computers hard blog post substack youtube

98398bb6-add2-4ff1-92a0-4c90aa42af56 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1190

Problem TLDR

Max time to run n computers with batteries #hard #bs

Intuition

    // n=3     b=[3,3,3] t= 3
    // n=3     b=[3,3,3,3] t= 3
    //            2 2 2 3
    //              1 1 2
    //            1   0 1 
    //            0 0   0 t=4
    // b= 1 2 3 4 5 6   n=3
    //    0 1 2
    //      0 1 3
    //        0 2 4
    //          1 3 5
    //          0 2 4 non optimal, left 6 which is 2*n
    //
    //          3 4 5
    //          2 3 4
    //          1 2 3
    //          0 1 2
    //    0 1 2
    //      0 1   0     1+2 left, non optimal, 1+2=n
    //
    //    0       4 5
    //      1     3 4
    //      0   3   3
    //        2 2 2
    //        1   1 2
    //          1 0 1
    //        0 0   0   7 optimal, left is 0
    //                  so the algo: take all bigger and one small
    //                  does this always work?
    //
    // n=2  1 40 40    just take biggest
    // ok looks like algo is not obvious, is it binary search?
    //
    // we have time, answer question can run?
    //               true true true | false false false
    //
    // now, given the time how to consume it?
    //
    // 1 2 3 4 5 6  n=3  time=7 sum=21; 
    //                   any minute we burn 3 points
    //                           total = 7*3 = 21
    //                   time=8 total < sum
    // 3 3 3 n=2 time=5; sum=9    total=2*5=10
    //           time=4           total=2*4=8
    //
    // corner cases
    // 1 1 10 n=2 sum=12  maxtime=6 
    // 2 2 10 n=2 sum=14
    //            let t = 4, 4*2 = 8
    // 2+2+4 = 8 
    //
    //  1 40 40 n=2, let t=40, 2*40=80
    //  
    // 30minute, look for hint: already knew; 
    // the actual hardness is how to determine if can run

With given time answer canRun n computers. Total required energy is t*n. Each battery can’t give more than it have or more than t (it can’t be alone used in parallel).

Approach

  • another intuition is: average sum/n, take max while it is bigger than average (they are not relevant to detection of max time); the leftover sum/n is the answer

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(1)\)

Code

// 13ms
    fun maxRunTime(n: Int, b: IntArray): Long {
        var lo = 0L; var hi = Long.MAX_VALUE/n
        while (lo <= hi) {
            val t = lo + (hi - lo) / 2
            if (t*n <= b.sumOf { min(1L*it, t) }) lo = t + 1 else hi = t - 1
        }
        return hi
    }
// 14ms
    pub fn max_run_time(n: i32, b: Vec<i32>) -> i64 {
        let (mut lo, mut hi) = (0, i64::MAX / n as i64);
        while lo <= hi {
            let t = lo + (hi - lo) / 2;
            if t * n as i64 <= b.iter().map(|&x|t.min(x as i64)).sum::<i64>() 
            { lo = t + 1 } else { hi = t - 1 }
        }; hi
    }

30.11.2025

1590. Make Sum Divisible by P medium blog post substack youtube

8fd0e802-9119-468e-a321-dda00fc6be1e (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1189

Problem TLDR

Min removal to make sum%p #medium #hashmap

Intuition

   // 3 1 4 2       sum=10 p=6
    // idea: prefix sums
    // 3 4 8 10
    // idea: all subarrays ending at position
    // 3 1 4 2
    //   *          1, 3+1=4
    // sum = remove + stay, where stay % p == 0
    // stay_a .. remove .. stay_b
    // stay_a + stay_b % p == 0
    // (prefix_sum + suffix_sum) % p == 0
    // and we want them as big as possible
    //
    // 3 1 4 2
    // i     j     3+2
    //   i   j     3+1+2=6
    //   or
    // i   j       3+4+2=9 we don't know which pointer to move
    //                     is this dp?
    //
    // idea: invert the problem
    // subarray should be divisible by %(sum%p)
    // check
    // 6 3 5 2    p=9    sum=16, 16%9=7, subarray %7
    //     [..]
    // ok seems works; how can we find it?
    // prefix sum
    //
    // 6 9 14 16
    // reminder to position
    // 6 2 0  2
    //        i    6-0, 2-1, 0-2, currSum=16, currRem=2 (lookup last pos of 2)
    // 
    // check
    // 3 1 4 2    sum=10, p=6, sum%p = 4
    // 3 4 8 10  
    // 3 0 0 2
    //   i        len=2
    //     i      len=1
    //
    // ok failed on 4 4 2 p=7
    //
    // 4 4 2
    // 4 8 10     k=10%7=3
    // 1 2 1      looks like it completely not working; we want to find %3 subarray
    //            so, 4 2 is %3 but the leftover 4 is not %7, looks like wrong intuition
    //            maybe we want to find at most 3, 10-7=3
    // another fail 
    // 3 6 8 1 p=8    sum=18   k=18%8=2
    // 31 minute
    // 1 1 1 0      remove 6 because it is %2, looks like a wrong idea
    //
    // 34 minute go for hints: same ideas as mine, but put s%p instead of s%k in map
    // looks like i overcomplicated and got lost
    // 3 1 4 2     p=6
    // 3 4 2 4
    //
    // 6 3 5 2    p=9 k=7
    // 6 2 0 2
    //
    // so the wrong part is that k should match exactly, not by %k

(pref_i - pref_j) % p = k pref_j %p = pref_i % p - k

Approach

  • store and lookup pref % p

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 55ms
    fun minSubarray(n: IntArray, p: Int): Int {
        val m = HashMap<Int, Int>(); m[0] = -1; var s = 0
        val k = n.fold(0) {r,t->(r+t)%p}
        return if (k == 0) 0 else n.indices.minOf { i ->
            s = (s + n[i])%p; val j = m[(s-k+p)%p]; m[s] = i
            i - (j?:-n.size)
        }.takeIf { it < n.size } ?: -1
    }
// 15ms
    pub fn min_subarray(n: Vec<i32>, p: i32) -> i32 {
        let k = n.iter().fold(0, |r, &t| (r + t) % p); if k < 1 { return 0 }
        let (mut m, mut s) = (HashMap::from([(0,-1)]), 0);
        n.iter().enumerate().map(|(i, &x)| { s = (s + x) % p;
            let d = m.get(&((s-k+p)%p)).map_or(n.len() as i32, |&j|i as i32 - j);
            m.insert(s, i as i32); d
        }).min().filter(|&r|r < n.len() as i32).unwrap_or(-1)
    }

29.11.2025

3512. Minimum Operations to Make Array Sum Divisible by K easy blog post substack youtube

1e4c53de-2b51-4294-b404-135d7f781973 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1188

Problem TLDR

Sum % k #easy

Intuition

The number of operations is the remainder of %k

Approach

  • %k

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 11ms
    fun minOperations(n: IntArray, k: Int) =
        n.sum() % k
// 0ms
    pub fn min_operations(n: Vec<i32>, k: i32) -> i32 {
        n.iter().sum::<i32>() % k
    }

28.11.2025

2872. Maximum Number of K-Divisible Components hard blog post substack youtube

beaee647-7205-4da8-b1a9-718568cec3f4 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1187

Problem TLDR

Max cuts where every subtree sum %k #hard #dfs

Intuition

    // any subtree sum %k is a valid cut

Approach

  • DFS: start from any, return sum, track %k each
  • BFS: start from leafs, accumulate sums in v, track %k each

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 34ms
    fun maxKDivisibleComponents(n: Int, e: Array<IntArray>, v: IntArray, k: Int): Int {
        val g = Array(n) { ArrayList<Int>() }; for ((a,b) in e) { g[a] += b; g[b] += a }
        fun dfs(i: Int, p: Int): Int = 
            (g[i].sumOf { j -> if (j==p) 0 else dfs(j, i)} + if (v[i]%k<1)1 else 0)
            .also { v[p] += v[i]%k }
        return dfs(0, 0)
    }
// 32ms
    pub fn max_k_divisible_components(n: i32, e: Vec<Vec<i32>>, mut v: Vec<i32>, k: i32) -> i32 {
        let (mut g, mut d) = (vec![Vec::new(); v.len()], vec![0; v.len()]);
        for p in e {let (a,b) = (p[0]as usize,p[1]as usize);g[a].push(b);g[b].push(a);d[a]+=1;d[b]+=1}
        let mut q = VecDeque::from_iter((0..v.len()).filter(|&i|d[i]<2)); let mut r = 0;
        while let Some(u) = q.pop_front() { if v[u] % k < 1 { r += 1 }
            for &x in &g[u] { if d[x] > 0 { v[x] += v[u]%k; d[x] -=1; if d[x]==1 { q.push_back(x);}}}
        }; r
    }

27.11.2025

3381. Maximum Subarray Sum With Length Divisible by K medium blog post substack youtube

83052778-c9b7-4dde-adc0-eed850cd8a2b (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1186

Problem TLDR

Max sum of %k-length subarray #medium

Intuition

    // -1 1 -1 1 -1 1   %3
    //    *
    //    *  * *
    //
    // all sums O(n^2)
    // all subarrays O(n^2) k=1
    // find just max subarray sum, then expand/shrink?
    // use two pointers and shrink from both ends until %k?
    // 2 -5 3 2 1     %3, which pointer to move?
    // i        j
    //
    //      i    ending at i we have i/k possible starting points
    //           all of them are moving with i + 1, 
    //  **s**s**s*i  %3
    //          ***
    //       ******
    //    *********
    //                      the algo is O(n*(n/k)) = O(n^2)
    //
    // looks like a hard problem

    // 17 minutes, use hint - min prefix sum ending at every i%k (didn't tell much)
  • dp[i] = sum(i-k..i)+max(0, dp[i-k]), where dp[i] is answer for array ending at i

Approach

  • solution from lee (i copied it in rust) is uncomprehensible, let’s just say it is compressed

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 44ms
    fun maxSubarraySum(n: IntArray, k: Int): Long {
        val dp = LongArray(n.size); val p = LongArray(n.size+1)
        for (i in n.indices) p[i+1] = n[i].toLong()+p[i]
        for (i in n.indices) dp[i] = (p[i+1]-if(i-k+1>=0)p[i-k+1]else 0) + 
                                      max(0, if(i-k+1>=k)dp[i-k]else 0)
        return dp.drop(k-1).max()
    }
// 7ms
    pub fn max_subarray_sum(n: Vec<i32>, k: i32) -> i64 {
        let k = k as usize; let (mut p, mut s) = (vec![i64::MAX/2; k], 0); p[k-1] = 0;
        (0..n.len()).map(|i| { s += n[i] as i64; 
            let r = s - p[i%k]; p[i%k] = s.min(p[i%k]); r}).max().unwrap()
    }

26.11.2025

2435. Paths in Matrix Whose Sum Is Divisible by K hard blog post substack youtube

92e260af-fc15-4c08-97d6-25914946ca75 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1185

Problem TLDR

Paths in 2D matrix %k #hard

Intuition

Each cell hash exactly k possible remainders of all paths, so memo by [y][x][k]

Approach

  • top down is just a memo+bruteforce DFS

Complexity

  • Time complexity: \(O(nk)\)

  • Space complexity: \(O(nk)\)

Code

// 479ms
    fun numberOfPaths(g: Array<IntArray>, k: Int): Int {
        val M = 1000000007; val dp = HashMap<Int, Int>()
        fun dfs(y: Int, x: Int, s: Int): Int = 
            if (y==g.size-1&&x==g[0].size-1) {if ((g[y][x]+s)%k==0) 1 else 0}
            else if (y==g.size||x==g[0].size) 0 else
            dp.getOrPut(y*1000000+x*100+s) {
                (dfs(y+1, x, (g[y][x] + s)%k) + dfs(y, x+1, (g[y][x]+s)%k))%M
            }
        return dfs(0, 0, 0)
    }
// 29ms
    pub fn number_of_paths(g: Vec<Vec<i32>>, k: i32) -> i32 {
        let k = k as usize; let mut r = vec![vec![0; k+1]; g[0].len()+1];
        let mut n = r.clone(); r[1][0] = 1;
        for row in g {
            for x in 0..r.len()-1 { let v = row[x]as usize; for i in 0..k { 
                n[x+1][(i+v)%k] = (n[x][i] + r[x+1][i])%1000000007 }}
            (r,n)=(n,r)
        }; r[r.len()-1][0]
    }

25.11.2025

1015. Smallest Integer Divisible by K medium blog post substack youtube

72671a01-2ac7-463c-bbb2-e06c9dbcfc74 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1184

Problem TLDR

Smallest number 11..1 % k #medium

Intuition

    // k 10^5
    // x*k = n, n is '1(1)`
    // return length(n) or lg(n)
    // smallest
    // 11 = 10 + 1
    // 111 / 3 = 37
    // this is math brainteaser
    //
    // what numbers gives 1 at the end
    // 1 7 11
    //
    // how to make result all of ones?
    //
    // or, if we take long string of ones how to find if it is %k
    // we have to multiply by 10 and add 1
    // can we do %k every time and check first that is 0?
    // how to stop?

Approach

  • to stop look for remainder loops or just stop at k steps

Complexity

  • Time complexity: \(O(k)\)

  • Space complexity: \(O(1)\)

Code

// 11ms
    fun smallestRepunitDivByK(k: Int): Int {
        var x = 0
        return (1..k).firstOrNull { x = (x * 10 + 1) % k; x == 0 } ?: -1
    }
// 0ms
    pub fn smallest_repunit_div_by_k(k: i32) -> i32 {
        let mut x = 0;
        (1..=k).find(|i| {x=(x*10+1)%k; x==0}).unwrap_or(-1)
    }

24.11.2025

1018. Binary Prefix Divisible By 5 easy blog post substack youtube

b21bafa5-e591-49e3-8c72-f8752080b3a0 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1183

Problem TLDR

Prefixes divisible by 5 #easy #brainteaser

Intuition

    // its not easy; its brainteaser
    // the 10^5 length
    // how to convert base_2 to base_5 directly?
    // to convert to base_10
    // let's try convert to long base_10
    // it goes out of range too fast
    // can we trim it % 5?

Approach

  • the remainder of %5 is enough

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 3ms
    fun prefixesDivBy5(n: IntArray) = 
    { var x = 0; n.map {x = (x*2+it)%5; x<1 }}()
// 0ms
    pub fn prefixes_div_by5(n: Vec<i32>) -> Vec<bool> {
        let mut x = 0; n.iter().map(|&n|{x=(x*2+n)%5; x<1}).collect()
    }

23.10.2025

1262. Greatest Sum Divisible by Three medium blog post substack youtube

d77898d7-d631-4c04-801f-267c931476bf (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1182

Problem TLDR

Max sum that %3 #medium

Intuition

    // add all numbers that are %3
    // search the remaining
    // they can be %3=1, %3=2
    // we need pairs 1+2
    // now take max pairs from 1+2
    // or tripples from %3=1 is this a choice?
    // big_1 big_1 big_1  small_2
    // this makes us loose big_1 + big_1 compared to small_2

    // what if we take from single sorted list
    // big_1 big_2 (take)
    // big_2 big_2 (skip) big_2(skip) big_1 big_1 wrong skip

    // what if we take from two lists big_1 sorted and big_2 sorted
    // take big_1 big_1 big_1 if it is bigger then big_1 big_2

    // edge case: 5 2 2 2  so three %3=2 is also %3

    // + some big corner case (my not optimal)
    // probably case where 111 == 222 == 12 and we have to choose
    // is this dp?

    // 23 minute, let's look hints: yes it is dp

    // 28 minute: MLE

    // i have another idea: all sum can be %3==0,1, or 2
    // if %3==0 just return sum
    // if %3==1 remove smallest %3==1 or two %3==2
    // if %3==2 remove smallest %3==2 or two %3==1
  • remove the smallest from sum
  • only 3 cases possible

Approach

  • another approach is dp: keep three running sums: %3=0,1,2; evaluate where to place

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 4ms
    fun maxSumDivThree(n: IntArray): Int {
        var s=0; var s1=20000; var s11=s1; var s2=s1; var s22=s1
        for (x in n) {
            s += x
            if (x%3==1) if (x<s1) {s11=s1; s1=x} else if (x<s11) s11=x
            if (x%3==2) if (x<s2) {s22=s2; s2=x} else if (x<s22) s22=x
        }
        return s - if (s%3==2) min(s2,s1+s11) else (s%3)*min(s1,s2+s22)
    }
// 0ms
    pub fn max_sum_div_three(n: Vec<i32>) -> i32 {
        let mut s = [0,0,0];
        for x in n { for y in [x+s[0], x+s[1], x+s[2]] { 
            let i = (y%3) as usize; s[i] = s[i].max(y) }}; s[0]
    }

22.11.2025

3190. Find Minimum Operations to Make All Elements Divisible by Three easy blog post substack youtube

9e398533-0b61-4a05-b20f-168a4d7d0dcc (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1181

Problem TLDR

Min steps inc/dec to make %3 #easy

Intuition

  • min(x%3, 3-x%3)

Approach

  • it is actually always min(1,2) = 1

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 1ms
    fun minimumOperations(n: IntArray) =
        n.count { it%3>0 }
// 0ms
    pub fn minimum_operations(n: Vec<i32>) -> i32 {
        n.iter().filter(|&x| x%3>0).count() as _
    }

21.11.2025

1930. Unique Length-3 Palindromic Subsequences medium blog post substack youtube

d3163fea-afa0-4a08-9973-cf6a15c7b5d3 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1180

Problem TLDR

3-palindroms subsequences #medium

Intuition

    // how many pairs we have for alphabet?
    // 26*26 - 500*10^5 = 10^7 too big
    // a b c d a  so, between same chars every uniq counts
    // a......b........a.......b  can intersect

Approach

  • we can use bitmask for speedup

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 121ms
    fun countPalindromicSubsequence(s: String) =
    ('a'..'z').sumOf { s.slice(s.indexOf(it)+1..<s.lastIndexOf(it)).toSet().size }
// 127ms
    pub fn count_palindromic_subsequence(s: String) -> i32 {
        ('a'..='z').filter_map(|c| {
            let r = s.rfind(c)?; let l = s[..r].find(c)?; 
            Some(s[l+1..r].chars().unique().count() as i32)
        }).sum()
    }

20.11.2025

757. Set Intersection Size At Least Two hard blog post substack youtube

36766e29-5633-49f2-9695-b0105097bb24 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1179

Problem TLDR

Min set each interval have two values in it #hard #sorting

Intuition

    // 1 2 3 4 5
    // * * *
    // * * * *
    //   * * * *
    //     * * *
    //       i     drop 1..3, should take two values from it +2
    //                        take the last two: 2,3
    //         i   drop 1..4, the last two is in 1..4, so skip
    //           i drop 2..5, 2 in 2..5, 3in2..5, skip
    //             drop 3..5, 2 !in 3..5, take 5, 3 in 2..5  +1

    // 1 2 3 4 5
    // * *
    //   * *
    //   * * *
    //       * *
    //     i      drop 1..2, +2 (a=1,b=2)
    //       i    drop 2..3, +1 (a=3,b=2)
    //         i  drop 2..4, skip
    //            drop 4..5, +2 a=5,b=4

    // 1 2 3 4 5 6 7 8
    // * * *
    //     * * * * *
    //         * * *
    //             * *
    //       i=2         drop 1..3, +2, a=2 b=3
    //               i=3 drop 3..7, +1, a=7 b=3 then a=3 b=7
    //                   drop 5..7, +1, 
  • sort by the ends: this tells you that interval has ended and you should do something with it

Approach

  • no need to store visited intervals in a heap
  • no need for a hashset, just use two variables
  • don’t even need for while loop: just check if every interval has ‘a’ and ‘b’ in it

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(1)\)

Code

// 25ms
    fun intersectionSizeTwo(v: Array<IntArray>): Int {
        v.sortBy { it[1] }; var a = -1; var b = -1; var res = 0
        for ((l,r) in v) {
            if (a < l) { a = if (r==b) b-1 else b; b=r; res++}
            if (a < l) { a = b-1; res++}
        }
        return res
    }
// 3ms
    pub fn intersection_size_two(mut v: Vec<Vec<i32>>) -> i32 {
        v.sort_by_key(|v|v[1]); let (mut a, mut b, mut r) = (-1,-1,0);
        for v in &v {
            if a < v[0] { a = if b == v[1] { b-1 } else { b }; b = v[1]; r += 1 }
            if a < v[0] { a = b - 1; r += 1 }
        }; r
    }

19.11.2025

2154. Keep Multiplying Found Values by Two easy blog post substack youtube

c4be91d4-0c0e-4b50-bbd4-237ec2f1d49d (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1178

Problem TLDR

First original=original*2 not in array #easy

Intuition

Simulate the proces. Use hashset to speedup.

Approach

  • for 1000 elements O(n^2) is acceptable

Complexity

  • Time complexity: \(O(n + log(max))\)

  • Space complexity: \(O(n)\)

Code

// 15ms
    fun findFinalValue(n: IntArray, o: Int) =
        o shl (0..10).first { o shl it !in n }
// 0ms
    pub fn find_final_value(n: Vec<i32>, o: i32) -> i32 {
       o << (0..11).find(|b| !n.contains(&(o << b))).unwrap()
    }

18.11.2025

717. 1-bit and 2-bit Characters easy blog post substack youtube

16aa5b10-bbe8-4c9a-b673-39462c191a4e (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1177

Problem TLDR

Is ‘0’ last from characters ‘0’,’10’,’11’ concatenation #easy

Intuition

I had to start with DP: in each i position if b[i] zero go next, otherwise go next->next. Then it is just a linear solution without a choice.

Approach

  • optimization: go from back

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 0ms
    fun isOneBitCharacter(b: IntArray): Boolean {
        var i = b.size - 2
        while (i >= 0 && b[i] > 0) i -= b[i]
        return (b.size - i) % 2 < 1
    }
// 0ms
    pub fn is_one_bit_character(b: Vec<i32>) -> bool {
        b[..b.len()-1].split(|&x|x<1).last().unwrap().len()%2<1
    }

17.11.2025

1437. Check If All 1’s Are at Least Length K Places Away easy blog post substack youtube

dc32b130-129d-412c-b438-b0e73b728df3 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1176

Problem TLDR

All ones k-distant #easy

Intuition

Count zeros in-between.

Approach

  • we can write it with 1 extra variable

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 3ms
    fun kLengthApart(nums: IntArray, k: Int): Boolean {
        var z = k
        return nums.all { n -> (n < 1 || z >= k).also { z = (1-n)*(z+1-n)}}
    }
// 0ms
    pub fn k_length_apart(n: Vec<i32>, k: i32) -> bool {
        let mut z = k;
        n.iter().all(|&n|{ let r = n < 1 || z >= k; z = (1-n)*(z+1-n); r})
    }

16.11.2025

1513. Number of Substrings With Only 1s medium blog post substack youtube

5e173ed0-6bd3-4f9b-99fa-250efe0725c7 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1175

Problem TLDR

Substrings of ones #medium #counting

Intuition

Sum the separate islands of ones. Each island length is n(n+1)/2 arithmetic sum.

Approach

  • or compute the arithmetic sum on the go

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 21ms
    fun numSub(s: String) = s.fold(0 to 0) { (r,curr), c ->
        val curr = (c-'0')*curr + (c-'0')
        (r + curr) % 1000000007 to curr
    }.first
// 0ms
    pub fn num_sub(s: String) -> i32 {
        s.bytes().fold((0, 0), |(r, curr), c| {
            let curr = (c-b'0')as i32*curr + (c-b'0')as i32;
            ((r+curr)%1000000007, curr)
        }).0
    }

15.11.2025

3234. Count the Number of Substrings With Dominant Ones medium blog post substack youtube

3102b2ec-4a3a-4fe0-8739-27fe9096ee7d (2).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1174

Problem TLDR

Subarray zeros^2 less than ones #medium #sliding_window

Intuition

    // 000110011(+21 ones tail, can't move j)
    // j      i    z=5 o=3
    //  j     i    z=4 o=3
    //   j    i    z=3 o=3
    //    j   i    z=2 o=3
    // for each i how many 'j' we have
    // z = zeros[i]-zeros[j]
    // o = ones[i]-ones[j]
    // `z*z` less or equal `o`
    // (z[i]-z[j])^2 +o[j] = o[i]
    // z[i]^2 -2z[i]z[j]+z[j]^2+o[j]=o[i]
    // -2z[i]z[j]+z[j]^2+o[j]=o[i]-z[i]^2 
    // 
    // solve around j, looks like a math problem
    // ok this is a hard problem but let's try brute force O(n*sqrt(n))
    // 32 minute - TLE on input all of ones; because the answer is n^2 of them good
    // hints are not giving any obvious ideas
    // but i suspect we can skip islands of ones

Approach

  • use prefix sums
  • use jump array
  • if we good we can jump all ones in current island of ones
  • if we not, jump to the difference z^2-o

Complexity

  • Time complexity: \(O(nsqrt(n))\)

  • Space complexity: \(O(n)\)

Code

// 58ms
    fun numberOfSubstrings(s: String): Int {
        val z = IntArray(s.length+1); val o = IntArray(s.length+1)
        val io = IntArray(s.length) { it-1 }; var res = 0
        for (i in 0..<s.length) {
            if (s[i]=='0') ++z[i+1] else ++o[i+1]
            if (i > 0 && s[i]=='1' && s[i-1]=='1') io[i] = io[i-1]
            z[i+1] += z[i]; o[i+1] += o[i]; var j = i
            while (j >= 0) {
                val z = z[i+1]-z[j]; val d = z*z-o[i+1]+o[j]
                if (d > 0) j -= d else { res += j-io[j]; j = io[j] }
            }
        }
        return res
    }
// 63ms
    pub fn number_of_substrings(s: String) -> i32 {
        let (n, s) = (s.len(), s.as_bytes());
        let (mut z, mut o, mut io)=(vec![0;n+1],vec![0;n+1],vec![0;n]);
        let mut r = 0; for i in 0..n { io[i] = i as i32 - 1; }
        for i in 0..n {
            if s[i]==b'0' { z[i+1] = 1 } else { o[i+1] = 1 }
            if i>0 && s[i]==b'1'&&s[i-1]==b'1' { io[i] = io[i-1] }
            z[i+1] += z[i]; o[i+1] += o[i]; let mut j = i;
            while j<n {
                let z = z[i+1]-z[j]; let d = z*z-o[i+1]+o[j];
                if d>0 { j -= d as usize } else { r += j as i32-io[j]; j=io[j]as usize }
            }
        }; r
    }

14.11.2025

2536. Increment Submatrices by One medium blog post substack youtube

156a70ab-a694-45e7-9288-a04af0d4500f (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1173

Problem TLDR

Increase matrix by query of rectangles of ones #medium #linesweep

Intuition

Expand 1D line sweep pattern to 2D: mark entire rows with +1 for start and -1 to end.

Approach

  • -1 should be on the next cell
  • or, you can mark just 4 cells and compute prefix sum in a separate step

    Complexity

  • Time complexity: \(O(q*n)\)

  • Space complexity: \(O(n^2)\)

Code

// 31ms
    fun rangeAddQueries(n: Int, q: Array<IntArray>): Array<IntArray> {
        val cnt = Array(n) { IntArray(n+1) }
        for (q in q) for (y in q[0]..q[2]) {++cnt[y][q[1]]; --cnt[y][q[3]+1]}
        return Array(n) { y -> var c=0; IntArray(n) { x -> c += cnt[y][x];c}}
    }
// 4ms
    pub fn range_add_queries(n: i32, q: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
        let n = n as usize; let mut m = vec![vec![0; n];n];
        for q in q {
            let (a,b,c,d) = (q[0]as usize,q[1]as usize,q[2]as usize,q[3]as usize);
            m[a][b] += 1; if d+1 < n { m[a][d+1] -= 1}; if c+1 < n { m[c+1][b] -= 1}
            if c+1 < n && d+1 < n { m[c+1][d+1] += 1}
        }
        for row in &mut m { for col in 1..n { row[col] += row[col-1] }}
        for row in 1..n { for col in 0..n { m[row][col] += m[row-1][col] }}; m
    }

13.11.2025

3228. Maximum Number of Operations to Move Ones to the End medium blog post substack youtube

52a8d213-8db3-4706-bf6f-5d9e450d8007 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1172

Problem TLDR

Max steps to move all ones to the right #medium

Intuition

    // 1010101010
    // 1010101001
    // 1010100011
    // 1010000111
    // 1000001111
    // 0000011111
    //
    //  a b c d e
    // 1010101010
    // 0110101010 a-1
    // 0101101010 b-1
    // 0011101010 b-2
    // 0011011010 c-1
    // 0010111010 c-2
    // 0001111010 c-3
    // 0001110110 d-1
    // 0001101110 d-2
    // 0001011110 d-3
    // 0000111110 d-5
    // 0000111110 e-5 bubble '0' to the left
    // go from left to right, each zero gives +(number of ones)
    // dedup zeros

Go from left to right and count ones; each zero adds +count_ones

Approach

  • skip duplicate consequent zeros

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 39ms
fun maxOperations(s: String) = s.indices.fold(0 to 0) {(o,r),i-> 
    o+(s[i]-'0') to if (s[i]>'0'||i>0 && s[i]==s[i-1]) r else r+o}.second
// 0ms
    pub fn max_operations(s: String) -> i32 {
        let (mut o, s) = (0, s.as_bytes()); 
        (0..s.len()).map(|i| { o += (s[i] - b'0') as i32;
            if i>0&&s[i]==s[i-1]||s[i]==b'1'{0}else{o}
        }).sum()
    }

12.11.2025

2654. Minimum Number of Operations to Make All Array Elements Equal to 1 medium blog post substack youtube

f34ff64b-2d89-4f2c-bb07-691e536e4644 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1171

Problem TLDR

Min steps to make all ‘1’ by gcd #medium

Intuition

  • gcd of array = reduce(::gcd)

3 cases:

  • have ones in array - then just propagate it in ‘size-ones’ steps
  • gcd(array)>1 - no answer, -1
  • gcd(array)==1 - then it is min_window_gcd1 steps to make a single 1 plus propagate it size-single ones steps

Approach

  • this is a hard problem

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n)\)

Code

// 27ms
    fun minOperations(n: IntArray): Int {
        val n = n.asList(); val ones = n.count { it<2 }
        fun gcd(a: Int, b: Int): Int = if (b==0) a else gcd(b, a%b)
        return if (ones > 0) n.size - ones else if (n.reduce(::gcd) > 1) -1
        else n.size - 2 + (2..n.size).first { L -> n.windowed(L).any { it.reduce(::gcd)<2}}
    }
// 0ms
    pub fn min_operations(n: Vec<i32>) -> i32 {
        let o = n.iter().filter(|&&x|x==1).count() as i32;
        if o > 0 { n.len()as i32 - o} else {
            fn g(mut a:i32,b:&i32)->i32 { let mut b = *b; while b>0 { let t=b;b=a%b;a=t;} a}
            if n.iter().fold(0,g)>1 { -1 } else { n.len() as i32 - 2 + 
            (2..=n.len()).find(|&l|n.windows(l).any(|w|w.iter().fold(0,g)==1)).unwrap()as i32}
        }
    }

11.11.2025

474. Ones and Zeroes medium blog post substack youtube

1f7cb25c-39cc-4cf6-ae33-8e0345abf2f4 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1170

Problem TLDR

Longest subsequence (ones,zeros) at most (m,n) #medium #dp

Intuition

At each string do a choice take it or not. Cache by (i, zeros, ones).

Approach

  • bottom up intuition: “update [zeros x ones] matrix if we take the current string”

Complexity

  • Time complexity: \(O(nl^2)\)

  • Space complexity: \(O(nl^2)\)

Code

// 179ms
    fun findMaxForm(s: Array<String>, m: Int, n: Int): Int {
        val os = s.map { it.count { it == '1' }}; val dp = HashMap<Int, Int>();
        fun dfs(i: Int, no: Int, nz: Int): Int = dp.getOrPut(i*10000+no*100+nz) {
            if (no > n || nz > m) return Int.MIN_VALUE / 2; if (i == s.size) return 0
            max(1 + dfs(i + 1, no + os[i], nz + s[i].length - os[i]), dfs(i + 1, no, nz))
        }
        return dfs(0, 0, 0)
    }
// 17ms
    pub fn find_max_form(s: Vec<String>, m: i32, n: i32) -> i32 {
        let (m,n)=(m as usize, n as usize); let mut dp = vec![vec![0; n+1];m+1];
        for s in s {
            let o = s.matches('1').count(); let z = s.len() - o;
            for i in (z..=m).rev() { for j in (o..=n).rev() {
                dp[i][j] = dp[i][j].max(dp[i - z][j - o] + 1) }}
        }; dp[m][n]
    }

10.11.2025

3542. Minimum Operations to Convert All Elements to Zero medium blog post substack youtube

1827673c-dd69-45f1-b40c-66834545a841 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1169

Problem TLDR

Min ops to zeros by making min of subarrays 0 #medium #monotonic_stack

Intuition

    // 1 2 3 1 2 3 4 1 2 3
    // 0 2 3 0 2 3 4 0 2 3
    // 0 0 3 0 2 3 4 0 2 3
    // 0 0 0 0 2 3 4 0 2 3
    // 0 0 0 0 0 3 4 0 2 3
    // 0 0 0 0 0 0 4 0 2 3
    // 0 0 0 0 0 0 0 0 2 3
    // 0 0 0 0 0 0 0 0 0 3
    // 0 0 0 0 0 0 0 0 0 0
    // 
    // 1 2 3 2 1 
    // 0 2 3 2 0 
    // 0 0 3 0 0 
    // 0 0 0 0 0 
    //
    // 3 2 1 2 3
    // 3 2 0 2 3
    // 3 0 0 2 3
    // 0 0 0 2 3
    // 0 0 0 0 3
    // 0 0 0 0 0
    //
    // 3 2 1 2 3 2 1
    // *               3
    //   *             2<3, +ops
    //     *           1<2, +ops
    //       2         2 1
    //         3       3 2 1
    //           2     2<3, +ops; 2 1
    //             1   1<2, +ops; 1
    //                 1 + ops
    //    total = 5
  • each decrease means the previous value goes to the separate operation

Approach

  • the remainig values in stack are all separate operations
  • or, we can count increases as operations instead of decreases
  • dirty trick to O(1) memory: use input array as a stack

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 32ms
    fun minOperations(n: IntArray): Int {
        var s = -1
        return n.count { x ->
            while (s >= 0 && n[s] > x) s--
            (x > 0 && (s < 0 || n[s] < x)).also { if (it) n[++s] = x}
        }
    }
// 12ms
    pub fn min_operations(n: Vec<i32>) -> i32 {
        let (mut r, mut s) = (0, vec![0]);
        for x in n {
            while s[s.len()-1] > x { s.pop(); }
            if s[s.len()-1] < x { r += 1; s.push(x) }
        }; r
    }

09.11.2025

2169. Count Operations to Obtain Zero easy blog post substack youtube

ed52662d-317d-4c76-9e3f-e3fcd2ee7132 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1168

Problem TLDR

Count numbers subtractions until 0 #easy

Intuition

Simulate the process.

Another way to look at it: the biggest would be subtracted big/small times until numbers flip.

Approach

  • recursion space complexity is log(depth)
  • it is Euclidian algorithm (a,b) to (b, a%b)
  • there is a golden ratio hidden here
  • consequtive Fibonacci numbers would give the slowest path: Fibonacci sequence backwards

Complexity

  • Time complexity: \(O(log(n))\)

  • Space complexity: \(O(log(n))\)

Code

// 0ms
    fun countOperations(a: Int, b: Int): Int =
        if (a<1||b<1) 0 else a/b + countOperations(b,a%b)
// 0ms
    pub fn count_operations(a: i32, b: i32) -> i32 {
        if a<1 || b<1 { 0 } else { a/b + Self::count_operations(b,a%b) }
    }

08.11.2025

1611. Minimum One Bit Operations to Make Integers Zero hard blog post substack youtube

649c14d6-6dcd-4881-ab28-3aa8be3f5f31 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1167

Problem TLDR

Min steps to make zero by xor 1 or xor rightmost+1 #hard #bits

Intuition

Didn’t solve myself.

   // 000010101
    //        **
    // 000100000 1
    // 000100001 2
    // 000100011 3
    // 000100010 4
    // 000100110 5
    // 000100101 6
    // 000100100 7
    // 000101100 8
    // 000101101 9
    // 000101111 10
    // 000101110 11
    // 000101010 12
    // 000101011 13 
    // 000101001 14
    // 000101000 15
    // 000111000 16
    // 000111001 17
    // 000111011 18
    // 000111010 19
    // 000111110 20
    // 000111111 21
    // 000111101 22
    // 000111100 23
    // 000110100 24
    // 000110101 25
    // 000110111 26
    // 000110110 27
    // 000110010 28
    // 000110011 29
    // 000110001 30
    // 000110000 31
    // 000010000 0
    // 000010001 1
    // 000010011 2
    // 000010010 3
    // 000010110 4
    // 000010111 5
    // 000010101 6
    // 000010100 7
    // 000011100 8
    // 000011101 9
    // 000011111 10
    // 000011110 11
    // 000011010 12
    // 000011011 13
    // 000011001 14
    // 000011000 15
    // 000001000 0 
    // 000001001 1 
    // 000001011 2 
    // 000001010 3 
    // 000001110 4 
    // 000001111 5 
    // 000001101 6 
    // 000001100 7 
    // 000000100 0 
    // 000000101 1 
    // 000000111 2 
    // 000000110 3 
    // 000000010 0 
    // 000000011 1 
    // 000000001 0 
    // 
    // the brute force gives TLE (19 minute)

    // bit 8
    // bit 7   255      128
    // bit 6 - 127 step  64
    // bit 5 - 63 step  32
    // bit 4 - 31 steps 16
    // bit 3 - 15 steps  8
    // bit 2 - 7 steps  4
    // bit 1 - 3 steps  2
    // bit 0 - 1 steps  1
    // the law bit - 2^(bit+1)-1 it is to make zero, not just remove bit

    // but what if we start not from a single bit? any additional bit decrease the steps needed
    // or, its all steps for the next bit plus tail

    // maybe brute force until find some power of two? - TLE
    // Hint 2 (45 minute) useless, i don't know how to transition from a single bit to several bits
    // ok, hint from discussion: the tail bits treated like separate subtractions
    //
    // 1011 = 1000 + 0010 + 0001
    //        3        1       0
    //        a        b       c
    //        a    - ( b   -   c)

  1. The law for the single bit set is 2^(bit+1)-1 - just check testcases with 2,4,8,16,32,64,..
  2. Solve for the most significant bit. The steps already include the tail, so subtract the tail. Do the recursion.

Approach

  • to find the 2 intuition you can spend a day or month of thinking

Complexity

  • Time complexity: \(O(log(n))\)

  • Space complexity: \(O(1)\)

Code

// 0ms
    fun minimumOneBitOperations(n: Int): Int {
        if (n == 0) return 0
        val bit = n.takeHighestOneBit()
        return (bit shl 1) - 1 - minimumOneBitOperations(n xor bit)
    }
// 0ms
    pub fn minimum_one_bit_operations(n: i32) -> i32 {
        if n < 1 { return 0 }
        let b = 1 << (31 - n.leading_zeros());
        (b << 1) - 1 - Self::minimum_one_bit_operations(n^b)
    }

07.11.2025

2528. Maximize the Minimum Powered City hard blog post substack youtube

625a3497-7986-4f81-9162-7dedabcaa33c (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1166

Problem TLDR

Max min r-range sum after adding total of k #hard #bs #sliding_window

Intuition

Define a target minimum range and binary search it. To check if each value can add up to range in total of k budget use a sliding window. Add to the rightmost position.

    // 1 2 4 5 0    r=1  k=2
    // *         1+2   3 +2
    //   *       1+2+4 7
    //     *     2+4+5 11
    //       *   4+5+0 9
    //         * 5+0   5
    // the greedy idea: take the lowest city, but how many to add?
    // the k is 10^9, adding by constant can be too much steps
    // also adding to city propagates to range, so it O(adds*range)
    //
    // binary search idea: define the target minimum, greedily add up to it
    // how to add to a city in a linear way?
    //
    // we can have two ranges and a single optimal spot
    //
    //     [ range1 ]
    //            [ ]        the optimal spot
    //            [ range2 ]
    // 
    // anyway, if we see the first city that needs more power add lazily
    //            [i + range - 1] += 1

    // to calculate powers we need O(n)
    // 1 1 1 1 1 1
    // [ 3 ]
    //   [ x ]
    //   x =  prev+1-1

Approach

  • use a separate long array to keep track of the additions

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(n)\)

Code

// 89ms
    fun maxPower(s: IntArray, R: Int, k: Int): Long {
        var lo = 0L; var hi = Long.MAX_VALUE
        while (lo <= hi) {
            val m = lo + (hi - lo) / 2; var good = true
            val s = LongArray(s.size) { s[it].toLong() }
            var sum = 0L; var k = k.toLong(); var r = 0
            for (i in s.indices) {
                while (r < s.size && r - i <= R) sum += s[r++]
                if (sum < m) { 
                    s[min(s.lastIndex,i+R)] += m - sum
                    k -= m - sum; sum = m 
                }
                if (i - R >= 0) sum -= s[i-R]
                if (k < 0) { good = false; break }
            }
            if (good) lo = m + 1 else hi = m - 1
        }
        return hi
    }

06.11.2025

3607. Power Grid Maintenance medium blog post substack youtube

4273c241-4875-4ebd-ac94-b83dfcb1f7fb (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1165

Problem TLDR

Smallest in subgraph after turning some nodes off #medium #uf

Intuition

Union-Find to build subgraphs. Group by roots and put into TreeSets.

Approach

  • use Map<Root,TreeSet>

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(n)\)

Code

// 223ms
    fun processQueries(c: Int, conn: Array<IntArray>, q: Array<IntArray>)=buildList<Int>{
        val u = IntArray(c+1) { it }
        fun f(x: Int): Int = if (x == u[x]) x else f(u[x]).also {u[x] = it}
        for ((a,b) in conn) u[f(a)] = f(b)
        val g = (1..c).groupBy { f(it) }.mapValues {TreeSet<Int>(it.value)}
        for ((t, v) in q) g[f(v)]?.let {if (t == 2) it.remove(v) else 
            add(if (v in it) v else it.firstOrNull()?:-1) }
    }

// 99ms
    pub fn process_queries(c: i32, conn: Vec<Vec<i32>>, q: Vec<Vec<i32>>) -> Vec<i32> {
        let mut u: Vec<_> = (0..=c as usize).collect();
        fn f(u: &mut Vec<usize>, x: usize) -> usize { if x==u[x] { x } else { let r = f(u,u[x]); u[x]=r; r} }
        for e in conn { let (a,b) = (e[0]as usize,e[1]as usize); let r = f(&mut u,a); u[r]=f(&mut u,b);}
        let mut g = HashMap::new();
        for i in 1..=c as usize {g.entry(f(&mut u,i)).or_insert_with(BTreeSet::new).insert(i as i32);}
        q.iter().map(|p|{
            let (t,v) = (p[0],p[1]); let s = g.get_mut(&f(&mut u,v as usize)).unwrap();
            if t > 1 { s.remove(&v);-2} else { if s.contains(&v) { v} else { *s.iter().next().unwrap_or(&-1)}}
        }).filter(|&r| r > -2).collect()
    }

05.11.2025

3321. Find X-Sum of All K-Long Subarrays II hard blog post substack youtube

169218bf-5867-48db-b3f0-d59fbfeaebe6 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1164

Problem TLDR

Sums of x most frequent from k-windows #hard

Intuition

The main hardness is how to maintain the top sorted X values in a sliding window. There is a trick from:

  • use TreeSet for the X values
  • when removing from X, place removed numbers in a second TreeSet B
  • balance if the best number from B is better than lowest from X
    // 3 3 1 3 3
    // how to speed up/re-use the sum of most frequent
    // 1 1 2 2 3 4 2 3
    // 1 1 2 2 3 4        2 1 4 3   top 2 is 2 1 or sum(1 1 2 2)
    //   1 2 2 3 4 2      2 4 3 1   top 2 is 2 4 or sum(2 2 2 4)   -1 +2 binarysearch n is in topX? 
    //     2 2 3 4 2 3    2 3 4 2   top 2 is 2 3 or sum(2 2 2 3 3) -4(all) + 3(all)
    // how to find which values are out of top
    // the add to top is simple: only when frequency increases, same value can became in top
    // but what values are out of top? maybe the last in the top

    // can we only keep X values in set? - no, because we loose some promising big numbers like 4 from 1,1,2,2,3,4,2,3
    // 11122333  x=1
    // 111         
    //  112    
    //   122
    // time 55, look for hint: the misteriuos second set

Approach

  • related problem: https://leetcode.com/problems/sliding-window-median/description/

Complexity

  • Time complexity: \(O(nlogx)\)

  • Space complexity: \(O(n)\)

Code

// 1054ms
    fun findXSum(n: IntArray, k: Int, x: Int): LongArray {
        val f = HashMap<Int, Long>(); val res = LongArray(n.size-k+1)
        val q = TreeSet<Int>(compareBy<Int>{f[it]?:0L}.thenBy<Int>{it})
        val o = TreeSet<Int>(q.comparator()); var sum = 0L
        fun poll() = if (q.size > x) {
                sum -= 1L * (f[q.first()] ?: 0) * q.first()
                o += q.pollFirst()
            } else Unit
        fun add(n: Int) { q += n; sum += 1L * f[n]!! * n; poll() }
        fun balance() {
            poll()
            if (o.size > 0 && (q.size < x || q.comparator().compare(o.last(),q.first()) > 0)) add(o.pollLast())
        }
        for (i in n.indices) {
            val oldF = f[n[i]] ?: 0L; val newF = 1L + oldF
            if (n[i] in q) sum -= oldF * n[i]
            q -= n[i]; o -= n[i]; f[n[i]] = newF; add(n[i])
            if (i >= k-1) {
                balance()
                res[i-k+1] = sum
                val n = n[i-k+1]; val oldF = f[n] ?: 0L; val newF = oldF - 1L
                if (n in q) sum -= oldF * n
                o -= n; q -= n; f[n] = newF; if (newF > 0L) add(n) else f -= n
            }
        }
        return res
    }

04.11.2025

3318. Find X-Sum of All K-Long Subarrays I easy blog post substack youtube

d9c7334b-fc8a-482e-8ae9-8c6184d92591 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1163

Problem TLDR

Sums of x most frequent from k-windows #easy

Intuition

Not actually easy. Brute-force: solve for each window, count frequency map, sort, take x.

Approach

  • only 50 numbers; use an array instead of a HashMap

Complexity

  • Time complexity: \(O(nklogk)\)

  • Space complexity: \(O(n)\)

Code

// 62ms
    fun findXSum(n: IntArray, k: Int, x: Int) = 
    (0..n.size-k).map { val g = n.slice(it..<it+k).groupBy {it}
        g.keys.sortedWith(compareBy({-(g[it]!!).size},{-it}))
         .take(x).map { it * g[it]!!.size }.sum()
    }

// 1ms
    pub fn find_x_sum(n: Vec<i32>, k: i32, x: i32) -> Vec<i32> {
        n.windows(k as usize).map(|w| {
            let mut f = [0;51]; for &v in w.iter() { f[v as usize] += 1 }
            (0..51).map(|v|(-f[v],-(v as i32))).sorted().into_iter()
            .take(x as usize).map(|(f,v)|v*f).sum()
        }).collect() 
    }

03.11.2025

1578. Minimum Time to Make Rope Colorful medium blog post substack youtube

b366cc18-6d83-467d-985e-e33344442746 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1162

Problem TLDR

Min weighted removals to dedup #medium #greedy

Intuition

Scan from left to right, keep only max from islands of duplicates.

Approach

  • how many extra variables you need?
  • add all time at each step, remove max at change
  • or, add all sum(window(min))

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 23ms
    fun minCost(c: String, t: IntArray) =
        (1..<c.length).sumOf { i -> if (c[i] != c[i-1]) 0 else
            min(t[i], t[i-1]).also { t[i] = max(t[i], t[i-1]) }
        }

// 3ms
    pub fn min_cost(c: String, t: Vec<i32>) -> i32 {
        c.bytes().zip(t.iter()).chunk_by(|(a,_)| *a).into_iter()
        .map(|(_, c)| {
            let (s,m) = c.fold((0, 0), |(s,m), (_, &t)| (s+t,m.max(t))); s-m
        }).sum()
    }

02.11.2025

2257. Count Unguarded Cells in the Grid medium blog post substack youtube

21d59441-3b73-4ce0-b535-36863983f07d (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1161

Problem TLDR

Count unseen cells by rays from guards #medium #grid

Intuition

  • 4 rays iterations: left, top, right, bottom
  • or, rays from guards until another guard or wall
  • or, rays from guards, but mask by direction; don’t have to place guards

Approach

  • count in-place or in another iteration

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 168ms
    fun countUnguarded(m: Int, n: Int, g: Array<IntArray>, w: Array<IntArray>): Int {
        val c = Array(m) { IntArray(n) }; for ((y, x) in g+w) c[y][x] = 2; var x=0; var y=0
        for ((i, j) in g) for (f in setOf({--x;1},{++x;1},{--y;1},{++y;1})) { y=i; x=j; f()
            while (y in 0..<m && x in 0..<n && c[y][x] < 2) c[y][x] = f() }
        return c.sumOf { it.count { it < 1 }}
    }

// 31ms
    pub fn count_unguarded(m: i32, n: i32, g: Vec<Vec<i32>>, w: Vec<Vec<i32>>) -> i32 {
        let mut c = vec![vec![0;n as usize];m as usize]; for g in chain(&g,&w) { c[g[0] as usize][g[1] as usize]=2}
        for g in &g { for (i,j) in &[(-1,0),(0,1),(1,0),(0,-1)] { let (mut y, mut x)=(g[0]+i, g[1]+j);
            while y.min(x)>=0 && y<m && x<n && c[y as usize][x as usize] < 2 { c[y as usize][x as usize]=1; y+=i; x+=j}
        }} c.iter().flatten().filter(|&&v|v<1).count() as _
    }

01.11.2025

3217. Delete Nodes From Linked List Present in Array medium blog post substack youtube

44f34127-6606-4b69-bcaf-e5ac536eace9 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1160

Problem TLDR

Remove an array from linked list #medium #ll

Intuition

Convert the array to HashSet.

Approach

  • use a dummy node in a case of a removal of the first node from LL
  • use a nested while loop
  • code can be rewritten to a single while loop

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 47ms
    fun modifiedList(n: IntArray, h: ListNode?): ListNode? {
        val dummy = ListNode(0).apply { next = h }
        val s = n.toSet(); var curr = dummy
        while (curr.next != null)
            if (curr.next.`val` in s) curr.next = curr.next.next
            else curr = curr.next ?: break
        return dummy.next
    }

// 20ms
    pub fn modified_list(n: Vec<i32>, h: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
        let mut dummy = ListNode { val: 0, next: h };
        let mut cur = &mut dummy;  let mut s: HashSet<_> = n.iter().collect();
        while let Some(next_box) = cur.next.as_mut() {
            if s.contains(&next_box.val) {
                cur.next = next_box.next.take();;
            } else { cur = cur.next.as_mut().unwrap() }
        }
        dummy.next
    }

31.10.2025

3289. The Two Sneaky Numbers of Digitville easy blog post substack youtube

5cd75984-aef3-440e-932d-e589bbaac92e (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1159

Problem TLDR

Two extra numbers from 0..n #easy

Intuition

Use any of:

  • HashSet for visited
  • bitmask for visited
  • array itself for visited

The clever solution with bit manipulation:

  • total xor, no extras: a^b^c – can compute as x1
  • total xor for single extra: a^b^c^a
  • total xor for two extras: a^b^c^a^b – can compute as x2
  • xor of x1^x2: a^b^c ^ a^b^c^a^b = a^b – can compute as x1^x2

Now we have a^b, each bits is a different between a and b.

Split all given numbers by have or have-nots of this bit. xor(have_bit) = xx1 xor(have_not_bit) == xx2

Then split range numbers similarly: xor(have_bit) == yy1 xor(have_not_bit) == yy2

Then a = xx1 ^ yy1, b = xx2 ^ yy2

Approach

  • just brute-force

Complexity

  • Time complexity: \(O()\)

  • Space complexity: \(O()\)

Code

// 17ms
    fun getSneakyNumbers(n: IntArray) = 
        n.indices.filter { x -> n.count { it == x } > 1 }

// 0ms
    pub fn get_sneaky_numbers(n: Vec<i32>) -> Vec<i32> {
        let mut m = 0u128;
        n.into_iter().filter(|x| { let u = (1 << x) & m > 0; m |= 1<<x; u}).collect()
    }

30.10.2025

1526. Minimum Number of Increments on Subarrays to Form a Target Array hard blog post substack youtube

b16d3eb3-4cea-4656-acb3-37d6e6d4dbc8 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1158

Problem TLDR

Min +1 range increases to make target from zeros #hard

Intuition

    // *********  1
    // **  *****  2, 3
    // **  ** **  4, 5, 6
    //     *      7
    // 331143233

    // 6 7 7 2 1 2 2 1 3
    // 6                   6 levels
    //   7                 +1 level, (6..1 levels continue)
    //     7               +0 levels, (7..1 levels continue)
    //       2             -5 levels (7..3 stop, 2..1 continue) +5 ops
    //         1           -1        (2..2 stop, 1..1 continue) +1 ops
    //           2         +1        (1..2 continue)
    //             2       +0
    //               1     -1        (2..2 stop, 1..1 continue) +1 ops
    //                 3   +2        1..3 continue
    //                  end          (1..3 stop) +2 ops and +1 for level 1

Optimal strategy is the Tetris game: remove islands from the bottom. The number of ops is the number of islands. The number of islands is the number of decreases.

Approach

  • draw the picture
  • assume algorithm is linear, try to gain as much information at each step as possible

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 58ms
    fun minNumberOperations(t: IntArray) = 
        t.zip(t.drop(1)+0).sumOf { (a,b) -> max(0, a-b)}


// 0ms
    pub fn min_number_operations(t: Vec<i32>) -> i32 {
        t[0] + t.windows(2).map(|w| 0.max(w[1]-w[0])).sum::<i32>()
    }

29.10.2025

With All Set Bits easy blog post substack youtube

56938ebc-e4f5-4d0c-b54a-5848bbd610b3 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1157

Problem TLDR

Next all bits set number #easy #bits

Intuition

HighestOneBit shl 1 - 1

101
100 highest one bit
1000 shl 1
0111  -1

Approach

  • how to find highestOneBit?
  • we can brute force too (n..2*n).first { (it+1) and it == 0 }

Complexity

  • Time complexity: \(O(1)\)

  • Space complexity: \(O(1)\)

Code

// 0ms
    fun smallestNumber(n: Int) =
        (n.takeHighestOneBit() shl 1) - 1

// 0ms
    pub fn smallest_number(n: i32) -> i32 {
        i32::MAX >> n.leading_zeros() - 1 
    }

28.10.2025

3354. Make Array Elements Equal to Zero easy blog post substack youtube

20e665bd-064a-4623-bf91-44617549c8b7 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1156

Problem TLDR

Places & directions that lead the simulation to all zeros #easy #simualtion

Intuition

Try every combination of place and direction

Approach

  • without simulation: sum diff (left, right) must be less than 2

Complexity

  • Time complexity: \(O(n^3)\), n^2 for the simulation

  • Space complexity: \(O(n)\)

Code

// 261ms
    fun countValidSelections(n: IntArray) =
        n.indices.sumOf { s -> if (n[s] == 0) listOf(-1,1).count { d ->
            val n = n.clone(); var c = s; var d = d
            while (c in 0..<n.size) 
                if (n[c] > 0) { n[c]--; d *= -1; c += d } else c += d
            n.all { it == 0 }
        } else 0 }

// 2ms
    pub fn count_valid_selections(n: Vec<i32>) -> i32 {
        let (mut r, mut l, mut res) = (n.iter().sum::<i32>(),0,0);
        for n in n {
            l += n; r -= n;
            if n < 1 {
                if (l - r).abs() < 2 { res += 1 }
                if l == r { res += 1 }
            }
        } res
    }

27.10.2025

2125. Number of Laser Beams in a Bank medium blog post substack youtube

5a71695d-3b4c-4c0b-bbf8-0c85a67b717f (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1155

Problem TLDR

Count multiplications between rows #medium

Intuition

Total += previous * current (count ‘1’)

Approach

  • empty rows are irrelevant

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\) or O(1)

Code

// 56ms
    fun numberOfBeams(b: Array<String>) = b
    .mapNotNull { it.sumOf { it - '0' }.takeIf { it > 0 }}
    .windowed(2).sumOf { it[0]*it[1] }

// 0ms
    pub fn number_of_beams(b: Vec<String>) -> i32 {
        b.iter().map(|s| s.bytes().filter(|&b| b == b'1').count())
         .filter(|&c| c > 0).tuple_windows().map(|(a,b)| (a*b) as i32).sum()
    }

26.10.2025

2043. Simple Bank System medium blog post substack youtube

https://assets.leetcode.com/users/images/537d3343-674d-4aca-855d-70851800629b_1761473639.0489593.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1154

Problem TLDR

Design a bank #medium

Intuition

Reuse transfer = withdraw & deposit.

Approach

  • carefull with off-by-ones

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code

// 144ms
class Bank(val b: LongArray) {
    fun transfer(a1: Int, a2: Int, m: Long) = 
        a2 <= b.size && withdraw(a1, m) && deposit(a2, m)
    fun deposit(a: Int, m: Long) = 
        a <= b.size && { b[a-1] += m; true }()
    fun withdraw(a: Int, m: Long) = 
        a <= b.size && b[a-1] >= m && { b[a-1] -= m; true }()
}

// 13ms
struct Bank(Vec<i64>); impl Bank {
    fn new(b: Vec<i64>) -> Self { Self(b) }
    fn transfer(&mut self, a1: i32, a2: i32, m: i64) -> bool 
        { a2 as usize <= self.0.len() && self.withdraw(a1, m) && self.deposit(a2, m) }
    fn deposit(&mut self, a: i32, m: i64) -> bool 
        { let a = a as usize - 1; a < self.0.len() && { self.0[a] += m; true }}
    fn withdraw(&mut self, a: i32, m: i64) -> bool {
        let a = a as usize - 1;
        a < self.0.len() && self.0[a] >= m && { self.0[a] -= m; true }
    }
}

25.10.2025

1716. Calculate Money in Leetcode Bank easy blog post substack youtube

4ae592a1-851f-4053-b5e8-d1d641ed2a4b (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1153

Problem TLDR

Add increasing sum of money, drop weekly gain on mondays #easy

Intuition

Simulate.

    // 0 1 2 3  4  5  6
    // 7 8 9 10 11 12 13
    // 14
    // 1 2 3 4 5 6 7
    // 2 3 4 5 6 7 8   or prev + 7
    // 3 4 5 6 7 8 9   or prev + 7
    // 4 5 6 7 8 9 10  or prev + 7

The O(1) solutino: count weeks and remainder of days. Each week contributes as a sum of base7. Contribution of each bases is w(w-1)/2. Another week contribution is weekly gains, 7*(7+1)/2. They are just w*gains

Approach

  • draw the numbers to better understand the laws

Complexity

  • Time complexity: \(O(n)\) or O(1)

  • Space complexity: \(O(1)\)

Code

// 8ms
    fun totalMoney(n: Int) = (0..<n).sumOf { it % 7 + it / 7 + 1 }

// 0ms
    pub fn total_money(n: i32) -> i32 {
        let w = n/7; let d = n-7*w;
        let fullweeks = 28*w + 7*w*(w-1)/2;
        let taildays = d*(d+1)/2 + w*d;
        fullweeks + taildays
    }

24.10.2025

2048. Next Greater Numerically Balanced Number medium blog post substack youtube

18ff3401-d0bb-4fd6-9898-57577a733eec (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1152

Problem TLDR

First bigger number freq[digit]=digit #medium

Intuition

Brute-force is accepted. For the problem size of 10^6 the next value is 1224444 which is just 200k loop.

Approach

  • or we can try to generate all permutations; prune by length of the initial number

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 425ms
    fun nextBeautifulNumber(n: Int) = (n+1..n*21+1)
        .first { "$it".groupBy { it }.all { it.key-'0' == it.value.size }}


// 22ms
    pub fn next_beautiful_number(n: i32) -> i32 {
        (n+1..n*22+2).find(|&x| { let (mut y,mut f) = (x, [0;10]); 
            while y > 0 { f[(y%10)as usize] += 1; y /= 10 }
            (0..=9).all(|x| f[x] == x || f[x] < 1)
        }).unwrap() 
    }

23.10.2025

3461. Check If Digits Are Equal in String After Operations I easy blog post substack youtube

3706fdee-bab0-4c11-8a4b-bc83632f6439 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1151

Problem TLDR

Fold each pair to (a+b)%10 until 2 left #easy

Intuition

Just do the simulation

Approach

  • use windows
  • this problem has a hard solution for O(n): each digit repeats in Pascal triangle pattern coefficients, that is nCr(size-2, i) % 10. Then there are hard tricks to find %10.

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n)\)

Code


// 86ms
    fun hasSameDigits(s: String): Boolean = if (s.length < 3) s[0] == s[1] else
        hasSameDigits(s.map {it-'0'}.windowed(2).map {it.sum()%10}.joinToString(""))


    fun hasSameDigits(s: String): Boolean {
        fun nCr(n: Int, k: Int): Int {
            if (k < 0 || k > n) return 0
            var k = if (k > n - k) n - k else k; var c = 1.toBigInteger()
            for (j in 1..k) c = c.multiply((n - k + j).toBigInteger())
                                 .divide(j.toBigInteger())
            return c.mod(10.toBigInteger()).toInt()
        }
        var a = 0; var b = 0
        for (i in s.indices) {
            a = (a + nCr(s.length - 2, i) * (s[i] - '0')) % 10
            b = (b + nCr(s.length - 2, i - 1) * (s[i] - '0')) % 10
        }
        return a == b
    }


    fun hasSameDigits(s: String): Boolean {
        fun pascal(p: Int) = Array(p) { IntArray(p) }.also {
            for (i in 0..<p) {
                it[i][0] = 1; it[i][i] = 1
                for (j in 1..<i) it[i][j] = (it[i-1][j-1] + it[i-1][j])%p
            }
        }
        val pas2 = pascal(2); val pas5 = pascal(5)
        fun nCrLucas(nn: Int, kk: Int, p: Int, m: Array<IntArray>): Int {
            var n = nn; var k = kk; var res = 1 
            while (n > 0 || k > 0) {
                val ni = n % p; val ki = k % p; if (ki > ni) return 0
                res = (res * m[ni][ki]) % p
                n /= p; k /= p
            }
            return res
        }
        fun nCr10(n: Int, k: Int): Int {
            if (k < 0 || k > n) return 0
            val r2 = nCrLucas(n, k, 2, pas2); val r5 = nCrLucas(n, k, 5, pas5)
            var r = r5 + if ((r5 and 1) != (r2 and 1)) 5 else 0
            return r % 10
        }
        var a = 0; var b = 0
        for (i in s.indices) {
            a = (a + nCr10(s.length-2, i)   * (s[i] - '0')) % 10
            b = (b + nCr10(s.length-2, i-1) * (s[i] - '0')) % 10
        }
        return a == b
    }


// 0ms
    pub fn has_same_digits(s: String) -> bool {
        let mut v: Vec<_> = s.bytes().map(|c| c - b'0').collect();
        while v.len() >= 3 { v = v.windows(2).map(|w| (w[0] + w[1]) % 10).collect() }
        v[0] == v[1]
    }

22.10.2025

3347. Maximum Frequency of an Element After Performing Operations II hard blog post substack youtube

3caeb30d-45b6-49e7-8473-6c3f0bc032ab (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1150

Problem TLDR

Max frequency after changing +k..-k ops elements #medium #sliding_window

Intuition

    // its like yesterday problem
    // so we have two numbers 5,11     the k=5 but ops=1
    //                                 we can't change both
    // can we have same situation for 3 numbers?
    //           5,5,11   k=5 ops=2     the strategy min(o,2)*k didn't work

Solve two separate problems:

  1. choose every number as baseline, window b-k..b+k
  2. no baseline, just 2k window

Approach

  • the first is the frequency of baseline plus all opeations restricted by the window size
  • the second is the entire window restricted by the number of operations

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(n)\)

Code


// 180ms
    fun maxFrequency(n: IntArray, k: Int, o: Int): Int {
        n.sort(); var l = 0; var j = 0; var r = 0; var f = HashMap<Int,Int>()
        return n.withIndex().maxOf { (i,x) ->
            while (r < n.size && n[r] <= x+k) f[n[r]] = 1 + (f[n[r++]] ?: 0)
            while (l < n.size && n[l] < x-k) f[n[l]] = -1 + f[n[l++]]!!
            while (x - n[j] > 2*k) ++j
            max(min(f[x]!!+o, r-l), min(i-j+1, o))
        }
    }


// 42ms
    pub fn max_frequency(mut n: Vec<i32>, k: i32, o: i32) -> i32 {
        n.sort_unstable(); let (mut l, mut j, mut r, mut f) = (0,0,0,HashMap::new());
        n.iter().enumerate().map(|(i,&x)|{
            while r < n.len() && n[r] <= x+k { *f.entry(n[r]).or_insert(0) += 1; r += 1 }
            while l < n.len() && n[l] < x-k { *f.get_mut(&n[l]).unwrap() -= 1; l += 1 }
            while x - n[j] > 2*k { j += 1 }
            o.min((i-j+1)as i32).max((r-l) as i32).min(f[&x]+o)
        }).max().unwrap_or(0)
    }

21.10.2025

3346. Maximum Frequency of an Element After Performing Operations I medium blog post substack youtube

00ba3e93-d803-4aee-b4c2-be4f275895f9 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1149

Problem TLDR

Max frequency after changing +k..-k ops elements #medium #sliding_window

Intuition

Didn’t solved.

    // 5 6 7 8 10 15 20        k=5
    // maybe binary search? for resulting number in lowest..highest
    //       no rule for bs
    // sliding window
    // how to track how many was changed?
    // group?
    // 0 0 0 0 5 5 10 10 10   k=5 o=2
    // 0 0 0 0 5 5 10 10 10   k=5 o=1
    // 0 0 5 5 5 5            k=5 o=1
    // 0 1 1 1 5 5            k=5 o=1
    // maintain frequency of each element in window, know max frequency, 
    //   ans = min(max_frequency_in_window+ops, window_size)
    // for frequencies: running sorted window, keep map num:freq; when add sorted-f[num]+(++f[num])
    // looks complicated, maybe wrong 
    // 1: window is 2*k
    // 2: can't just use most frequent 
    // 35 minute: let's look for hints
    // try each as candidate (j)
    // how to count number of operations? window-curr_freq is not correct
    // 5 11 20 20 when current freq = 2 of '20'; to do the 2*k range we have to use 2 operations
    // and to do 1*k range we can use 0 operations
    // 1:14 failed on 58 80 5 let's give up

Solve two separate problems:

  1. choose every number as baseline, window b-k..b+k
  2. no baseline, just 2k window

Approach

  • sometimes there is no single algorithm, just separate tasks for different cases

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(n)\)

Code


// 125ms
    fun maxFrequency(n: IntArray, k: Int, o: Int): Int {
        n.sort(); var res = 0; var l = 0; var r = 0; var f = HashMap<Int,Int>()
        for (x in n) {
            while (r < n.size && n[r] <= x+k) f[n[r]] = 1 + (f[n[r++]] ?: 0)
            while (l < n.size && n[l] < x-k) f[n[l]] = -1 + f[n[l++]]!!
            res = max(res, min(f[x]!!+o, r - l))
        }
        l = 0
        return max(res, n.indices.maxOf { r ->  while (n[r] - n[l] > 2*k) ++l; min(r-l+1, o) })
    }


20.10.2025

2011. Final Value of Variable After Performing Operations easy blog post substack youtube

1476e184-c73b-4b5f-a496-0feaf1535283 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1148

Problem TLDR

do ++ or – operation from 0 #easy

Intuition

Simulate the process.

Approach

  • just check ‘+’ in string

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 7ms
    fun finalValueAfterOperations(o: Array<String>) = 
        2 * o.count { '+' in it } - o.size


// 1ms
    pub fn final_value_after_operations(o: Vec<String>) -> i32 {
        (o.join("").matches('+').count() - o.len()) as _
    }

19.10.2025

1625. Lexicographically Smallest String After Applying Operations medium blog post substack youtube

29a9832f-f303-48a8-af19-682d15e0734e (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1147

Problem TLDR

Min string after shifting by b and rotating odd indice by a #medium #bruteforce

Intuition

    // s is small, up to 100
    // if b is even:    12345678  34567812  56781234  78123456
    //                  1234567   3456712   5671234   7123456 2345671 4567123  6712345  1234567
    // if b is odd:     12345678  45678123  78123456  23456781  56781234 81234567 3.. 6.. 
    //                  1234567   4567123   7123456   3456712  6712345  2345671 5671234
    // so only when b%2 == 0 && size%2 == 0 we don't have access to all elements
    // the size is small, we can brute-force every possible rotation to get the minimum
    // rotation of digit: 1, a = 3: 1,4,7,0,3,6,9,2
    // 25 minute: forgot about odd indices
    // 40 minute: we can't change indices independently ?
    // 43987654 b=3
    // *  *  *
    // 01234567
    // 34567012
    // 67012345
    // 12345670
    // 45670123
    // 70123456
    // 23456701
    // 56701234
    // 01234567  so, all indices can be on the first position
    // 50 minute: wrong steps calculation
    // 12345678901234 14, step=6
    // 58016941393090
    // 41393090580169

    //     * *     *
    // 123456789abcde
    // 56789abcde1234

Two situations:

  1. odd length and odd shift: we can rotate only odd indices
  2. otherwise we can rotate odd indices and even indices

Approach

  • rotations should be for all indices; separate value of rotations for odd and even

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n)\)

Code


// 50ms
    fun findLexSmallestString(s: String, a: Int, b: Int) = s.indices.minOf { i ->
        fun rot(c: Char) = (0..9).minBy { (c-'0'+it*a)%10 }
        var sh = s.drop((i*b)%s.length)+s.take((i*b)%s.length)
        val eo = listOf(if (s.length % 2 == 0 && b % 2 == 0) 0 else rot(sh[0]), rot(sh[1]))
        sh.mapIndexed { i,c -> '0'+(c-'0' + eo[i%2]*a)%10 }.joinToString("")
    }


// 0ms
    pub fn find_lex_smallest_string(s: String, a: i32, b: i32) -> String {
        (0..s.len()).map(|i| {
            let rot = |c: u8| {(0..10).min_by_key(|&x| (c - b'0' +  x * a as u8) % 10).unwrap()};
            let sh = s.chars().cycle().skip((i * b as usize)%s.len()).take(s.len()).collect::<String>();
            let eo = [if (s.len() as i32|b)&1 < 1 {0} else {rot(sh.as_bytes()[0])}, rot(sh.as_bytes()[1])];
            sh.bytes().enumerate().map(|(i, c)| (b'0' + (c - b'0' + eo[i&1]*a as u8)%10) as char).collect()
        }).min().unwrap()  
    }

18.10.2025

3397. Maximum Number of Distinct Elements After Operations medium blog post substack youtube

2d4101ab-32f3-466d-ab2f-475bd5d27b01 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1146

Problem TLDR

Distincts count after adding -k..k to each #medium

Intuition

Sort. There is a window we can take from duplicates: -k, -k+1, …, k-1, k. Slide from the left, greedily apply lowest possible change to the number. Update max of used values.

Approach

  • don’t stop when current value is out of range, the next can be bigger

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(1)\)

Code


// 515ms
    fun maxDistinctElements(n: IntArray, k: Int): Int {
        var m = Int.MIN_VALUE; n.sort()
        return n.count { val r = m < it + k; if (m < it+k) m = max(m+1,it-k); r }
    }


// 20ms
    pub fn max_distinct_elements(n: Vec<i32>, k: i32) -> i32 {
        let mut m = i32::MIN;
        n.iter().sorted().filter(|&x| { let r = m < x+k; if (r) { m = (m+1).max(x-k)}; r }).count() as _
    }


17.10.2025

3003. Maximize the Number of Partitions After Operations medium blog post substack youtube

fb9e2b9c-0ec1-40cf-995a-41ec74832ea0 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1145

Problem TLDR

Max k-uniq parts after changing one letter #hard #prefix

Intuition

Didn’t solve.

    // accca    k=2
    // 12222
    // abcca
    // 123    cca
    // acbca
    // 123    bca  bc a
    // accba
    // 1223   ba

    // 47 minutes: my algo stuck in corner cases, looking for hints
    // partition_start is not very obvious
    // 56 minute: look for solution

Precompute suffix & prefix: parts count and uniqs count so far at i. Heuristic to split into three parts: left and right parts are full and uniqs are not full. Heuristic to not split: count uniqs is less than k, so letter should go to left or right. Otherwise split once.

Approach

  • prefix can be computed on the go

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 9ms
    fun maxPartitionsAfterOperations(s: String, k: Int): Int {
        val sf = Array(s.length) { IntArray(2) }
        var msk = 0; var part = 0; var res = 0
        for (i in s.lastIndex downTo 1) {
            val bit = 1 shl (s[i]-'a'); msk = msk or bit
            if (msk.countOneBits() > k) { part++; msk = bit }
            sf[i-1][0] = part; sf[i-1][1] = msk
        }
        msk = 0; part = 0
        for (i in 0..<s.lastIndex) {
            val cntall = (msk or sf[i][1]).countOneBits()
            res = max(res, part + sf[i][0] +
                if (msk.countOneBits() == k && sf[i][1].countOneBits() == k && cntall < 26) 2
                else if (min(cntall + 1, 26) <= k) 0 else 1)
            val bit = 1 shl (s[i]-'a'); msk = msk or bit
            if (msk.countOneBits() > k) { part++; msk = bit }
        }
        return res + 1
    }

16.10.2025

2598. Smallest Missing Non-negative Integer After Operations medium blog post substack youtube

cb628084-0ca6-4203-becb-a78cbcd2ab7b (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1144

Problem TLDR

First positive number can’t be build by adding/subtracting value #medium #hashmap

Intuition

Iterate from zero and look for the reminder. Use it or stop.

Approach

  • corner case: negatives
  • we can use array size of v as a frequency map

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 135ms
    fun findSmallestInteger(n: IntArray, v: Int): Int {
        val m = n.groupBy{ (it%v+v)%v }.mapValues{ it.value.size }.toMutableMap()
        return (0..n.size).first { val c = m[it%v]?:0; m[it%v]=c-1; c < 1 }
    }


// 0ms
    pub fn find_smallest_integer(n: Vec<i32>, v: i32) -> i32 {
        let mut f = vec![0; v as usize]; for &x in &n { f[((x%v+v)%v) as usize] += 1 }
        (0..=n.len()).find(|x| { let c = f[x%v as usize]; f[x%v as usize] -= 1; c < 1 }).unwrap() as _
    }

15.10.2025

3350. Adjacent Increasing Subarrays Detection II medium blog post substack youtube

8344491e-361e-498a-a277-dc8168c5c52a (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1143

Problem TLDR

Max k of adjucent increasing k-windows #medium #counting

Intuition

In a single iteration, count of increasing numbers. Drop on non-increasing. Compare with previous.

Approach

  • can use chunk_by and windows in Rust

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\), or O(n)

Code


// 870ms
    fun maxIncreasingSubarrays(n: List<Int>): Int {
        var a = 0; var b = 0; var p = 0
        return n.maxOf { n ->
            if (n > p) ++a else { b = a; a = 1 }
            p = n; max(a/2, min(a, b))
        }
    }


// 26ms
    pub fn max_increasing_subarrays(n: Vec<i32>) -> i32 {
        once(0).chain(n.chunk_by(|a,b| a < b).map(|c| c.len() as i32)).collect::<Vec<_>>()
        .windows(2).map(|c| c[0].min(c[1]).max(c[1]/2)).max().unwrap()
    }

14.10.2025

3349. Adjacent Increasing Subarrays Detection I medium blog post substack youtube

6a711a37-86e3-4929-b20f-737b09eb2b2f (1) (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1142

Problem TLDR

Any increasing consequent windows size k #easy

Intuition

Just brute-force every index. O(1) memory solution: count increasings, keep previous and current, check

Approach

  • corner case: single 2k increasing chunk

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\), can be O(1)

Code


// 379ms
    fun hasIncreasingSubarrays(n: List<Int>, k: Int) = n.indices
        .any { i -> fun List<Int>.g()=this==sorted()&&toSet().size==k;
            n.slice(i..<min(n.size,i+k)).g() && 
            n.slice(min(n.size-1,i+k)..<min(n.size,i+k+k)).g()
        }


// 5ms
    pub fn has_increasing_subarrays(n: Vec<i32>, k: i32) -> bool {
        once(0).chain(n.chunk_by(|a,b| a < b).map(|c|c.len() as i32))
        .collect::<Vec<_>>().windows(2).any(|c| c[0].min(c[1]).max(c[1]/2) >= k)
    }

13.10.2025

2273. Find Resultant Array After Removing Anagrams medium blog post substack youtube

ef5404c8-652d-4e6c-ac76-4e95cfe41880 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1141

Problem TLDR

Dedup anagrams #easy

Intuition

Simulate the process. The islands of equal-by-anagram are not influence each other when split by non-equal word.

Approach

  • going from left to right, take value if previous is not anagram to current
  • check anagrams by: a) sorting b) comparing the frequency map

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 42ms
    fun removeAnagrams(w: Array<String>) = w.take(1) + w.asList()
    .zipWithNext().mapNotNull {(a,b) -> b.takeIf{a.groupBy{it}!=b.groupBy{it}}}


// 3ms
    pub fn remove_anagrams(mut w: Vec<String>) -> Vec<String> {
       w.dedup_by_key(|w| w.bytes().counts()); w
    }

12.10.2025

3539. Find Sum of Array Product of Magical Sequences medium blog post substack youtube

4aab11ea-339f-4961-8990-f511ccadbe08 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1140

Problem TLDR

Product of all good subsequences and permutations #hard #combinatorics

Intuition

    // by looking at the constraints: full search may be possible
    // take 30 indices out of 50 nums
    // how to use sum(2^seq[i]) = k set bits
    // set bits are the sum of 2^bit1 + 2^bit2 + 2^bit3, where 1,2,3 are the set bits
    // 1..k..m..30
    //
    // after sequence is found, we should count permutations and multiply by product

    // 0 1 2 3 4 5   k=2 m=2
    //               2^0 + 2^1 = 1+2=3 = b011
    //               2^0 + 2^2 = 1+4=5 = b101
    // so it is just any-to-any permutations
    // 0:   1 2 3 4 5
    // 1: 0   2 3 4 5
    // 2: 0 1   3 4 5
    // 3: 0 1 2   4 5
    // 4: 0 1 2 3   5
    // 5: 0 1 2 3 4      5^5=25
    // choose k from n


    // no examples where k < m
    // 0 1 2 3 4 5   k=2 m=3
    // let's write brute-force to see the picture 2^50 too much

    // 39 minute: brute-force works, TLE for n=50,m=30,k=20
    // this can be about combinatorics, let's look for hint
    // 1 dp?, the nums can't be split, so we have to look at m and k
    // m=1,k=1: single bit, single index, powers of two 0 2 4 8 16 32 
    // m=2,k=1: single bit, two indices, choose two from previous
    // m=2,k=2: two bits, two indices:
    // 53 minute: ok, i looked at hints and decided to give up

    // basically inline checkmagic and prod compute in the dfs or not

Approach

  • maybe I should learn combinatorics

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 405ms
    fun magicalSum(m: Int, k: Int, nums: IntArray): Int {
        val dp = HashMap<Long, Long>(); val M = 1000000007L
        fun fact(n: Long): Long = if (n == 0L) 1L else (fact(n-1L)*n)%M
        fun pow(a:Long,x:Long):Long=if (x==1L)a else if(x==0L)1L else (pow(a*a%M,x/2)*pow(a,x and 1L))%M
        val fc = LongArray(m + 1); fc[m] = pow(fact(1L* m), M-2); for (i in m-1 downTo 0) fc[i] = (fc[i+1] * (i+1))%M
        fun nCr(n: Int, r: Int):Long = (((fact(1L*n) * fc[r]) % M) * fc[n-r])%M
        fun f(mask: Long, m: Int, k: Int, i: Int): Long = dp.getOrPut(mask*1000000+m*10000+k*100+i) {
            if (m == 0) return@getOrPut if (mask.countOneBits() == k) 1L else 0L
            if (i == nums.size) return@getOrPut 0L
            var res = 0L
            for (c in 0..m) {
                val perm = (nCr(m, c)*pow(1L*nums[i], 1L*c)) % M
                val sp = f((mask+c)/2, m-c, k-((mask+c) and 1).toInt(), i+1)
                res = (res + (perm * sp) % M)%M
            }
            res
        }
        return f(0, m, k, 0).toInt()
    }


11.10.2025

3186. Maximum Total Damage With Spell Casting medium blog post substack youtube

baf56442-2656-48e6-a7b6-9e1d24b736a1 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1139

Problem TLDR

Max sum of choosen values, skip v[i]+1+2-1-2 #medium #dp #sorting

Intuition

Thoughts process:

    // 31 minute: greedy doesn't work
    // 6  5  4 3
    // 12 15 8 6
    // *  x  x *
    // x  *  x x
    // x  x  * x
    // *  x  x *

    // * x x x x * skip up to 4 elements
    // don't see greedy, try dp
    // 53 minute TLE
  • sort and deduplicate
  • dp[i] is the result for suffix [i..]
  • dp[i] = max(take, notTake)
  • if take, find the next index of p[i]+2

Approach

  • to find next index you can use TreeMap.higherEntry(p+2)
  • solution from u/votrubac/: dp[i+1] is the result if dp[i] is taken; dp[i]=max(dp[..j]), p[j]+2 is less than p[i]

Complexity

  • Time complexity: \(O(nlog(n))\), solution uses TreeMap retrieval of log(n). Sorting is nlog(n).

  • Space complexity: \(O(n)\)

Code


// 813ms
    fun maximumTotalDamage(p: IntArray): Long {
        val pc = p.groupBy { it }.mapValues { it.value.size }
        val pi = TreeMap<Int, Int>(); val dp = HashMap<Int,Long>()
        val keys = pc.keys.sorted(); for (i in keys.indices) pi[keys[i]] = i
        fun dfs(i: Int): Long = if (i==keys.size) 0L else  dp.getOrPut(i) {
            val p = keys[i]
            max(1L*p*pc[p]!! + (pi.higherEntry(p+2)?.let { dfs(it.value)}?:0), dfs(i+1))
        }
        return dfs(0)
    }


// 38ms
    pub fn maximum_total_damage(mut p:Vec<i32>)->i64{
        let (mut d, mut m) = (vec![(0,0)], 0);
        p.iter().sorted().chunk_by(|&x|x).into_iter().map(|(&v, g)| {
            while d.len() > 0 && d[0].1+2 < v as i64 { m = d.remove(0).0.max(m) }
            d.push((v as i64 * g.count() as i64 + m, v as i64)); d[d.len()-1].0
        }).max().unwrap()
    }


10.10.2025

3147. Taking Maximum Energy From the Mystic Dungeon medium blog post substack youtube

6c72b184-248f-4f18-8f48-de7d078824ff (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1138

Problem TLDR

Max k-distant suffix sum #medium #array

Intuition

Each k sums have stable positions. Track k sums, drop if negative.

Approach

  • can be done in-place

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\) or O(1) with input mutation

Code


// 724ms
    fun maximumEnergy(e: IntArray, k: Int) = (e.size-1 downTo 0)
    .maxOf { e[it] += if (it+k < e.size) e[it+k] else 0; e[it] }


// 21ms
    pub fn maximum_energy(mut e: Vec<i32>, k: i32) -> i32 {
        let k = k as usize; for i in k..e.len() { e[i%k] = e[i] + 0.max(e[i%k]) }
        *e[..k].iter().max().unwrap()
    }

09.10.2025

3494. Find the Minimum Amount of Time to Brew Potions medium blog post substack youtube

ba3a9efc-683f-418d-852e-1d2799bf5e36 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1137

Problem TLDR

Min total time to finish all skills[i]*mana[j], non-intersecting #medium #bs

Intuition

The order is preserved. Binary Search the start time for each potion. Check if all next times are bigger then previous.

Approach

  • use Long.MAX_VALUE / 2 for right border of bs
  • n^2 solution from lee: optimal start(mana) = max_i(finish[i+1]-mana * sum(skills[0..i]))

Complexity

  • Time complexity: \(O(n^2log(n))\)

  • Space complexity: \(O(n)\)

Code


// 1681ms
    fun minTime(s: IntArray, m: IntArray): Long {
        val ts = LongArray(s.size + 1)
        for (p in m) {
            var lo = ts[0]; var hi = Long.MAX_VALUE / 2
            while (lo <= hi) {
                val m = (lo + hi)/2; var curr = m
                for (i in 1..<ts.size) {
                    if (curr < ts[i]) { curr = -1; break }
                    curr += s[i-1] * p
                }
                if (curr >= 0) hi = m - 1 else lo = m + 1
            }
            ts[0] = lo; for (i in 1..<ts.size) ts[i] = ts[i-1] + 1L * s[i-1] * p
        }
        return ts.last()
    }


// 53ms
    pub fn min_time(mut s: Vec<i32>, m: Vec<i32>) -> i64 {
        for i in 1..s.len() { s[i] += s[i - 1] }; let mut p = 0i64;
        (1..m.len()).map(|i|
            (1..s.len()).fold(s[0] as i64 * m[i - 1] as i64, |min, j|
                min.max(m[i-1] as i64 * s[j] as i64 - m[i] as i64 * s[j-1] as i64))
        ).sum::<i64>() + s[s.len()-1] as i64 * m[m.len()-1] as i64
    }

08.10.2025

2300. Successful Pairs of Spells and Potions medium blog post substack youtube

52c5b1de-7775-444b-971c-02899fbf9a0f (2).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1136

Problem TLDR

Number of potions * spells[i] bigger than success #midium #bs #sort

Intuition

Sort potions. Binary search value spells[i] * potions[j] < success.

Approach

  • or search for success + spells - 1 / spells withoud converting to double

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(n)\)

Code


// 105ms
    fun successfulPairs(sp: IntArray, p: IntArray, s: Long) = run { p.sort()
        sp.map { v -> 1 + p.size + p.asList().binarySearch{ if (1L*it*v < s) -1 else 1 }}}



// 17ms
    pub fn successful_pairs(sp: Vec<i32>, mut p: Vec<i32>, s: i64) -> Vec<i32> {
        p.sort_unstable(); let l = p.len() as i32;
        sp.iter().map(|&v| l - p.partition_point(|&p| v as i64 * (p as i64) < s) as i32).collect()
    }


07.10.2025

1488. Avoid Flood in The City medium blog post substack youtube

1 (5).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1135

Problem TLDR

Replace zeros with numbers to avoid duplicates #medium #binary_search #greedy

Intuition

    // 0 1 2 3 4 5 6 7 8 9 1011
    // 1 2 0 0 3 4 0 0 3 4 1 2
    //                 i       - first filled, use zero at index 2

    // 0 1 1 - corner case
    //     i -- can't use zero, because no zero before previous 1

    // 0 0 0 0 0 0 2 1 2

    // 0 0 0 0 0 0 2 0 0 1 2 1
    //       ^
    //       can i use any of these? - no

    // 1 2 0 0 3 4 0 0 3 4 1 2
    //             * * i       
    //     * *     * *     i      i can use zeros between duplicates
    //                            or, zero can be used for any element before it
    //
    //                            which one to choose? closest

    // 1 2 0 0 2 1
    // 1 2 0 2 0 1
    // 1 0 2 0 2 1

    // 1 2 0 1 0 2
    // 1 0 2 0 1 2

    // 0 1 1
    // i       zi  = [0]
    //   i     fi[1] = 1

    // 0 1 2 3 4 5 6
    // 1 0 2 3 0 1 2 
    // i         .     fi[1] = 0
    //   i       .     zi = [1]
    //     i     .     fi[2]=2
    //       i   .     fi[3]=3
    //         i .     zi=[1,4]
    //           i     prev=fi[1]=0, 4>1, res[4]=1, ok so this breaks 2
    //                                              closest is not optimal
    //                                    "smallest after"

  • remember zero days
  • when seeing a duplicate, pick the first zero after the previous duplicate instance

Approach

  • use the BinarySearch or TreeSet .higher(x)

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(n)\)

Code


// 64ms

    fun avoidFlood(r: IntArray): IntArray {
        val zi = TreeSet<Int>(); val fi = HashMap<Int, Int>()
        for ((i, l) in r.withIndex()) if (l > 0) {
            if (fi[l] != null) r[zi.higher(fi[l]) ?: return intArrayOf()] = l
                .also { zi -= zi.higher(fi[l]) }
            fi[l] = i; r[i] = -1
        } else { zi += i; r[i] = 1 }
        return r
    }



// 21ms

    pub fn avoid_flood(mut r: Vec<i32>) -> Vec<i32> {
        let (mut f, mut z) = (HashMap::new(), BTreeSet::new());
        for i in 0..r.len() { let l = r[i];
            if l == 0 { z.insert(i); r[i] = 1; continue }
            if let Some(&j) = f.get(&l) { 
                let Some(&d) = z.range(j+1..).next() else { return vec![] }; 
                r[d] = l; z.remove(&d); }
            f.insert(l, i); r[i] = -1
        } r
    }


06.10.2025

778. Swim in Rising Water hard blog post substack youtube

2b53bb4d-e70e-4e33-9ffa-ab8b910dab88 (1).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1134

Problem TLDR

Min time to swim to end, flooding every second #hard #bfs

Intuition

Iterate over time (0..50^2) and do BFS step while less than time. Or, just put time variable in a PriorityQueue.

Approach

  • another way is the BinarySearch: check reachability in O(n^2), do log(n) search in time
  • the simple 0-1 BFS didn’t work here: all times should be sorted

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(n)\)

Code


// 42ms
    fun swimInWater(g: Array<IntArray>): Int {
        val q = PriorityQueue<IntArray>(compareBy { it[0] })
        var r = g[0][0]; q += intArrayOf(r,0,0); g[0][0] = -1
        while (q.size > 0) {
            val (t,y,x) = q.poll(); r = max(r,t); if (y==g.size-1&&x==g[0].size-1) break
            for ((u,r) in listOf(0,1,0,-1,0).zipWithNext())
                if (x+r in g[0].indices && y+u in g.indices && g[y+u][x+r]>=0)
                    { q += intArrayOf(g[y+u][x+r],y+u,x+r); g[y+u][x+r] = -1 }
        }; return r
    }



// 0ms
    pub fn swim_in_water(mut g: Vec<Vec<i32>>) -> i32 {
        let (n,m,mut h) = (g.len(),g[0].len(), BinaryHeap::from([(-g[0][0],0,0)]));
        g[0][0] = -1; let mut r = 0;
        while let Some((t,y,x)) = h.pop() {
            r = r.max(-t); if (y,x) == (n-1,m-1) { break }
            for (u,r) in [(y-1,x),(y+1,x),(y,x-1),(y,x+1)] {
                if u < n && r < m && g[u][r] >= 0 { h.push((-g[u][r],u,r)); g[u][r] = -1 }
        }} r  
    }


05.10.2025

417. Pacific Atlantic Water Flow medium blog post substack youtube

1 (4).webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1133

Problem TLDR

Cells travel to TL&BR in decrease order #medium #dfs

Intuition

Think in reverse: travel from oceans in increase order and mark with 1 and 2. Collect both marks.

Approach

  • you already can collect on a second DFS run
  • the marking DFS can run in any order
  • for BFS: put (y,x,mask) to queue, go from walls, same logic

Complexity

  • Time complexity: \(O()\)

  • Space complexity: \(O()\)

Code


// 31ms
    fun pacificAtlantic(h: Array<IntArray>) = buildList<List<Int>> {
        val v = Array(h.size) { IntArray(h[0].size) }
        fun dfs(y: Int, x: Int, m: Int) {
            if (v[y][x] and m > 0) return; v[y][x] = v[y][x] or m
            if (v[y][x] > 2) add(listOf(y, x))
            for ((r,u) in listOf(-1,0,1,0,-1).zipWithNext())
            if (x+r in h[0].indices && y+u in h.indices && h[y+u][x+r]>=h[y][x]) dfs(y+u,x+r,m)
        }
        for (y in h.indices) { dfs(y, 0, 1); dfs(y, h[0].size-1, 2) }
        for (x in h[0].indices) { dfs(0, x, 1); dfs(h.size-1, x, 2) }
    }




// 0ms
    pub fn pacific_atlantic(h: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
        let (m,n) = (h.len(),h[0].len()); let mut q = Vec::with_capacity(m*n);
        let (mut v,mut res) = (vec![0u8;m*n],vec![]);
        for i in 0..m { q.push((i,0,1)); q.push((i,n-1,2)) }
        for i in 0..n { q.push((0,i,1)); q.push((m-1,i,2)) }
        while let Some((y,x,b)) = q.pop() {
            if v[y*n+x]&b<1 { v[y*n+x] |= b; if v[y*n+x]>2 { res.push(vec![y as i32,x as i32]) }
            for (u,r) in [(y-1,x),(y+1,x),(y,x-1),(y,x+1)] {
                if u<m && r<n && h[u][r] >= h[y][x] { q.push((u,r,b)) }
        }}} res
    }


04.10.2025

11. Container With Most Water medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1132

Problem TLDR

Max water container from two heights #medium #two-pointers

Intuition

Start with two pointer at max distance. Decrease distance by 1 by moving the lower height pointer. The length only decreases, so drop the lower height, it will not be better than the current.

Approach

  • if heights are equal move any pointer or both (to change minimum)

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 38ms
    fun maxArea(h: IntArray) =
        (h.lastIndex downTo 0).fold(0 to 0) { (r,i), l ->
            max(r,l*min(h[i],h[i+l])) to if (h[i]<h[i+l]) i+1 else i
        }.first




// 1ms
    pub fn max_area(h: Vec<i32>) -> i32 {
        (0..h.len()).rev().fold((0,0),|(r,i),l|
            (r.max(l as i32*h[i].min(h[i+l])),i+((h[i]<h[i+l])as usize))).0
    }


03.10.2025

407. Trapping Rain Water II hard blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1131

Problem TLDR

Fill water in 3D #hard #dfs #sorting

Intuition

I solved it not optimally in 50 minutes O(n^2) (accepted). Go layer-by-layer, DFS in each layer and find the min value of greater cells.

The optimal solution: go layer-by-layer, advance just single step, put back into queue with new height value min(lvl, next).

Approach

  • use priority_queue
  • use visited set or modify the grid

Complexity

  • Time complexity: \(O(n^2)\) or O(nlog(n))

  • Space complexity: \(O(n)\)

Code


// 1968ms
    fun trapRainWater(h: Array<IntArray>): Int {
        val w = h[0].size; 
        val q = PriorityQueue<Int>(compareBy{h[it/w][it%w]}); q += (0..<w*h.size)
        var lvl = 0; var res = 0; var curr = 0; val visited = HashSet<Int>()
        while (q.size > 0) {
            val yx = q.poll(); val (y, x) = yx/w to yx%w; val clvl = h[y][x]
            if (clvl > lvl) { res += curr; curr = 0; lvl = clvl; visited.clear() }
            var min = Int.MAX_VALUE
            fun dfs(y: Int, x: Int): Int {
                if (y<0||x<0||y>h.size-1||x>w-1) { min = 0; return@dfs 0 }
                if (h[y][x] > clvl) {min = min(min, h[y][x]);return@dfs 0}
                if (!visited.add(y*w+x)) return@dfs 0
                return@dfs 1 + dfs(y-1,x) + dfs(y+1,x) + dfs(y,x-1) + dfs(y,x+1)
            }
            curr += max(0, dfs(y,x)*(min-clvl))
        }
        return res
    }




// 7ms
    pub fn trap_rain_water(mut height_map: Vec<Vec<i32>>) -> i32 {
        let (m, n, mut r) = (height_map.len(), height_map[0].len(), 0);
        let mut q = BinaryHeap::new();
        for y in 0..m { for x in 0..n { if (y.min(x) < 1 || y == m - 1 || x == n - 1) {
            q.push((-height_map[y][x], y, x)) }}}
        while let Some((min, y, x)) = q.pop() {
            height_map[y][x] = -1; let min = -min;
            for (y1, x1) in [(y, x - 1), (y - 1, x), (y, x + 1), (y + 1, x)] {
                if (0..m).contains(&y1) && (0..n).contains(&x1) && height_map[y1][x1] >= 0 {
                    q.push((-min.max(height_map[y1][x1]), y1, x1));
                    r += 0.max(min - height_map[y1][x1]); height_map[y1][x1] = -1
                }}
        }; r
    }


02.10.2025

3100. Water Bottles II medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1130

Problem TLDR

Total drinks with growing exchange rate empty for full #medium #simulation

Intuition

Simulate the process. Don’t forget to keep lefover empty bottles.

Approach

  • there is a O(1) math solution exists

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 103ms
    fun maxBottlesDrunk(b: Int, x: Int, e: Int = 0): Int =
    b + if (b+e<x) 0 else maxBottlesDrunk(1,x+1,b+e-x)




// 3ms
    pub fn max_bottles_drunk(mut b: i32, mut x: i32) -> i32 {
        let (mut e, mut d) = (0, 0);
        while b > 0 || e >= x {
            d += b; e += b; b = if (e < x) {0} else {e-=x;x+=1;1};
        } d
    }


01.10.2025

1518. Water Bottles easy blog post substack youtube

1.jpg

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1129

Problem TLDR

Total drinks with exchange empty for full #easy #simulation

Intuition

Simulate the process. Don’t forget to keep lefover empty bottles.

Approach

  • the single math formula can be derived from: s = b + b/x + (b/x+b%x)/x + ((b/x+b%x)/x+(b/x+b%x)%x)/x...
  • or s = b*(1 + 1/x + 1/x^2 + 1/x^3 + ...), geometric series converges to 1/(1-r) where r=1/x
  • so s = b*(1/(1-1/x)) = b/(1-1/x) = b*x/(x-1) (ask chatgpt why it is (b*x-1) instead)

Complexity

  • Time complexity: \(O(1)\)

  • Space complexity: \(O(1)\)

Code


// 0ms
    fun numWaterBottles(b: Int, x: Int, e: Int = 0): Int = 
    b + if (b < 1) 0 else numWaterBottles((b+e)/x, x, (b+e)%x)




// 0ms
    pub fn num_water_bottles(b: i32, x: i32) -> i32 {
        (b*x-1)/(x-1)
    }


30.09.2025

2221. Find Triangular Sum of an Array medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1128

Problem TLDR

Triangle sum % 10 #medium #simulation

Intuition

The problem is small 1000, O(n^2) simulation is accepted.

The O(n) intuition (from Stefan Pochmann):

  • each position get repeated Pascal’s Triangle times
    1
    1 1
    1 2 1
    1 3 3 1
    1 4 6 4 1
    1 5 10 10 5 1
    1 6 15 20 15 6 1
    

    Each new row value is a binomial coefficient (https://en.wikipedia.org/wiki/Binomial_coefficient) mC(k+1) = mCk *(n-1-k)/(k+1) Division by /(k+1) can’t be safely done with %10.

Approach

  • windows.map = zipWithNext

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n)\)

Code


// 226ms
    fun triangularSum(n: IntArray) = (2..n.size)
    .fold(n.asList()){r,_->r.zipWithNext{a,b->(a+b)%10}}[0]


    fun triangularSum(n: IntArray): Int {
        var f = 1.toBigInteger()
        var r = 0.toBigInteger()
        for ((i, x) in n.withIndex()) {
            r = (r + f * x.toBigInteger()).mod(10.toBigInteger())
            f = f * (n.size - 1 - i).toBigInteger() / (i + 1).toBigInteger()
        }
        return r.toInt()
    }



// 27ms
    pub fn triangular_sum(n: Vec<i32>) -> i32 {
        (1..n.len()).fold(n,|r,t|r.into_iter().tuple_windows().map(|(a,b)|(a+b)%10).collect())[0]
    }


29.09.2025

1039. Minimum Score Triangulation of Polygon medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1127

Problem TLDR

Min sum of triangle product for every possible triangulation #medium #dp

Intuition

Used the hint.

How to triangulate: keep first and last vertice, try every possible third between them. Memorize for every possible from and to.

    // 3745
    // 
    //    3       7
    //
    //
    //    5       4
    //
    // 375+457 or 345+347
    //
    // 1 3 1 4 1 5
    //
    //       1    3
    //                 1
    //
    //                 4
    //       5     1
    //
    // 113 114 115 111
    //
    // how to triangulate? can't do 111+345
    // maybe recursive? (is it 50^50?)
    // 1 3 1 4 1 5
    // 1 3 1 + 1 1 4 1 5
    // 29 minute: every time we have a ring, just choose the top 2 and split at them
    // but what if they are consequtive?
    //
    // 0 1 2 3 4 5 6 
    //   *     *
    // 43 minute (solved for max instead of min)
    // 45 minute (the two vertex algo is not optimal)
    // should we peek 3 vertices?
    // 51 minute: wrong answer 2144
    //
    //  2    1
    //       
    //  4    4
    // looks like just picking min values is not enough
    // 54 minute take hints: just a single split?
    // 76 minute TLE (with dp?) [5,80,62,45,96,100,17,72,67,64,20,66,41,68,34,67,35,24,76,2]
    // ^ language syntax error

Approach

  • the hardest part is to find a clever triangulation technique

Complexity

  • Time complexity: \(O(n^3)\)

  • Space complexity: \(O(n^2)\)

Code


// 58ms
    fun minScoreTriangulation(v: IntArray): Int {
        val l = v.asList(); val dp = HashMap<Pair<Int, Int>, Int>()
        fun d(from: Int, to: Int): Int = if (to-from+1 < 3) 0 else dp.getOrPut(from to to) 
            { (from+1..<to).minOf { l[it]*l[from]*l[to] + d(from, it) + d(it, to) } }
        return d(0, v.lastIndex)
    }




// 0ms
    pub fn min_score_triangulation(v: Vec<i32>) -> i32 {
        let mut d = [[0;50];50];
        for i in (0..v.len()).rev() { for j in (i+1..v.len()) { for k in (i+1..j) {
            d[i][j]=(d[i][k]+d[k][j]+v[i]*v[j]*v[k]).min(if d[i][j]==0 {i32::MAX}else {d[i][j]})
        }}}; d[0][v.len()-1]
    }


28.09.2025

976. Largest Perimeter Triangle easy blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1126

Problem TLDR

Max triangle perimeter from array of lengths #easy #sliding_window

Intuition

Sort. Consider every 3-sliding window from biggest: when a+b <= c move next, discard the c, otherwise finish. When c is bigger than closes a+b, then it will be bigger than any other pair sum.

Approach

  • this is not an easy problem

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(n)\) or O(1)

Code


// 81ms
    fun largestPerimeter(n: IntArray) = 
        max(0, n.sorted().windowed(3)
        .maxOf{(a,b,c) -> (a+b+c)*(a+b).compareTo(c)})




// 0ms
    pub fn largest_perimeter(n: Vec<i32>) -> i32 {
        n.iter().sorted_by_key(|&x|-x).tuple_windows()
        .find(|&(c,b,a)| a+b>*c).map_or(0, |(a,b,c)| a+b+c)
    }


27.09.2025

812. Largest Triangle Area easy blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1125

Problem TLDR

Max area triangle #easy

Intuition

Brute-force & Google for formula.

Approach

  • max are triangle lies on a convex-hull

Complexity

  • Time complexity: \(O(n^2log(n))\) or n^2

  • Space complexity: \(O(1)\)

Code


// 31ms
    fun largestTriangleArea(p: Array<IntArray>) =
        p.maxOf {(x1,y1)-> p.maxOf{(x2,y2)-> p.maxOf{(x3,y3) ->
        abs((x2-x1)*(y3-y1)-(x3-x1)*(y2-y1)) }}} * 0.5




// 3ms
    pub fn largest_triangle_area(p: Vec<Vec<i32>>) -> f64 {
        let mut r = 0f64;
        for p1 in &p { for p2 in &p { for p3 in &p {
            r = r.max(((p2[0]-p1[0])*(p3[1]-p1[1])-(p3[0]-p1[0])*(p2[1]-p1[1])).abs()as f64)
        }}}; r * 0.5
    }


26.09.2025

611. Valid Triangle Number medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1124

Problem TLDR

Count triangles can be made from numbers #medium #binary_search #two_sum

Intuition

Sort. Binary Search: for every pair of numbers a and b search for c in [b-a..b+a] Two Sum: same idea, but left border is always goes forward, so we can do increament instead of bs

Approach

  • for the BinarySearch upper bound is already less than a+b, the range is [0..a]

Complexity

  • Time complexity: \(O(n^2log(n))\) or n^2

  • Space complexity: \(O(1)\)

Code


// 113ms
    fun triangleNumber(n: IntArray): Int {
        n.sort()
        return (2..<n.size).sumOf { i ->
            (1..<i).sumOf { j ->
                var lo = 0; var hi = j-1
                while (lo <= hi) {
                    val m = (lo + hi) / 2
                    if (n[m] > n[i]-n[j]) hi = m - 1 else lo = m + 1
                }
                j - lo
            }
        }
    }



// 44ms
    fun triangleNumber(n: IntArray): Int {
        n.sort()
        return (2..<n.size).sumOf { i ->
            var l = 0; var r = i-1; var c = 0
            while (l < r) if (n[l] + n[r] > n[i]) c += r-- -l else ++l
            c
        }
    }




// 18ms
    pub fn triangle_number(mut n: Vec<i32>) -> i32 {
        n.sort_unstable();
        (2..n.len()).map(|i| {
            let (mut l, mut r, mut c) = (0, i-1, 0);
            while l < r { if n[l]+n[r] > n[i] { c += r-l; r-=1} else { l+=1}}
            c as i32
        }).sum()
    }


25.09.2025

120. Triangle medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1123

Problem TLDR

Min path sum in triangle #medium #dp

Intuition

Go from top to bottom, keeping the previous result: curr[i] = t[j][i] + min(prev[i], prev[i-1])

Approach

  • careful with out of bounds exceptions
  • use Int.MAX_VALUE / 200

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 19ms
    fun minimumTotal(t: List<List<Int>>) = t.drop(1)
    .fold(t[0]) { p,t -> listOf(p[0] + t[0]) + (1..<t.size)
        .map { i-> t[i]+min(p[min(i, p.size-1)],p[i-1])}}.min()




// 0ms
    pub fn minimum_total(t: Vec<Vec<i32>>) -> i32 {
        t.iter().skip(1).fold(vec![t[0][0]], |p, r| { once(p[0]+r[0])
            .chain((1..r.len()).map(|i| r[i]+p[i.min(p.len()-1)].min(p[i-1]))).collect()
        }).into_iter().min().unwrap()
    }


24.09.2025

166. Fraction to Recurring Decimal medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1122

Problem TLDR

Calc a/b to string x.y(z) #medium #math

Intuition

Gave up to implement this correctly.

    // how to know it is repeating?
    // let's just brute-force 10^4 digits
    // ok, how to find repeats? kmp (i forgot it)?
    // just store visited "(a/b)"
    // ok 43 minute, looks for hints, any simpler ideas? (no)
    // decide to give up, no time for debugging this

The ideas:

  • to divide 1/3 multiply 1*10, and repeat the problem for 1%3 / 3
  • to find the repeating part remember the problem “1/3” or just “1”
  • to find where the repeating part start, remember the positions for each key “1”
  • solve the part before “.” before going next

Approach

  • abs(Int.MIN_VALUE) == Int.MIN_VALUE, convert to longs before abs

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 2ms
    fun fractionToDecimal(n: Int, d: Int) = buildString {
        if (1L * n.sign * d.sign < 0) append("-")
        var n = abs(1L*n); val d = abs(1L*d)
        append(n / d); n %= d; if (n > 0L) append(".")
        val visited = HashMap<Long, Int>()
        while (n > 0L) {
            n *= 10; append(n / d); n %= d
            visited.put(n, length)?.let {
                insert(it, "("); append(")"); n = 0L
            }
        }
    }



// 0ms
    pub fn fraction_to_decimal(n: i32, d: i32) -> String {
        let (n, d, mut s) = (n as i64, d as i64, String::new());
        if n * d < 0 { s.push('-') }; let (n, d) = (n.abs(), d.abs());
        s.push_str(&(n/d).to_string()); let mut n = n % d; if n > 0 {s.push('.')};
        let mut m = HashMap::new();
        while n > 0 {
            if let Some(&i) = m.get(&n) { s.insert(i, '('); s.push(')'); break }
            m.insert(n, s.len()); n *= 10; s.push_str(&(n/d).to_string()); n %= d
        } s
    }


23.09.2025

165. Compare Version Numbers medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1121

Problem TLDR

Compare versions x.x.x.x #medium

Intuition

Pad start strings or convert to ints.

Approach

  • 25 characters for pad start
  • pad lists of numbers length to the largest

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 23ms
    fun compareVersion(v1: String, v2: String) = listOf(v1, v2)
        .map { it.split('.').map {it.toInt()}}
        .let { (a, b) -> val d = List(abs(a.size - b.size)){0}; (a+d).zip(b+d)}
        .map { (a, b) -> a.compareTo(b) }.firstOrNull { it != 0 } ?: 0



// 0ms
    pub fn compare_version(v: String, w: String) -> i32 {
        v.split('.').zip_longest(w.split('.')).map(|e|e.or("0","0"))
        .map(|(l,r)|l.parse::<i32>().unwrap().cmp(&r.parse::<i32>().unwrap()) as i32)
        .find(|&x| x != 0).unwrap_or(0)
    }


22.09.2025

3005. Count Elements With Maximum Frequency easy blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1120

Problem TLDR

Count max-freq elements #easy #counting

Intuition

Maintain frequency map. Count on-line or in the second iteration.

Approach

  • for n=100 brute force is accepted

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n)\)

Code


// 13ms
    fun maxFrequencyElements(n: IntArray) =
    n.groupBy{it}.values.map{it.size}.run {max()*count{it==max()}}



// 1ms
    fun maxFrequencyElements(n: IntArray): Int {
        var res = 0; var maxF = 0; val f = IntArray(101)
        for (x in n) if (++f[x] > maxF) { maxF = f[x]; res = 1 }
                     else if (f[x] == maxF) ++res;
        return res * maxF
    }




// 0ms
    pub fn max_frequency_elements(mut n: Vec<i32>) -> i32 {
        n.sort_unstable(); n.chunk_by(|a, b| a == b)
        .fold((0, 0, 0), |r, c| if c.len() > r.0 { (c.len(), 1, c.len())} 
            else if c.len() == r.0 { (r.0, r.1 + 1, r.0 * (r.1+1))} else { r }).2 as _
    }


21.09.2025

1912. Design Movie Rental System medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1119

Problem TLDR

Design Movie Rent: rent,drop,search(5 lowest), report(5 lowest rented) #hard #ds

Intuition

To search by movie use a HashMap movie-TreeSet(price shop).  
To report 5 lowest rented use a TreeSet<(price shop movie)>.

Approach

  • TreeSet uses comparator to check uniqness, add movie to the key

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n)\)

Code


// 608ms
class MovieRentingSystem(n: Int, e: Array<IntArray>): 
TreeSet<IntArray>(compareBy({it[2]},{it[0]},{it[1]})) {
    val smp = e.groupBy {it[0]}.mapValues{(_,v) -> v.associate {it[1] to it}}
    val mps = e.groupBy {it[1]}.mapValues{(_,v) -> TreeSet(comparator()).also{it+=v}}
    fun search(m: Int) = mps[m]?.take(5)?.map {it[0]} ?: listOf()
    fun rent(s: Int, m: Int) = smp[s]!![m]!!.let {this += it; mps[m]!! -= it}
    fun drop(s: Int, m: Int) = smp[s]!![m]!!.let {this -= it; mps[m]!! += it}
    fun report() = take(5).map {it.take(2)}
}




// 99ms
type PSM = (i32,i32,i32); #[derive(Default)]
struct MovieRentingSystem(BTreeSet<PSM>,HashMap<i32,HashMap<i32,PSM>>,HashMap<i32,BTreeSet<PSM>>);
impl MovieRentingSystem {
    fn new(_: i32, e: Vec<Vec<i32>>) -> Self {
        let mut s = Self::default(); for v in e { let t=(v[2],v[0],v[1]);
        s.1.entry(v[0]).or_default().insert(v[1],t); s.2.entry(v[1]).or_default().insert(t);}; s }
    fn search(&self, m: i32)->Vec<i32>{self.2.get(&m).iter().flat_map(|s|s.iter().take(5).map(|t|t.1)).collect() }
    fn rent(&mut self, s: i32, m: i32){let t=self.1[&s][&m];self.0.insert(t);self.2.get_mut(&m).unwrap().remove(&t);}
    fn drop(&mut self, s: i32, m: i32){let t=self.1[&s][&m];self.0.remove(&t);self.2.get_mut(&m).unwrap().insert(t);}
    fn report(&self) -> Vec<Vec<i32>> {self.0.iter().take(5).map(|t|vec![t.1,t.2]).collect()}
}


20.09.2025

3508. Implement Router medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1118

Problem TLDR

Design Router: addPacket, forwardPacket, getCount(dst, ts start..end) #medium #ds

Intuition

The main difficulty is the getCount, we have to maintain some sorted order of timestamps, but there are duplicates.

  • use map dst to sorted timestamps for getCount; do binarysearch
  • use LinkedList or ArrayDeque or IntArray(limit) for FIFO adding/removal
  • use HashSet to skip duplicates

Approach

  • remember binary search: always check lo <= hi, always do hi=m-1 or lo=m+1, update value if in condition
  • skip the second binary search if the first gives out of range idx
  • when removing forwardPacket from byDst list we always remove the first (it is theoretically O(n) call, but there is no testcase for this; to improve have to track pointer to first and do garbage collection)

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n)\)

Code


// 291ms
class Router(val limit: Int) : LinkedHashSet<List<Int>>() {
    val byDst = HashMap<Int, ArrayList<Int>>()
    fun addPacket(src: Int, dst: Int, ts: Int) = 
        add(listOf(src,dst,ts)) && { if (size > limit) forwardPacket()
        byDst.getOrPut(dst) { ArrayList() } += ts; true }()
    fun forwardPacket() = firstOrNull()?.also {
            this -= it; byDst[it[1]]?.removeFirst()
        }?.toIntArray() ?: intArrayOf()
    fun getCount(dst: Int, st: Int, et: Int) = byDst[dst]?.run {
        binarySearch { if (it < st) -1 else 1 } -
        binarySearch { if (it <= et) -1 else 1 } } ?: 0
}




// 76ms
#[derive(Default)] struct Router(i32, VecDeque<[i32;3]>,HashMap<i32,Vec<i32>>,HashSet<[i32;3]>);
impl Router {
    fn new(l: i32) -> Self { let mut s = Self::default(); s.0 = l; s }
    fn add_packet(&mut self, s: i32, d: i32, t: i32) -> bool {
        let k = [s,d,t]; self.3.insert(k) && {
        self.1.push_back(k); self.2.entry(d).or_default().push(t);
        if self.1.len() as i32 > self.0 { self.forward_packet(); } true }
    }
    fn forward_packet(&mut self) -> Vec<i32> {
        self.1.pop_front().map(|k|{
            self.3.remove(&k); self.2.get_mut(&k[1]).map(|v|v.remove(0)); k.into()
        }).unwrap_or_default()
    }
    fn get_count(&self, d: i32, s: i32, e: i32) -> i32 {
        self.2.get(&d).map_or(0, |v|v.partition_point(|&x|x<=e)-v.partition_point(|&x|x<s)) as _
    }
}


19.09.2025

3484. Design Spreadsheet medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1117

Problem TLDR

Design Spreadsheet: setCell, resetCell, getValue(a+b) #medium #ds

Intuition

Rows count is small 1000, we can store all in two-dimensional array. Formula are just a single shot, without going recursive.

Approach

  • using a HashMap saves LOC and string parsing
  • single array: key = (c[0]-'A') * rows + c[1..].toInt()

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 205ms
class Spreadsheet(rows: Int) : HashMap<String, Int>() {
    fun setCell(c: String, v: Int) = put(c, v)
    fun resetCell(c: String) = put(c, 0)
    fun getValue(f: String) = f.drop(1).split("+")
        .sumOf { if (it[0].isDigit()) it.toInt() else get(it) ?: 0 }
}


// 30ms struct Spreadsheet([i32;26001]); impl Spreadsheet { fn new(_: i32) -> Self { Spreadsheet([0;26001]) } fn k(&self, c: &str) -> usize { let b = c.as_bytes(); (b[0]-b’A’)as usize*1000+c[1..].parse::().unwrap()} fn set_cell(&mut self, c: String, v: i32) { self.0[self.k(&c.as_str())] = v } fn reset_cell(&mut self, c: String) { self.set_cell(c, 0) } fn get_value(&self, f: String) -> i32 { f[1..].split('+').map(|t|t.parse().unwrap_or_else(|_| self.0[self.k(&t)])).sum() } }


# 18.09.2025
[3408. Design Task Manager](https://leetcode.com/problems/design-task-manager/description) medium
[blog post](https://leetcode.com/problems/design-task-manager/solutions/7201935/kotlin-rust-by-samoylenkodmitry-5a7v/)
[substack](https://open.substack.com/pub/dmitriisamoilenko/p/18092025-3408-design-task-manager?r=2bam17&utm_campaign=post&utm_medium=web&showWelcomeOnShare=true)
[youtube](https://youtu.be/HdtbT_rT1v0)

![1.webp](/assets/leetcode_daily_images/b33d4f9a.webp)


https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

#### Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1116

#### Problem TLDR

Design Scheduler: add, edit, remove, execute by priority #medium #ds

#### Intuition

Use TreeMap + TreeSet

#### Approach

* we can use a single key mask for priority `p * 10^5 + tid`
* lazy removal seems to speed up; didn't implemented it here

#### Complexity

- Time complexity:
$$O(nlogn)$$

- Space complexity:
$$O(n)$$

#### Code

```kotlin

// 358ms
class TaskManager(tasks: List<List<Int>>): TreeMap<Long, Int>() {
    val tp = HashMap<Int, Int>()
    init { for ((uid, tid, p) in tasks) add(uid, tid, p) }
    fun add(uid: Int, tid: Int, p: Int) { put(key(p, tid), uid); tp[tid] = p }
    fun key(p: Int, tid: Int): Long = 1L * p * 100_000 + tid
    fun key(tid: Int): Long = key(tp[tid]!!, tid)
    fun edit(tid: Int, p: Int) = add(rmv(tid), tid, p)
    fun rmv(tid: Int) = remove(key(tid)) ?: -1
    fun execTop(): Int = pollLastEntry()?.value ?: -1
}




// 118ms
#[derive(Default)] struct TaskManager(BTreeMap<(i32, i32), i32>, HashMap<i32, i32>);
impl TaskManager {
    fn new(v: Vec<Vec<i32>>) -> Self {
        let mut m = Self::default();
        for a in v { m.add(a[0], a[1], a[2]) }; m
    }
    fn add(&mut self, u: i32, i: i32, p: i32) 
        { self.0.insert((p, i), u); self.1.insert(i, p); }
    fn edit(&mut self, i: i32, p: i32) { let u = self.rmv(i); self.add(u, i, p) }
    fn rmv(&mut self, i: i32) -> i32 {
        let k = (self.1[&i], i); self.1.remove(&i); self.0.remove(&k).unwrap_or(-1)
    }
    fn exec_top(&mut self) -> i32 { self.0.pop_last().map(|(_, v)| v).unwrap_or(-1) }
}


17.09.2025

2353. Design a Food Rating System medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1115

Problem TLDR

Food rating system: change rating, peek highest by type #medium #ds

Intuition

Make TreeSet buckets for each cuisine.

Approach

  • don’t modify the rating while item in the TreeSet

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n)\)

Code


// 340ms
class FoodRatings(val foods: Array<String>, val cuisines: Array<String>, val ratings: IntArray) {
    val foodToIdx = foods.indices.associate { foods[it] to it }
    val csToIdx = foods.indices.groupBy { cuisines[it] }.mapValues { (k, v) -> 
                val q = TreeSet<Int>(compareBy({-ratings[it]}, {foods[it]})); q += v; q }
    fun changeRating(food: String, newRating: Int) {
        val i = foodToIdx[food]!!; val q = csToIdx[cuisines[i]]!!
        q -= i; ratings[i] = newRating; q += i
    }
    fun highestRated(cuisine: String) = foods[csToIdx[cuisine]!!.first()]
}




// 56ms
#[derive(Default)] struct FoodRatings(Vec<String>, Vec<String>, Vec<i32>, HashMap<String, usize>, HashMap<String, BTreeSet<(i32, String)>>);
impl FoodRatings {
    fn new(f: Vec<String>, c: Vec<String>, r: Vec<i32>) -> Self {
        let fi: HashMap<_,_> = (0..f.len()).map(|i| (f[i].clone(), i)).collect();
        let mut ct = HashMap::new();
        for i in 0..f.len() { ct.entry(c[i].clone()).or_insert(BTreeSet::new()).insert((-r[i],f[i].clone())); }
        Self(f, c, r, fi, ct)
    }
    fn change_rating(&mut self, f: String, v: i32) {
        let i = self.3[&f]; let c = &self.1[i];
        self.4.get_mut(c).unwrap().remove(&(-self.2[i],self.0[i].clone())); self.2[i] = v;
        self.4.get_mut(c).unwrap().insert((-v,self.0[i].clone()));
    }
    fn highest_rated(&self, c: String) -> String { self.4[&c].iter().next().unwrap().1.clone() }
}


16.09.2025

2197. Replace Non-Coprime Numbers in Array hard blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1114

Problem TLDR

Simulate gcd to lcm adjacent pair removal #hard #simulation

Intuition

Solved with the hint: only update values to the left.

As all the ways lead to the same result, that means we can pick the more comfortable way: just scan from the left to the right.

GCD(a, b) = (b, a%b) LCM(a, b) = a*b/GCD(a,b)

Approach

  • careful with int overflow

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 64ms
    fun replaceNonCoprimes(nums: IntArray) = buildList {
        fun gcd(a: Int, b: Int): Int = if (a % b == 0) b else gcd(b, a % b)
        fun lcm(a: Int, b: Int): Int = ((1L * a * b) / gcd(a, b)).toInt()
        for (x in nums) {
            this += x
            while (size > 1 && gcd(last(), this[size-2]) > 1) 
                this += lcm(removeLast(), removeLast())
        }
    }




// 18ms
    pub fn replace_non_coprimes(nums: Vec<i32>) -> Vec<i32> {
        fn gcd(a: i32, b: i32) -> i32 { if a%b > 0 { gcd(b, a%b)} else { b }};
        let lcm = |a: i32, b: i32| (a as i64 * b as i64/ gcd(a, b) as i64) as i32;
        let mut res = vec![];
        for x in nums { res.push(x); while res.len() > 1 && gcd(res[res.len()-1], res[res.len()-2]) > 1 {
            let (a, b) = (res.pop().unwrap(), res.pop().unwrap()); res.push(lcm(a, b))
        }} res
    }


15.09.2025

1935. Maximum Number of Words You Can Type easy blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1113

Problem TLDR

Count words with all letters #easy

Intuition

No special algo here. Broken letters is up to 26, no hashset needed.

Approach

  • write a one-liner

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 14ms
    fun canBeTypedWords(txt: String, bl: String) =
        txt.split(" ").count { it.all { it !in bl}}




// 0ms
    pub fn can_be_typed_words(txt: String, bl: String) -> i32 {
        txt.split(" ").filter(|w| !w.chars().any(|c| bl.contains(c))).count() as _
    }


14.09.2025

966. Vowel Spellchecker medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1112

Problem TLDR

Spellcheck with priority: original, case, vowels #medium #regex

Intuition

Understand the priority:

  1. Exact match
  2. Ignore-case match
  3. Vowel-as-wildcard match

Approach

  • do full-search for vowels (7 symbols max, 5 wovels = 7^5) or precompute a wildcards

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 73ms
    fun spellchecker(wl: Array<String>, q: Array<String>): List<String> {
        val orig = wl.groupBy { it }; val lower = wl.groupBy { it.lowercase() }
        val vowel = wl.groupBy { Regex("[eiou]").replace(it.lowercase(), "a")}
        return q.map { q ->
            orig[q]?.first() ?: lower[q.lowercase()]?.first() ?:
            vowel[Regex("[eiou]").replace(q.lowercase(), "a")]?.first() ?: ""
        }
    }




// 13ms
    pub fn spellchecker(w: Vec<String>, q: Vec<String>) -> Vec<String> {
        use itertools::Itertools;
        let exact: HashMap<_,_> = w.iter().map(|s| (s.as_str(), s.as_str())).collect();
        let lower: HashMap<_,_> = w.iter().rev().map(|s| (s.to_lowercase(), s.as_str())).collect();
        let vowel: HashMap<_,_> = w.iter().rev().map(|s| (s.to_lowercase().replace(|c|"eiou".contains(c),"a"), s.as_str())).collect();
        q.iter().map(|s| {
            exact.get(s.as_str()).copied()
            .or(lower.get(&s.to_lowercase()).copied())
            .or(vowel.get(&s.to_lowercase().replace(|c|"eiou".contains(c),"a")).copied())
            .unwrap_or("").into()
        }).collect()
    }


13.09.2025

3541. Find Most Frequent Vowel and Consonant easy blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1111

Problem TLDR

Max freq vowels + consonants #easy

Intuition

Make a frequency array, then find max of vowel and max of consonant.

Approach

  • can we do a one-liner?

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 27ms
    fun maxFreqSum(s: String) = s.partition { it in "aeiou" }.toList()
        .sumOf { it.groupBy { it }.maxOfOrNull { it.value.size } ?: 0 }


12.09.2025

3227. Vowels Game in a String medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1110

Problem TLDR

Can Alice win Bob both removeing odd-even vowel count substring optimally #medium

Intuition

Naive dp: at every position i check every position j=i..n if the tail is loosing. Optimization trick: check in reverse j=n..i to end game faster

Approach

  • the final solution is that Alice always wins: odd on the first move, even - on the third

Complexity

  • Time complexity: \(O(n^2)\), or O(n)

  • Space complexity: \(O(n)\), or O(1)

Code


// 16ms
    fun doesAliceWin(s: String) = 
        "[aeiou]".toRegex() in s



// 33ms
    fun doesAliceWin(s: String): Boolean {
        val f = IntArray(s.length)
        for ((i, c) in s.withIndex()) f[i] = f[max(0, i-1)] + if (c in "aeiou") 1 else 0
        val dp = HashMap<Pair<Int, Boolean>, Boolean>()
        fun dfs(i: Int, odd: Boolean): Boolean = 
        i < s.length && dp.getOrPut(i to odd) {
            for (j in s.length-1 downTo i) {
                var cnt = f[j] - (if (i > 0) f[i-1] else 0)
                if (odd == (cnt % 2 > 0))
                if (!dfs(j+1, !odd)) return@getOrPut true
            }
            false
        }
        return dfs(0, true)
    }



// 3ms
    pub fn does_alice_win(s: String) -> bool {
        s.chars().any(|c| "aeiou".contains(c))
    }

11.09.2025

2785. Sort Vowels in a String medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1109

Problem TLDR

Sort vowels #medium

Intuition

Just implementation, no extra tricks.

Approach

  • copy vowels, sort, put back
  • or do a counting sort

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 102ms
    fun sortVowels(s: String) = buildString {
        val vw = s.filter { it in "aeiouAEIOU" }.toList().sorted()
        var i = 0
        for (c in s) append(if (c in "aeiouAEIOU") vw[i++] else c)
    }



// 27ms
    fun sortVowels(s: String) = buildString {
        val v = "AEIOUaeiou"; val vw = IntArray(12)
        for (c in s) ++vw[1 + v.indexOf(c)]
        for (c in s) append(if (c in v) 
            v[(0..10).first {vw[it+1] > 0}.also {--vw[it+1]}] else c)
    }



// 10ms
    pub fn sort_vowels(s: String) -> String {
        let mut t = s.chars().filter(|&c| "AEIOUaeiou".contains(c)).sorted();
        s.chars().map(|c| if "AEIOUaeiou".contains(c) { t.next().unwrap() } else { c }).collect()
    }


10.09.2025

1733. Minimum Number of People to Teach medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1108

Problem TLDR

Min friends to teach common language to communicate in graph #medium

Intuition

Only one language is allowed.

    // user1: knows lang1, friends with user2,user3
    // user2: knows lang2, friends with user1,user3
    // user3: knows lang1,lang2, friends with user2

    // users graph:
    //     l1    l2     l1,l2
    //      u1---u2---u3
    //       \________/
    //
    // u1 & u2 can't communicate
    // u1 & u3 can
    // u2 & u3 can
    //
    // so u1 should learn any langs of u2
    // or
    // u2 should learn any langs of u1
    //
    // and we should make minimum users to teach

    //   [2] [3]  [1,2]
    //     1--4--3
    //      \   /         it is 3 components: 1, 4, 2-3
    //        2
    //         [1,3]
    //
    //    1 [+3] and 4 [+2]
    //
    // i don't get the optimal algo, look at hint (21 minute)
    //
    // so are users should talk each-to-each, event not direct friends?
    // why graph then?

I used the hint: just brute force all languages.

Approach

  • the main difficulty is to understand the problem
  • only consider non-communicating pairs
  • find most common language in non-communicated people

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 83ms
    fun minimumTeachings(n: Int, ls: Array<IntArray>, fs: Array<IntArray>): Int {
        val ls = ls.map { it.toSet() }; val fs = fs.map { it.toList() }
        var f = fs.filter { (a, b) -> !ls[b-1].any { it in ls[a-1] }}.flatten().toSet()
        return f.size - (f.flatMap { ls[it-1] }.groupBy{it}.maxOfOrNull{it.value.size}?:0)
    }


09.09.2025

2327. Number of People Aware of a Secret medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1107

Problem TLDR

People knowing a secret at day n, keeping delay then spread and forget #medium #simulation

Intuition

    // time, delay=1, forget = 3
    // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
    // a a a a
    //   b b b b
    //     c c c c
    //       d d d d
    //       e
    //       f
    //       \
    //        one from a(d), one from b(e), one from c(f)
    //        3 active, so +3 passive (+delay day +3 active)

Maintain diff array for

  • changing active spreaders
  • changing knowers

Another intuition from lee: dp[i] is how many new people at that day. From that angle we know dp[i-forget] is how many people will forget today, dp[i-(forget-delay)] is how many people became active today. Very useful.

Approach

  • the main difficulty is to find a good angle to look at this problem

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 4ms
    fun peopleAwareOfSecret(n: Int, delay: Int, forget: Int): Int {
        val M = 1000000007L
        val know = LongArray(n+forget+1); val active = LongArray(n+forget+1)
        know[delay] = 1; know[1+forget] = -1; active[delay] = 1; active[1+forget] = -1
        for (d in 1+delay..n) {
            active[d] = (active[d-1] + active[d] + M) % M
            active[d+delay] += active[d]; active[d+forget] -= active[d]
            know[d] = (know[d-1] + know[d] + active[d] + M) % M
            know[d+forget] -= active[d]
        }
        return know[n].toInt()
    }


08.09.2025

1317. Convert Integer to the Sum of Two No-Zero Integers easy blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1106

Problem TLDR

Find a+b=n without zeros in digits #easy

Intuition

Brute force a=1..<n, b = n-a

Approach

  • any faster solution?
  • any shorter solution?

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 55ms
    fun getNoZeroIntegers(n: Int) =
    (0..n).map { listOf(it, n-it) }.find { '0' !in "$it" }



// 0ms
    pub fn get_no_zero_integers(n: i32) -> Vec<i32> {
       (0..n).map(|a|vec![a,n-a]).find(|v|!format!("{:?}",v).contains('0')).unwrap()
    }



// 0ms
    vector<int> getNoZeroIntegers(int n) {
        int a=0,b=0,s=1;
        while (n) {
            int d = n%10; n/=10;
            if (n&&d<2) a += s*(8+d), b += s<<1, --n;
            else a += s, b += s*(d-1);
            s *= 10;
        }
        return {a,b};
    }


07.09.2025

1304. Find N Unique Integers Sum up to Zero easy blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1105

Problem TLDR

Any n uniq numbers with sum of 0 #easy

Intuition

  • fill symmetrical -i,i, then remove 0 if n is even
  • derive the law 1-n+i*2 (from lee)
  • fill range 2..n then add -sum of that

Approach

  • careful with even/odd

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 9ms
    fun sumZero(n: Int) = (2..n)+-(2..n).sum()


// 0ms
    fun sumZero(n: Int) = IntArray(n) {1-n+it*2}



// 0ms
    pub fn sum_zero(n: i32) -> Vec<i32> {
        (1..n).chain([(n-n*n)/2]).collect()
    }


// 0ms
    vector<int> sumZero(int n) {
        vector<int> r(n); iota(begin(r),end(r),1);
        r.back() = (n-n*n)/2; return r;
    }



// 0ms
    sumZero = lambda _,n:[*range(1-n,n,2)]



06.09.2025

3495. Minimum Operations to Make Array Elements Zero hard blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1104

Problem TLDR

Sum query [a..b] of optimal pairwise /4 until range is zero #hard #math

Intuition

Didn’t solve.

    //  2, 3, 4, 5, 6
    // nums are consequent, 
    // there can be a fast way to check ops count

    //              *
    //           *  *
    //        *  *  * ------ divide by four
    //     *  *  *  *
    //  *  *  *  *  *
    //  *  *  *  *  *
    //  0  0  1  1  1

    //    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
    //    1 1 1 2 2 2 2 2 2 2  2  2  2  2  2  3 ....
    //  1*3+12*2 + 
    //  1*(4^1-4^0) + 2*(4^2-4^1) + 3*(4^3-4^2)
    //
    // optimal way?
    // pairs  1 2 3 4 5     
    //                  the largest log_4(X) steps
    //    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 
    //      .       .                       3 4
    //      .       .                       0 1
    //      .       .                    3    0
    //      .       .                 3  0
    //      .       .              3  0
    //      .       .           2  0
    //      .       .        2  0
    //      .       .     2  0
    //      .       .   2 0
    //      .       . 1 0
    //      .       1 0
    //      .     1 0
    //      .   1 0
    //      . 0 0
    //    0 0

    //  1 1 1 1 2 2 2 2 2 2  2  2  2  2  2  2  3 3
    //      a                                    b

    //                                     4^3
    //                                     4^2
    //                                     4^1
    //                                     4^0
    //                                     0

    // we have this sequence
    // 
    //  1*(4^1-4^0) + 2*(4^2-4^1) + 3*(4^3-4^2) + k*(4^k-4^(k-1))
    //       /                           \ 
    //      a                             b somewhere there
    //        
    //    1 1 1 2 2 2 2 2 2  2  2  2  2  2  2  3 3
    //      a=3     .                           b=17
    //              .                          3..steps
    //              .                    2....steps
    //              .              2....steps
    //              .        2....steps
    //              .   2....steps
    //              2....steps
    //          2....steps
    //      1...step
    // r=1+2*6+3=1+2*(4^2-4^1)/2+3
    // how many steps to take pairs from a to b
    //
    // 1. find which range is b
    // ok let's look for hints (44 minute)
    // first hint already knew - steps(x) = log_4(x)
    // second hint don't understand - pair 2 numbers with max "/4" what?


  • each number has uniq growing number of ops
  • the sequence of ops is 1*(4^1-4^0) + 2*(4^2-4^1) + 3*(4^3-4^2) + k*(4^k-4^(k-1))
  • compute sum of individual ops in range: ops += (r-l+1)*pow
  • convert to pairwise and handle edge case of odd numbers: res += ops/2+ops%2

Approach

  • i was close to the solution, just didn’t believe i’m on a right track;
  • the tricky part is converting from singles to pairwise ops; have to do big observation for this, or just give up
  • not mine bithack: 0x15555555 >> (30 - 2*p)evaluates to 1 + 4 + 4² + … + 4^{p-1}. Why? 0x15555555 is the bit pattern 0101... (1s in even positions). Shifting by 30-2p moves exactly p of those 1s into the low end, giving the geometric series above.

Logic behind (x+1)*p-(4^p-1)/3: image.png

For [a,b]=[20,70]: 1.webp

Complexity

  • Time complexity: \(O(nlog(d))\)

  • Space complexity: \(O(1)\)

Code


// 8ms
    fun f(x: Int): Long = ((33 - x.countLeadingZeroBits()) shr 1).let { p ->
        1L*(x + 1) * p - (0x15555555 shr (30 - 2 * p)) }
    fun minOperations(qs: Array<IntArray>) = qs.sumOf { (f(it[1])-f(it[0]-1)+1)/2 }



// 69ms
    fun minOperations(qs: Array<IntArray>) =
        qs.sumOf { (a,b) ->
            ((1..16).sumOf { p -> 
                max(0, 1L*min(b, (1 shl p*2)-1) - max(a, 1 shl (p-1)*2) + 1) * p
            }+1) / 2
        }



// 24ms
    pub fn min_operations(q: Vec<Vec<i32>>) -> i64 {
        q.iter().map(|q| (1+(1..17).map(|p|
            0.max(1 + q[1].min((1<<p*2)-1) - q[0].max(1<<(p-1)*2)) as i64*p
        ).sum::<i64>())/2 ).sum::<i64>()
    }



// 30ms
    long long minOperations(vector<vector<int>>& q) {
        long long r = 0, o = 1;
        for (auto& q: q) {
            for (int p = 1; p < 17; ++p)
            o += p * max(0LL, 1LL + min(1LL*q[1], (1LL<<p*2)-1) - max(1LL*q[0], 1LL<<(p-1)*2));
            r += o / 2, o = 1;
        }
        return r;
    }


05.09.2025

2749. Minimum Operations to Make the Integer Zero medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1103

Problem TLDR

Min ops to subtract n2+2^(0..60) from n1 and make n1=0 #medium

Intuition

Didn’t solve.

    // n1 = a*n2 + b*2^i, i=0..60
    // count of (2^i) == a
    //           n1 = c*2^0+d*2^1+..x*2^32
    //                bits
    //  2^0 = 1              
    //  2^1 = 2
    // 2^i always positive
    //
    // n1=4  n2=0   2^2
    // n1=3  n2=0   2^1,2^0
    // n1=3  n2=1   2^1+1
    // n1=3  n2=2   2^0+2
    // n1=3  n2=3   -1
    // n1=7  n2=1   2^2+1,2^0+1
    // n1=7  n2=-1  2^3-1
    //    7-n2=8 2^3
    // n1=8  n2=-1
    //    8-n2=9 9-2^3=1
    //    1-n2=2 2-2^1=0
    // try just subtract the highest bit
    // n1=3 n2=-2
    //    3-n2=5 5-2^2=1
    //    1-n2=3 3-2^1=1   didn't work that way
    // 
    // 1 2 4 8 16 32
    // look for hints (23 minute)
    // hint one if n2==0, we need just countOneBits operations
    // hint two if n1 can be 0, we need at most 60 ops (why?)
    //
    // n1 = a*n2 + b*2^i, i=0..60
    // n1-a*n2 = sum_a(2^i)  (i up to a)
    //          0b01000

  • do arithmetics: n1-a*n2 = sum(2^x) = Y
  • a_max is x=0 for all 2^x = Y
  • a_min is countOneBits - optimal exponentiation

Approach

  • the hardest step is the grasping of min..max for a and understanding that we can split number if the a in that range

Complexity

  • Time complexity: \(O(60log(n))\)

  • Space complexity: \(O(1)\)

Code


// 4ms
    fun makeTheIntegerZero(n1: Int, n2: Int) = (1..32)
    .firstOrNull { it in (n1-1L*it*n2).countOneBits()..n1-1L*it*n2 } ?: -1



// 0ms
    pub fn make_the_integer_zero(n1: i32, n2: i32) -> i32 {
        let (mut x, mut r) = (n1 as i64, 0);
        for k in 1..33 {
            x -= n2 as i64;
            if x < k { return -1 }
            if k >= x.count_ones() as i64 { return k as _ }
        } -1 
    }



// 0ms
    int makeTheIntegerZero(int n1, int n2) {
        for(long long k = 1, x = n1;;++k) {
            x -= n2;
            if (x < k) return -1;
            if (__builtin_popcountll(x) <= k) return k;
        }
    }



// 3ms
    def makeTheIntegerZero(_, n1, n2):
        return next((t for t in range(1, 33)
            if (n1 - t*n2).bit_count() <= t <= n1 - t*n2), -1)


04.09.2025

3516. Find Closest Person easy blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1102

Problem TLDR

Compare two distances #easy

Intuition

Distance is abs(z - x or y)

Approach

  • use when

Complexity

  • Time complexity: \(O(1)\)

  • Space complexity: \(O(1)\)

Code


// 14ms
    fun findClosest(x: Int, y: Int, z: Int) =
        listOf(1,0,2)[abs(z - x).compareTo(abs(z - y))+1]



// 0ms
    pub fn find_closest(x: i32, y: i32, z: i32) -> i32 {
        [1,0,2][1+1.min((z-x).abs()-(z-y).abs()).max(-1) as usize]
    }



// 0ms
    int findClosest(int x, int y, int z) {
        return (abs(z-x)>abs(z-y))*2+(abs(z-x)<abs(z-y));
    }



// 0ms
    findClosest=lambda _,x,y,z:(abs(z-x)>abs(z-y))<<1|(abs(z-x)<abs(z-y))


03.09.2025

3027. Find the Number of Ways to Place People II hard blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1101

Problem TLDR

Left-top, bottom-right pairs with empty rectangles #medium #geometry

Intuition

Sort by x then rotate CCW around each point.

Approach

  • attention to the numbers range -10^9..10^9

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(1)\)

Code


// 692ms
    fun numberOfPairs(p: Array<IntArray>): Int {
        p.sortWith(compareBy({it[0]},{-it[1]}))
        return p.indices.sumOf { i -> var m = Int.MIN_VALUE
            p.drop(i+1).count { (_,y) -> y <= p[i][1] && y > m.also{m=max(m,y)}}
        }
    }


02.09.2025

3025. Find the Number of Ways to Place People I medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1100

Problem TLDR

Left-top, bottom-right pairs with empty rectangles #medium

Intuition

Brute-force is accepted for n=50.

Another intuition: sort by x then rotate CCW around each point.

Approach

  • should we learn quad trees?

Complexity

  • Time complexity: \(O(n^3)\)

  • Space complexity: \(O(1)\)

Code


// 55ms
    fun numberOfPairs(p: Array<IntArray>): Int {
        var res = 0
        for (i in p.indices) for (j in p.indices)
            if (i != j && p[i][0] <= p[j][0] && p[i][1] >= p[j][1] && 
                p.indices.none { k -> k != i && k != j && 
                    p[k][0] in p[i][0]..p[j][0] && p[k][1] in p[j][1]..p[i][1] }) ++res
        return res
    }



// 43ms
    fun numberOfPairs(p: Array<IntArray>): Int {
        p.sortBy { it[0]*1000-it[1] }
        return p.indices.sumOf { i ->
            var y = -1
            p.drop(i+1).count { (_,d) -> d <= p[i][1] && d > y.also{y=max(y,d)}}
        }
    }


01.09.2025

1792. Maximum Average Pass Ratio medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1099

Problem TLDR

Max avg ratio after assigning extra to ratios #medium

Intuition

Greedy works: for each extra choose the class that will make the most difference.

    //[1,2],[3,5],[2,2]] 
    // 2/3 vs 3/5
    // 10/15  9/15
    //
    // 2/3 4/6 2/2   vs   3/4 3/5 2/2
    // a/b c/d
    // a+1/b+1 +c/d   vs   a/b + c+1/d+1

Approach

  • we don’t have to validate in the end; choose only available numbers
  • there is a bitmask optimization
  • we can prioritize rows, cols or subs with more numbers filled

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n)\)

Code


// 332ms
    fun maxAverageRatio(cls: Array<IntArray>, ext: Int): Double {
        val q = PriorityQueue<IntArray>(compareBy { (a,b) -> 1.0*a/b-1.0*(a+1)/(b+1)})
        q += cls; for (e in 1..ext) q += q.poll().also { ++it[0]; ++it[1] }
        return cls.sumOf { (a,b) -> 1.0*a/b } / cls.size
    }


31.08.2025

37. Sudoku Solver hard blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1098

Problem TLDR

Solve sudoku #hard #backtrack

Intuition

Brute-force DFS with pruning

Approach

  • we don’t have to validate in the end; choose only available numbers
  • there is a bitmask optimization
  • we can prioritize rows, cols or subs with more numbers filled

Complexity

  • Time complexity: \(O(9^81)\), however, 9 is smaller with pruning

  • Space complexity: \(O(1)\)

Code


// 233ms
    fun solveSudoku(b: Array<CharArray>): Unit {
        val rows = Array(9) { b[it].toHashSet() }
        val cols = Array(9) { x -> (0..8).map { b[it][x] }.toHashSet() }
        val subs = Array(9) { i -> (0..8).map { j ->  b[i/3*3 + j/3][i%3*3 + j%3] }.toHashSet() }
        fun dfs(i: Int): Boolean {
            if (i == 81) return true
            val y = i / 9; val x = i % 9
            if (b[y][x] != '.') return dfs(i + 1)
            for (c in '1'..'9') if (c !in rows[y] && c !in cols[x] && c !in subs[y/3*3+x/3]) {
                b[y][x] = c; rows[y] += c; cols[x] += c; subs[y/3*3+x/3] +=c
                if (dfs(i + 1)) return true
                rows[y] -= c; cols[x] -= c; subs[y/3*3+x/3] -=c
            }
            b[y][x] = '.'; return false
        }
        dfs(0)
    }



// 79ms
    fun solveSudoku(b: Array<CharArray>): Unit {
        val s = Array(3) { IntArray(9) }
        for (y in 0..8) for (x in 0..8) if (b[y][x] != '.') { 
            val c = 1 shl (b[y][x] - '0')
            s[0][y] = s[0][y] or c; s[1][x] = s[1][x] or c; s[2][y/3*3+x/3] = s[2][y/3*3+x/3] or c}
        fun dfs(i: Int): Boolean {
            if (i == 81) return true
            val y = i / 9; val x = i % 9
            if (b[y][x] != '.') return dfs(i + 1)
            for (n in 1..9) {
                val c = 1 shl n
                if ((c and s[0][y]) + (c and s[1][x]) + (c and s[2][y/3*3+x/3]) == 0) {
                s[0][y] = s[0][y] xor c; s[1][x] = s[1][x] xor c; s[2][y/3*3+x/3] = s[2][y/3*3+x/3] xor c
                b[y][x] = '0' + n; if (dfs(i + 1)) return true
                s[0][y] = s[0][y] xor c; s[1][x] = s[1][x] xor c; s[2][y/3*3+x/3] = s[2][y/3*3+x/3] xor c
            }}
            b[y][x] = '.'; return false
        }
        dfs(0)
    }


30.08.2025

36. Valid Sudoku medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1097

Problem TLDR

Validate sudoku has no duplicates #medium

Intuition

Brute-force.

Approach

  • small grid is big * 3 + small
  • single hashset: use keys as row + digit, column + digit, box + digit

Complexity

  • Time complexity: \(O(1)\)

  • Space complexity: \(O(1)\)

Code


// 0ms
    fun List<Char>.ok() = filter { it != '.' }.let { it.toSet().size == it.size }
    fun isValidSudoku(b: Array<CharArray>) =
        (0..8).all { y -> b[y].map { it }.ok() } &&
        (0..8).all { x -> (0..8).map { b[it][x] }.ok() } &&
        (0..8).all { c -> (0..8).map { b[c/3 * 3 + it/3][c%3 * 3 + it%3]}.ok() }



// 0ms
    pub fn is_valid_sudoku(b: Vec<Vec<char>>) -> bool {
        let (mut cols, mut rows, mut subs) = ([0;9],[0;9],[0;9]);
        for y in 0..9 { for x in 0..9 { if b[y][x] != '.' {
            let d = 1 << (b[y][x] as u8 - b'1');
            if (cols[x] & d) + (rows[y] & d) + (subs[y/3*3+x/3] & d) > 0 { return false }
            cols[x] |= d; rows[y] |= d; subs[y/3*3+x/3] |= d;
        }}} true
    }



// 0ms
    bool isValidSudoku(vector<vector<char>>& b) {
        int f[244]={};
        for (int y = 0; y < 9; ++y) for (int x = 0; x < 9; ++x) if (b[y][x] != '.') {
            int d = b[y][x] - '1';
            if (f[y*9+d]+f[81+d*9+x]+f[81+81+(y/3*3+x/3)*9+d]) return 0;
            f[y*9+d]=1;f[81+d*9+x]=1;f[81+81+(y/3*3+x/3)*9+d]=1;
        } return 1;
    }



// 5ms
    def isValidSudoku(_, b):
        a = sum(([(d,y),(x,d),(y//3,x//3,d)]
                for y in range(9) for x in range(9)
                for d in [b[y][x]] if d != '.'),[])
        return len(a) == len(set(a))


29.08.2025

3021. Alice and Bob Playing Flower Game medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1096

Problem TLDR

Pairs x=1..n * y=1..m for Alice to win in take from (x+y) game #medium

Intuition

Count odd x+y. It is sum of first odd+second even or reversed.

The interesting math fact from others (can be proved by considering 4 cases: even-even, even-odd,odd-even, odd-odd):

n/2 * (m+1)/2 + m/2 * (n+1)/2 == n*m/2

Approach

  • try to write O(1)

Complexity

  • Time complexity: \(O(1)\)

  • Space complexity: \(O(1)\)

Code


// 0ms
    fun flowerGame(n: Int, m: Int) =
        1L * (n/2) * ((m+1)/2) + 1L * ((n+1)/2) * (m/2)



// 11ms
    fun flowerGame(n: Int, m: Int): Long {
        val ne = (2..n).count { it % 2 < 1 }
        val me = (2..m).count { it % 2 < 1 }
        return 1L * (n-ne) * me + 1L * ne * (m-me)
    }



// 0ms
    pub fn flower_game(n: i32, m: i32) -> i64 {
        n as i64 * m as i64 / 2
    }



// 0ms
    long long flowerGame(int n, int m) {
        return 1LL * n * m / 2;
    }



// 0ms
    flowerGame = lambda _,n,m: n*m//2


28.08.2025

3446. Sort Matrix by Diagonals medium blog post substack youtube 1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1095

Problem TLDR

Sort bottom left and top right diagonals #medium #matrix

Intuition

Problem is small, put them into lists, sort, then put back.

Approach

  • iterate over y for bottom-left, x for top-right
  • priority queue gives a compact code

Complexity

  • Time complexity: \(O(n^2logn)\)

  • Space complexity: \(O(1)\)

Code


// 18ms
    fun sortMatrix(g: Array<IntArray>) = g.apply {
        val m = HashMap<Int, PriorityQueue<Int>>()
        for (y in indices) for (x in g[0].indices) m.getOrPut(y-x) 
            { PriorityQueue { a,b -> if (y < x) a - b else b - a }} += g[y][x]
        for (y in indices) for (x in g[0].indices) g[y][x] = m[y-x]!!.poll()
    }



// 35ms 
    fun sortMatrix(g: Array<IntArray>) = g.apply {
        for (y in indices) {
            val ns = (0..<g.size-y).map { g[y+it][it] }.sortedDescending()
            for (x in ns.indices) g[y+x][x] = ns[x]
        }
        for (x in 1..<g[0].size) {
            val ns = (0..<g[0].size-x).map { g[it][x+it] }.sorted()
            for (y in ns.indices) g[y][x+y] = ns[y]
        }
    }



// 0ms
    pub fn sort_matrix(mut g: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
        for (x0, y0) in (0..g.len()).map(|y| (y, 0)).chain((1..g[0].len()).map(|x| (0, x))) {
            let (mut x, mut y, mut v) = (x0, y0, vec![]);
            while x < g[0].len() && y < g.len() { v.push(g[y][x]); y += 1; x += 1 }
            v.sort_unstable(); if y >= x { v.reverse() }; (x, y) = (x0, y0);
            for v in v { g[y][x] = v; y += 1; x += 1 }
        } g
    }



// 3ms
    vector<vector<int>> sortMatrix(vector<vector<int>>& g) {
        int n = size(g), m = size(g[0]), b = n - 1; 
        vector<priority_queue<int>> q(n+m-1);
        for (int y = 0; y < n; ++y) for (int x = 0; x < m; ++x) q[x-y+b].push(y<x?-g[y][x]:g[y][x]);
        for (int y = 0; y < n; ++y) for (int x = 0; x < m; ++x) 
        { int d = x - y + b, v = q[d].top(); q[d].pop(); g[y][x]=y<x?-v:v; } return g;
    }



// 12ms
    def sortMatrix(_, g):
        d = {}
        [[heappush(d.setdefault(y-x, []), t*(1,-1)[y>=x]) for x,t in enumerate(r)] for y,r in enumerate(g)]
        g[:] = [[(heappop(d[y-x])*(1,-1)[y>=x]) for x in range(len(r))] for y,r in enumerate(g)]
        return g


27.08.2025

3459. Length of Longest V-Shaped Diagonal Segment hard blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1094

Problem TLDR

Max length of 1-2-0-2.. diagonal sequence, on cw rotation #hard #dp

Intuition

Do Depth-First Search, add memoization (however accepted without it)

Approach

  • enumerate diagonals as 0..3, cw rotation is (d+1)%4, ccw (d+3)%4
  • v is irrelevant to dp key
  • dp key can be Int: (500*y+x)*100 + dir*10 + rot
  • I think the HashMap is the weakest point of performance

Complexity

  • Time complexity: \(O(mn)\)

  • Space complexity: \(O(n)\)

Code


// 1219ms
    fun lenOfVDiagonal(g: Array<IntArray>): Int {
        val nxy = arrayOf(-1,-1,1,1,-1); val nv = arrayOf(2,2,0); var res = 0
        fun dfs(y: Int, x: Int, dir: Int, rot: Int, v: Int): Int = 
            if (y !in 0..<g.size || x !in 0..<g[0].size || g[y][x] != v ) 0 
            else 1 + max(dfs(y+nxy[dir],x+nxy[dir+1],dir,rot,nv[v]),
                         if (rot > 0) dfs(y,x,(dir+1)%4,0,v)-1 else 0)
        for (y in g.indices) for (x in g[0].indices) if (g[y][x] == 1)
            res = max(res, (0..3).maxOf {dfs(y,x,it,1,1)})
        return res
    }



// 981ms
    fun lenOfVDiagonal(g: Array<IntArray>): Int {
        val nxy = arrayOf(-1,-1,1,1,-1); val nv = arrayOf(2,2,0); var res = 0
        val dp = HashMap<Int, Int>()
        fun dfs(y: Int, x: Int, dir: Int, rot: Int, v: Int): Int = 
            if (y < 0 || x < 0 || y == g.size || x  == g[0].size || g[y][x] != v ) 0 
            else 1 + dp.getOrPut((y*500 + x)*100 + dir*10 + rot) { max(
                dfs(y+nxy[dir],x+nxy[dir+1],dir,rot,nv[v]),
                if (rot > 0) dfs(y,x,(dir+1)%4,0,v)-1 else 0) }
        for (y in g.indices) for (x in g[0].indices) if (g[y][x] == 1)
            res = max(res, (0..3).maxOf {dfs(y,x,it,1,1)})
        return res
    }


26.08.2025

3000. Maximum Area of Longest Diagonal Rectangle medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1093

Problem TLDR

Max area of max diagonal rectangles #easy

Intuition

Single iteration:

  • update max diagonal, forget max area
  • update max area

Approach

  • or we can find a max of a single variable diagonal+area

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 11ms
    fun areaOfMaxDiagonal(d: Array<IntArray>) = d
        .maxOf { (w,h) -> (w*w+h*h) * 10000 + w*h }%10000



// 0ms
    pub fn area_of_max_diagonal(d: Vec<Vec<i32>>) -> i32 {
        d.iter().map(|d|(d[0]*d[0]+d[1]*d[1],d[0]*d[1])).max().unwrap().1
    }
    


// 0ms
    int areaOfMaxDiagonal(vector<vector<int>>& d) {
        int x = 0;
        for (auto d: d) x = max(x, (d[0]*d[0]+d[1]*d[1])*10000+d[0]*d[1]);
        return x%10000;
    }



// 0ms
    areaOfMaxDiagonal= lambda _,d:max((w*w+h*h,w*h) for w,h in d)[1]


25.08.2025

498. Diagonal Traverse medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1092

Problem TLDR

Matrix diagonal traversal #medium

Intuition

Use the fact: diagonal x + y = constant

Approach

  • use d%2 to check if should go up

Complexity

  • Time complexity: \(O(nm)\)

  • Space complexity: \(O(nm)\)

Code


// 39ms
    fun findDiagonalOrder(m: Array<IntArray>) = buildList {
        for (d in 0..m.lastIndex+m[0].lastIndex)
            for (x in (max(0,d-m.lastIndex)..min(d, m[0].lastIndex))
                .let { if (d%2>0) it.reversed() else it}) this += m[d-x][x]
    }



// 0ms
    pub fn find_diagonal_order(m: Vec<Vec<i32>>) -> Vec<i32> {
        (0..=m.len()+m[0].len()-2).flat_map(|d| {
            let (a, b) = (d.saturating_sub(m.len()-1), d.min(m[0].len()-1));
            let mut n: Vec<_> = (a..=b).map(|x| m[d-x][x]).collect();
            if d%2>0 { n.reverse() }; n
        }).collect()
    }
    


// 4ms
    vector<int> findDiagonalOrder(vector<vector<int>>& m) {
        vector<int>r; int w = size(m[0]), h = size(m);
        for (int d = 0; d <= w+h-2; ++d) {
            int b = min(d, w-1), a = max(0, d-h+1);
            for (int x = (d%2)*b+(1-d%2)*a; d%2 && x >= a || d%2<1 && x <= b; d%2?--x:++x)
                r.push_back(m[d-x][x]);
        } return r;
    }



// 27ms
    def findDiagonalOrder(_, m):
        h,w=len(m),len(m[0]); return [m[d-x][x] 
        for d in range(h+w-1) 
        for x in range(max(0,d-h+1),min(d,w-1)+1)[::1-2*(d&1)]]


24.08.2025

1493. Longest Subarray of 1’s After Deleting One Element medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1091

Problem TLDR

Max 1-subarray after removing one elemnt #medium #two_pointers

Intuition

The simple way:

  • count prev ones and curr ones, then max(res, prev+curr)
  • corner cases are: all ones, single one island and zero

The clever way:

  • use fact that we only interested in the largest island
  • set left border l and move it always while zeros are two and more
  • all the smaller islands doesn’t matter

Approach

  • the two pointers: always move right, move left until condition, compute current min/max result
  • for max window sometimes we didn’t have to shrink window, just move
  • right border of sliding window will eventually be at size-1, we only interested in left

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 2ms
    fun longestSubarray(n: IntArray): Int {
        var l = 0; var z = 0
        for (x in n) z -= x - if (z > x) n[l++] else 1
        return n.size - l - 1
    }



// 4ms
    fun longestSubarray(n: IntArray): Int {
        var p = 0; var c = 0; var r = 0; var z = 1
        for (x in n) if (x > 0) r = max(r, ++c+p)
            else { p = c; c = 0; z = 0 }
        return r - z
    }



// 0ms
    pub fn longest_subarray(n: Vec<i32>) -> i32 {
        let (mut l, mut zs) = (0, 0);
        (0..n.len()).map(|i| {
            zs += 1 - n[i];
            if zs > 1 { zs -= 1 - n[l]; l += 1 }
            i - l
        }).max().unwrap() as _
    }
    


// 0ms
    int longestSubarray(vector<int>& n) {
        int l = 0, z = 0;
        for (int x: n) z -= x-(z>x?n[l++]:1);
        return size(n) - l - 1;
    }



// 43ms
    def longestSubarray(_, n):
        l=z=0
        for x in n: t=z>x; z+=1-x-t+t*n[l]; l += t
        return len(n)-l-1


23.08.2025

3197. Find the Minimum Area to Cover All Ones II hard blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1090

Problem TLDR

Min sum all-1 areas of 3-split #hard

Intuition

Use hint: try every split

Approach

  • corner case: consider reverse split and sum

Complexity

  • Time complexity: \(O(nm^4)\)

  • Space complexity: \(O(1)\)

Code


// 51ms
    fun minimumSum(g: Array<IntArray>): Int {
        val w = g[0].size; val h = g.size
        fun sum(x1: Int, y1: Int, x2: Int, y2: Int): Int {
            var r = 0; var b = 0; var l = w; var t = h
            for (y in y1..y2) for (x in x1..x2) if (g[y][x] > 0) 
            { r = max(r, x); l = min(l, x); b = max(b, y); t = min(t, y) }
            return (r-l+1)*(b-t+1)
        } 
        fun split(x1: Int, y1: Int, x2: Int, y2: Int): Int {
            var res = 30*30
            for (y in y1..<y2) res = min(res, sum(x1, y1, x2, y) + sum(x1, y+1, x2, y2))
            for (x in x1..<x2) res = min(res, sum(x1, y1, x, y2) + sum(x+1, y1, x2, y2))
            return res
        } 
        var res = 30*30
        for (y in 0..<h-1) res = min(res, sum(0, 0, w-1, y) + split(0, y+1, w-1, h-1))
        for (y in 0..<h-1) res = min(res, split(0, 0, w-1, y) + sum(0, y+1, w-1, h-1))
        for (x in 0..<w-1) res = min(res, sum(0, 0, x, h-1) + split(x+1, 0, w-1, h-1))
        for (x in 0..<w-1) res = min(res, split(0, 0, x, h-1) + sum(x+1, 0, w-1, h-1))
        return res
    }


22.08.2025

3195. Find the Minimum Area to Cover All Ones I medium blog post substack youtube

1.webp https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1089

Problem TLDR

Min all-1 rectangle #medium

Intuition

Compute 4 variables: minX..maxX, minY..maxY

Approach

  • or, we can go from the corners

Complexity

  • Time complexity: \(O(nm)\)

  • Space complexity: \(O(1)\)

Code


// 945ms
    fun minimumArea(g: Array<IntArray>): Int {
        var a = 0; var b = 0; var c = g.size; var d = g[0].size
        for (y in 0..<c) for (x in g[0].indices) if (g[y][x] > 0) 
            { a = y; b = max(b, x); c = min(c, y); d = min(d, x) }
        return (b-d+1)*(a-c+1)
    }



// 1019ms
    fun minimumArea(g: Array<IntArray>): Int {
        var w = g[0].size; var h = g.size
        for (y in g.indices) if (1 !in g[y]) --h else break
        for (y in g.lastIndex downTo 0) if (1 !in g[y]) --h else break
        for (x in g[0].indices) if (g.indices.all { g[it][x] < 1}) --w else break
        for (x in g[0].lastIndex downTo 0) if (g.indices.all { g[it][x] < 1}) --w else break
        return w * h
    }



// 39ms
    pub fn minimum_area(g: Vec<Vec<i32>>) -> i32 {
        let mut r = [0, 0, g.len(), g[0].len()];
        for y in 0..r[2] { for x in 0..g[0].len() { if g[y][x] > 0 
            { r = [y, r[1].max(x), r[2].min(y), r[3].min(x)] }
        }} ((r[1] - r[3] + 1) * (r[0] - r[2] + 1)) as _
    }



// 275ms
    int minimumArea(vector<vector<int>>& g) {
        int a=0,b=0,c=size(g),d=size(g[0]),n=c,m=d;
        for (int y = 0; y < n; ++y) for (int x = 0; x < m; ++x)
            g[y][x]&&(a=y,b=b>x?b:x,c=c<y?c:y,d=d<x?d:x);
        return (a-c+1)*(b-d+1);
    }



// 3144ms
    def minimumArea(_, g):
       i, j = zip(*((y,x) for y,r in enumerate(g) for x,v in enumerate(r) if v)) 
       return (max(j)-min(j)+1)*(max(i)-min(i)+1)



// 2593ms
    def minimumArea(_, g):
        n,m = len(g), len(g[0])
        t = next(i for i in range(n) if 1 in g[i])
        b = next(i for i in range(n-1,-1,-1) if 1 in g[i])
        l = next(j for j in range(m) if any(g[i][j] for i in range(n)))
        r = next(j for j in range(m-1,-1,-1) if any(g[i][j] for i in range(n)))
        return (b-t+1)*(r-l+1)


21.08.2025

1504. Count Submatrices With All Ones medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1088

Problem TLDR

Count islands of 1 #medium #dp

Intuition

    // 
    //   4  
    //   *  
    //   *  
    // 1 *  
    // * x  
    // 1 4  

    //   3     
    //   4   4 
    //   * 3 * 
    //   * * * 
    // 1 * * * 
    // * * * x 
    // 1 3 3 4 
    //
    //   3       5
    //   4   4 4 *
    //   * 3 * * *
    //   * * * * *
    // 1 * * * * *
    // * * * * * x
    // 1 3 3 4 4 5
    //
    //   4       6
    //   5   5 5 *
    //   * 4 * * *
    //   * * * * *
    // 2 * * * * *
    // * * * * * *
    // * * * * * x
    // 2 4 4 5 5 6

    // 1,0,1,1,1,1,1   16
    // 1,1,0,0,0,1,1
    // 2 1       2 2   26
    // 1,1,1,0,0,1,1
    // 3 2 1
    // 1,0,1,0,1,0,1
    // 1,0,1,1,1,0,1
    // 1,1,0,1,1,1,1
    // 1,0,0,1,1,0,1

Go row by row, store the heights. For each new position

  • it is the bottom right corner of all possible rectangles
  • it is equal to the sum of decreasing heights

Approach

  • reuse the input (not in production or in interview)
  • the monotonic stack is not required; idea: it holds only increasing indices, pop while decrease, remove the diff (use the next index in stack or -1)

Complexity

  • Time complexity: \(O(n^2m)\)

  • Space complexity: \(O(1)\)

Code


// 8ms
    fun numSubmat(m: Array<IntArray>): Int {
        var res = 0; val h = IntArray(m[0].size)
        for (r in m) for (x in h.indices) {
            var c = r[x] * ++h[x]; h[x] = c 
            for (j in x downTo 0) { c = min(c, h[j]); res += c }
        }
        return res
    }



// 53ms
    fun numSubmat(m: Array<IntArray>) =
        m.withIndex().sumOf { (y, h) ->
            val st = Stack<Int>(); var c = 0
            m[y].indices.sumOf { x ->
                h[x] = m[y][x] * (1 + if (y > 0) m[y-1][x] else 0); c += h[x]
                while (st.size > 0 && h[st.peek()] > h[x]) {
                    val j = st.pop()
                    c -= (h[j] - h[x]) * (j - if (st.size > 0) st.peek() else -1)
                }
                st += x; c
            }
        }



// 4ms
    pub fn num_submat(m: Vec<Vec<i32>>) -> i32 {
        let (mut r, mut h) = (0, vec![0; m[0].len()]);
        for y in &m { for x in 0..h.len() {
            let mut c = y[x] * (1 + h[x]); h[x] = c; 
            for j in (0..=x).rev() { c = c.min(h[j]); r += c }
        }} r
    }



// 5ms
    int numSubmat(vector<vector<int>>& m) {
        int res = 0; vector<int> h(size(m[0]));
        for (auto& r: m) for (int x = 0; x < size(r); ++x) {
            int c = r[x] * ++h[x]; h[x] = c;
            for (int j = x; j >= 0; --j) res += c = min(c, h[j]);
        } return res;
    }



// 772ms
    def numSubmat(_, m):
        r = 0; h = [0] * len(m[0])
        for y in m:
            for i,x in enumerate(y):
                c=x and h[i]+1;h[i]=c
                r+=sum((c:=min(c, h[j])) for j in range(i, -1, -1))
        return r


20.08.2025

1277. Count Square Submatrices with All Ones medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1087

Problem TLDR

Count square islands of 1 #medium #dp

Intuition

Reuse the previous row calculations:

  • look diagonal up-left
  • look up
  • count left

Approach

  • try to write without ifs
  • reuse the input (not in production or in interview)

Complexity

  • Time complexity: \(O(nm)\)

  • Space complexity: \(O(1)\)

Code


// 21ms
    fun countSquares(m: Array<IntArray>) = with(m) {
        for (y in 1..<size) for (x in 1..<m[0].size) 
            m[y][x] *= 1 + min(m[y][x-1], min(m[y-1][x-1], m[y-1][x]))
        sumOf { it.sum() }
    }



// 0ms
    pub fn count_squares(mut m: Vec<Vec<i32>>) -> i32 {
        for y in 1..m.len() { for x in 1..m[0].len() {
            m[y][x] *= 1 + m[y][x-1].min(m[y-1][x-1]).min(m[y-1][x])
        }} m.iter().flatten().sum()
    }



// 0ms
    int countSquares(vector<vector<int>>& m) {
        int r = 0;
        for (int y = 0; y < size(m); ++y) for (int x = 0; x < size(m[0]); ++x)
        r += m[y][x] *= 1 + (y&&x ? min(m[y-1][x-1], min(m[y][x-1], m[y-1][x])): 0);
        return r;
    }



// 85ms
    def countSquares(_, m: List[List[int]]):
        for y in range(len(m)):
            for x in range(len(m[0])):
                m[y][x] *= 1 + (y and x and min(m[y-1][x-1], m[y][x-1], m[y-1][x]))
        return sum(map(sum, m))


19.08.2025

2348. Number of Zero-Filled Subarrays medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1086

Problem TLDR

Count 0-subarrays #medium #counting

Intuition

Count zero islands, use arithmetic sum: n(n+1)/2

Approach

  • instead of arithmetics, just add current count to the result

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 5ms
    fun zeroFilledSubarray(n: IntArray) =
        n.fold(0L) { r, t -> 
            if (t == 0) ++n[0] else n[0] = 0; r + n[0]
        }


// 3ms
    fun zeroFilledSubarray(n: IntArray): Long {
        var res = 0L; var curr = 0
        for (x in n) {
            if (x == 0) ++curr else curr = 0
            res += curr
        }
        return res
    }



// 0ms
    pub fn zero_filled_subarray(n: Vec<i32>) -> i64 {
        let (mut r, mut c) = (0, 0);
        for x in n { if (x == 0) { c += 1 } else { c = 0 }; r += c } r
    }



// 0ms
    long long zeroFilledSubarray(vector<int>& n) {
        long long r = 0;
        for (int c = 0; int x: n) r += c = x ? 0: ++c;
        return r;
    }



// 49ms
    zeroFilledSubarray = lambda _,n: sum(accumulate(n, lambda c,x: (c+1)*(x==0), initial=0))



18.08.2025

679. 24 Game hard blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1085

Problem TLDR

Can a,b,c,d = 24 with ops */+-() #hard #backtracking #math

Intuition

Solved not optimally.

    // 1..9
    // ()+-/*
    // 12 * 2
    // 8 * 3
    // 6 * 4
    // 2 * 3 * 4
    // 2 * 3 * 2 * 2
    // 1 - 2/3 = 1/3; 8 / (1 - 2/3)
    // 1 - 3/4 = 1/4; 6 / (1 - 3/4)
    // 1 - 5/6 = 1/6; 4 / (1 - 5/6)
    // 1 - 7/8 = 1/8; 3 / (1 - 7/8)
    // 20+4; 5*4+2+2    2+2=1..3 + 3..1
    //       5*(2+2)+4
    // 21+3; too many to list them all
    // implement eval?

    // 1 3 4 6
    // 6/(1-3/4)

    // i don't think my solution is the expected
    // 0123456789012
    // .x..x...x..x.   13 positions
    // (  (   (   
    //      )   )  )
    //   +   +   +
    //   -   -   -
    //   *   *   *
    //   /   /   /
    //  a  a   a  a
    //  b  b   b  b
    //  c  c   c  c
    //  d  d   d  d

My intuition was just to build all possible equations, then parse them and eval.

The optimal intuition (not mine): every equation has the first step than you can do, just compute by picking any two numbers.

Approach

  • solve not optimally to appreciate the cleverness of an idea

Complexity

  • Time complexity: \(O(n^(2n))\), n levels deep, n^2 at each level

  • Space complexity: \(O(n^n)\), n levels, n size at each level

Code


// 80ms
    fun judgePoint24(cards: IntArray): Boolean {
        fun dfs(cs: List<Double>): Boolean {
            for (i in cs.indices) for (j in cs.indices) if (i != j) {
                val a = cs[i]; val b = cs[j]
                val next = arrayListOf(a+b, a-b,b-a, a*b); if(b!=0.0) next += a/b
                val rest = (cs.indices - i - j).map {cs[it]}
                for (x in next) if (dfs(rest + x)) return true
            }
            return cs.size == 1 && abs(24.0-cs[0])<0.001
        }
        return dfs(cards.map { 1.0 * it })
    }


17.08.2025

837. New 21 Game medium blog post substack youtube

1.webp

https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1084

Problem TLDR

Probability sum of random(1..m) less than n when stop adding at k #medium #math #probability

Intuition

Didn’t solved without TLE

    // each step:
    // sum +=
    // + random(1..maxpts)
    // + random(1..maxpts)
    // + random(1..maxpts)
    // + random(1..maxpts)
    // stop if sum bigger than k
    //
    // probability sum <= n

    // n=10 k=1 m=10
    // s += 
    // 1..10   (let's be 1)
    // s = 1 bigger k -- stop
    // s less 10 true

    // n=6 k=1 m=10
    // s +=
    //   1,2,3,4,5,6
    //   7,8,9,10
    // s is more than k; stop
    // only 6/10 is less than n

    // n=21 k=17 m=10
    // 1..10   
    // 1..10
    // making +1 calls is too heavy 10^4 x 10^4 TLE
    // maybe wrong dp dimension?
    //  no hints; i'll give up
    // i didn't get why p20=p16*p4+p15*p5+..p10*p10

The math intuition: (credits https://leetcode.com/problems/new-21-game/solutions/220949/python-3-memorize-dfs-from-o-kw-w-to-o-k-w/)

f(s) = f(s+1)+f(s+2)+...+f(s+m)  /m
f(s+1) = f(s+2)+f(s+3)+...+f(s+m)+f(s+1+m)  /m

f(s) - f(s+1) = (f(s+1) - f(s+1+m)) /m

The final condition:


k......n......m means we take (n-k)/m

k.............m....n means we always good 1.0

Approach

  • try to understand at least one intuition fully

Complexity

  • Time complexity: \(O(k + m)\)

  • Space complexity: \(O(k + m)\)

Code


// 28ms
    fun new21Game(n: Int, k: Int, m: Int): Double {
        val dp = HashMap<Int, Double>()
        fun dfs(s: Int): Double = 
            if (s == k - 1) 1.0*min(n - k + 1, m) / m
            else if (s >= k) { if (s <= n) 1.0 else 0.0 }
            else dp.getOrPut(s) {
                dfs(s + 1) - (dfs(s + 1 + m) - dfs(s + 1)) / m
            }
        return dfs(0)
    }


16.08.2025

1323. Maximum 69 Number easy blog post substack youtube 1.webp https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1082

Problem TLDR

Bigger number by replacing 6 to 9 #easy

Intuition

The simpliest way is to convert to char array, replace first, then stop.

Approach

  • let’s explore other unusual ways

Complexity

  • Time complexity: \(O(1)\)

  • Space complexity: \(O(1)\)

Code


// 7ms
    fun maximum69Number (n: Int) = 
    "$n".replaceFirst('6', '9').toInt()



// 12ms
    fun maximum69Number (n: Int) = 
    n + 3 * (setOf(1000, 100, 10, 1).firstOrNull { n/it%9>0 }?:0)



// 0ms
    pub fn maximum69_number(n: i32) -> i32 {
        n + 3 * [1000, 100, 10, 1].iter().find(|&&p| n/p%10==6).unwrap_or(&0)
    }



// 0ms
    int maximum69Number (int n) {
        for (int p = 1000; p; p /= 10)
            if (n/p%10 == 6) return n + 3*p;
        return n;
    }



// 0ms
    maximum69Number = lambda _, n: int(str(n).replace('6','9',1))


15.08.2025

342. Power of Four easy blog post substack youtube 1.webp https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1081

Problem TLDR

Is number power of 4? #easy

Intuition

  • count bits, look at trailing zeros count, should be even
  • use a bitmask ...1010101010101
  • use (n-1)%3: n-1 = 4^k -1 = (2^k -1)(2^k + 1), from odd,2^n,odd row, one of the odds is always %3: 123, 345, 789, and so on

Approach

  • also fun regex solution

Complexity

  • Time complexity: \(O(1)\)

  • Space complexity: \(O(1)\)

Code


// 16ms
    fun isPowerOfFour(n: Int) =
        Regex("^1(?:00)*$").matches(n.toString(2))



// 4ms
    fun isPowerOfFour(n: Int) =
        (0..15).any { n == 1 shl it*2 }


// 1ms
    fun isPowerOfFour(n: Int) =
       n.countOneBits() == 1 && n and 1431655765 == n



// 1ms
    fun isPowerOfFour(n: Int) =
        n.countOneBits() == 1 && (n-1)%3 == 0



// 0ms
    pub fn is_power_of_four(n: i32) -> bool {
        (0..16).any(|p| n == 1 << p * 2)
    }



// 0ms
    bool isPowerOfFour(int n) {
        return n > 0 && (n & n-1) + (n-1)%3 == 0;
    }



// 0ms
    def isPowerOfFour(self, n: int) -> bool:
        return n in [1<<p*2 for p in range(16)]


14.08.2025

2264. Largest 3-Same-Digit Number in String easy blog post substack youtube https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1080

Problem TLDR

Max 3-digit in string #easy

Intuition

Sliding window is accepted and the optimal

Approach

  • compare just a single char
  • let’s explore the variations: what if we check each digit individually?

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 26ms
    fun largestGoodInteger(num: String) = num.windowed(3)
    .filter { it.toSet().size < 2 }.maxByOrNull { it[0] } ?: ""



// 15ms
    fun largestGoodInteger(n: String) = (9 downTo 0)
        .map { "$it$it$it" }.find { it in n } ?: ""



// 0ms
    pub fn largest_good_integer(num: String) -> String {
        num.as_bytes().windows(3).filter(|w| w[0] == w[1] && w[1] == w[2])
        .max_by_key(|w| w[0]).map_or("".into(), |w| from_utf8(w).unwrap().into())
    }



// 0ms
    string largestGoodInteger(string n) {
        int c = 0, p = 0; char m = 0;
        for (auto x: n) c = p == x ? ++c : 1, p = x, m = c > 2 ? max(m, x):m;
        return m > 0 ? string()+m+m+m : "";
    }



// 0ms
    def largestGoodInteger(_, n):
        return next((d*3 for d in '9876543210' if d*3 in n), '')


13.08.2025

326. Power of Three easy blog post substack youtube https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1079

Problem TLDR

Is n power of 3? #easy #math

Intuition

Almost failed at corner case Int.MAX_VALUE, be aware of Int overflow when *3. Another interesting facts:

  • 3-base representation has only single 1, others 0
  • 3^19 is max fit into Int, if 3^19 % n == 0, n is a power of 3

Approach

  • try to write all the different ways
  • the / solution is the most robust
  • some arithmetic fact: log_3(n) = log_x(n)/log_x(3) for any x

Complexity

  • Time complexity: \(O(log(n))\)

  • Space complexity: \(O(1)\)

Code


// 27ms
    fun isPowerOfThree(n: Int) = 
        n.toString(3).replace("0", "") == "1"



// 10ms
    fun isPowerOfThree(n: Int) = n > 0 &&
        3.0.pow(1.0*log(1.0*n, 3.0).roundToInt()) == 1.0*n



// 9ms
    fun isPowerOfThree(n: Int) = 
        n > 0 && 3.0.pow(19.0).toInt() % n < 1



// 8ms
    fun isPowerOfThree(n: Int): Boolean {
        if (n <= 0) return false
        var x = 1L; val n = 1L * n
        while (x < n) x *= 3
        return x == n
    }



// 8ms
    fun isPowerOfThree(n: Int): Boolean {
        var n = n; if (n > 1) while (n % 3 == 0) n /= 3
        return n == 1
    }



// 0ms
    pub fn is_power_of_three(n: i32) -> bool {
        n > 0 && 3i32.pow(19) % n < 1
    }



// 3ms
    bool isPowerOfThree(int n) {
       while (n > 1 && n % 3 == 0) n /= 3; 
       return n == 1;
    }



// 6ms
    def isPowerOfThree(self, n: int) -> bool:
        return n > 0 and 3**19%n<1


12.08.2025

2787. Ways to Express an Integer as Sum of Powers medium blog post substack youtube https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1078

Problem TLDR

Ways to make n by sum of a^x+b^x+… #medium #dp

Intuition

Solved not optimally. Consider all numbers: p = 1, 2, 3, ... a, b, c ... n and their x-powers: pow = a^x b^x c^x. Do depth-first search, at each step make a decision:

  • take the number: v + a^x, p++
  • or skip it: v, p++ If we arrive at v==n we have a one good combination, return 1. Cache the answer for inputs v, p.

For optimization, rewrite to iterate over the same values v, p, reversing the ranges. Then do a space optimization, as we always look at p+1 previous row.

Approach

  • I guess it is always good to start with simple choice instead of range iteration inside DFS

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n)\)

Code


// 1092ms
    fun numberOfWays(n: Int, x: Int): Int {
        val m = 1000000007; var maxp = n; val pow = IntArray(n + 1) { 1 }
        for (i in pow.indices) for (j in 1..x) {
            pow[i] *= i; if (pow[i] > n) maxp = min(maxp, i)
        }
        val ways = Array(maxp + 2) { IntArray(n + 1) }
        for (i in ways.indices) ways[i][0] = 1
        for (x in 1..n) for (from in maxp downTo 1)
            for (y in from..maxp) {
                if (x - pow[y] < 0) break
                ways[from][x] = (ways[from][x] + ways[y + 1][x - pow[y]])%m
            }
        return ways[1][n]
    }



// 657ms
    fun numberOfWays(n: Int, x: Int): Int {
        val m = 1000000007; val dp = HashMap<Pair<Int, Int>, Int>()
        fun dfs(v: Int, p: Int): Int = dp.getOrPut(v to p) {
            if (v == 0) 1 else if (v < 0 || p > v || Math.pow(1.0*p, 1.0*x).toInt() > v) 0 
            else (dfs(v - Math.pow(1.0*p, 1.0*x).toInt(), p + 1) + dfs(v, p + 1)) % m
        }
        return dfs(n, 1)
    }



// 15ms
    fun numberOfWays(n: Int, x: Int): Int {
        val m = 1000000007; val ways = IntArray(n + 1); ways[0] = 1
        for (p in 1..n) {
            var pow = 1; for (i in 1..x) pow *= p; if (pow > n) break
            for (v in n downTo pow) ways[v] = (ways[v] + ways[v - pow]) % m
        }
        return ways[n]
    }



// 0ms
    pub fn number_of_ways(n: i32, x: i32) -> i32 {
        let mut dp = [0;301]; let n = n as usize; dp[0] = 1;
        for p in 1..=n {
            let pow = p.pow(x as u32);
            for v in (pow..=n).rev() { dp[v] = (dp[v] + dp[v - pow]) % 1000000007 }
        } dp[n]
    }



// 14ms
    int numberOfWays(int n, int x) {
        int d[301]={}; d[0] = 1;
        for (int p = 1; p <= n && pow(p, x) <= n; ++p)
            for (int v = n, pw = pow(p, x); v >= pw; --v)
                d[v] = (d[v] + d[v-pw]) % 1000000007;
        return d[n];
    }



// 363ms
    def numberOfWays(self, n: int, x: int) -> int:
        d = [1] + [0] * n
        for p in range(1, n + 1):
            for v in range(n, p ** x - 1, -1):
                d[v] = (d[v] + d[v - p ** x]) % 1000000007
        return d[n]


11.08.2025

2438. Range Product Queries of Powers medium blog post substack youtube https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1077

Problem TLDR

Range product queries of powers of two from n #medium

Intuition

  1. Known technique to split number to the powers of two: exponentiation, each set bit is the power of two
  2. Trick observation: there are at most 30 of them, can brute-force each query ```j // 012345 // 1248 // 1111 // ok how to do modulus subarray? // maybe use the fact they are all powers of two? (not many of them)

Interesting math optimization to O(nlog(30) + 30):
* product is `2^a * 2^b * 2^c = 2^(a+b+c)` 
* so, we can use powers prefixes sum
* then product of range is `p_i_j = 2^(bits in i..j)`
* to calc `x^y %m` use math: `x^y = (x * x)^y/2 + x^y%2`

#### Approach

* use long, product can overflow even before `%m`
* optimization: precompute square matrix `30^2` for `result[from][to]`

#### Complexity

- Time complexity:
$$O(n)$$, 

- Space complexity:
$$O(1)$$

#### Code

```kotlin [-Kotlin (71ms]

// 71ms
    fun productQueries(n: Int, q: Array<IntArray>): IntArray {
        val p = ArrayList<Int>(); val M = 1000000007L
        for (b in 0..30) if (n shr b and 1 != 0) p += 1 shl b
        return IntArray(q.size) { 
            (q[it][0]..q[it][1]).fold(1L) { r, i -> (r * p[i]) % M }.toInt()
        }
    }


```kotlin [-19ms)]

// 19ms fun productQueries(n: Int, q: Array): IntArray { val p = IntArray(n.countOneBits() + 1); var i = 1; val M = 1000000007L for (b in 0..30) if (n shr b and 1 > 0) p[i] += b + p[i++ - 1] return IntArray(q.size) { val (l, r) = q[it] var k = p[r + 1] - p[l] var x = 1L; var b = 2L while (k > 0) { if (k and 1 > 0) x = (x * b) % M b = (b * b) % M; k = k shr 1 } x.toInt() } }

```rust [-Rust 15ms]

// 15ms
    pub fn product_queries(n: i32, q: Vec<Vec<i32>>) -> Vec<i32> {
        let mut p = vec![]; let M = 1000000007i64;
        for b in 0..31 { if n >> b & 1 > 0 { p.push(1i64 << b) }}
        q.iter().map(|q| { let (s, e) = (q[0] as usize, q[1] as usize);
            (s..=e).fold(1, |r, i| (r * p[i]) % M) as i32
        }).collect()
    }


```c++ [-c++ 16ms]

// 16ms vector productQueries(int n, vector<vector>& q) { vector p, r; int m = 1000000007; for (int b = 0; b < 31; ++b) if (n >> b & 1) p.push_back(1<<b); for (auto& q: q) { long x = 1L; for (int i = q[0]; i <= q[1]; ++i) x = (1L * x * p[i])%m; r.push_back((int) x); } return r; }

```python [-python 95ms]

// 95ms
    def productQueries(self, n: int, q: List[List[int]]) -> List[int]:
        m = 1_000_000_007
        p = [b for b in range(31) if (n >> b) & 1]
        pref = [0]
        for e in p:
            pref.append(pref[-1] + e)
        return [pow(2, pref[r+1] - pref[l], m) for l, r in q]



10.08.2025

869. Reordered Power of 2 medium blog post substack youtube https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1076

Problem TLDR

Rearrange digits to make power of two #medium #dfs #bits

Intuition

The naive brute force of O(log(n)!) is accepted, we only have 9 digits, n is 10^9.

The trick: think from the finish line - we only have 30 powers of two, let’s just check them.

Approach

  • compare by frequency
  • optimization: for 9 digits, each max frequency is 9, we can put freqency array into a single 10 digits number (c++ solution)

Complexity

  • Time complexity: \(O(log^2(n))\),

  • Space complexity: \(O(log(n))\)

Code

```kotlin [-Kotlin (233ms]

// 233ms fun reorderedPowerOf2(n: Int): Boolean { val ds = “$n” fun dfs(curr: Int, m: Int): Boolean { if (m == 0) return curr.countOneBits() == 1 for (i in 0..30) if (m and (1 shl i) != 0) { if (ds[i] == ‘0’ && curr == 0) continue if (dfs(curr * 10 + (ds[i] - ‘0’), m xor (1 shl i))) return true } return false } return dfs(0, (1 shl ds.length) - 1) }

```kotlin [-18ms)]

// 18ms
    fun reorderedPowerOf2(n: Int) =
        (0..30).any { "$n".groupBy { it } == "${1 shl it}".groupBy { it }}


```rust [-Rust (0ms]

// 0ms pub fn reordered_power_of2(mut n: i32) -> bool { let mut nf = [0; 10]; while n > 0 { nf[(n % 10) as usize] += 1; n /= 10 } (0..30).any(|i| { let mut x = 1 « i; let mut f = [0; 10]; while x > 0 { f[(x % 10) as usize] += 1; x /= 10 } f == nf }) }

```c++ [-c++ (0ms]

// 0ms
    bool reorderedPowerOf2(int n) {
        long c = 0; while (n) c += pow(10, n % 10), n /= 10;
        for (int i = 0, x=0, y=1; i < 30; ++i, x = 0, y = 1<<i) {
            while (y) x += pow(10, y % 10), y /= 10;
            if (x == c) return 1;
        }
        return 0;
    }


```python [-python 0ms]

// 0ms def reorderedPowerOf2(self, n: int) -> bool: return any(sorted(str(n)) == sorted(str(1 « i)) for i in range(31))

# 9.08.2025
[231. Power of Two](https://leetcode.com/problems/power-of-two/description/) easy
[blog post](https://leetcode.com/problems/power-of-two/solutions/7060229/kotlin-rust-by-samoylenkodmitry-ap99/)
[substack](https://open.substack.com/pub/dmitriisamoilenko/p/9082025-231-power-of-two?r=2bam17&utm_campaign=post&utm_medium=web&showWelcomeOnShare=true)
[youtube](https://youtu.be/dpCsHFQK4pE)
![1.webp](/assets/leetcode_daily_images/cef8cf7c.webp)
https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

#### Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1075

#### Problem TLDR


Is int 32 power of 2? #easy #bits

#### Intuition

Any negative number is not power of 2 by problem description.

#### Approach

* there are built-in functions

#### Complexity

- Time complexity:
$$O(1)$$, 

- Space complexity:
$$O(1)$$

#### Code
```kotlin [-Kotlin (0ms]

// 0ms
    fun isPowerOfTwo(n: Int) = 
    n > 0 && n.countOneBits() < 2


```kotlin [-0ms)]

// 0ms fun isPowerOfTwo(n: Int) = n > 0 && n and (n - 1) < 1

```rust [-Rust (0ms]

// 0ms
    pub fn is_power_of_two(n: i32) -> bool {
        n > 0 && n.count_ones() == 1
    }


```rust [-0ms]

// 0ms pub fn is_power_of_two(n: i32) -> bool { n > 0 && (n as u32).is_power_of_two() }

```c++ [-c++ (0ms]

// 0ms
    bool isPowerOfTwo(int n) {
        return n > 0 && !(n&(n-1));
    }



// 0ms
    bool isPowerOfTwo(int n) {
        return n > 0 && __builtin_popcount(n) < 2;
    }


```python [-python 0ms]

// 0ms def isPowerOfTwo(_, n: int) -> bool: return n > 0 and not n & (n-1)


# 8.08.2025
[808. Soup Servings](https://leetcode.com/problems/soup-servings/description/) medium
[blog post](https://leetcode.com/problems/soup-servings/solutions/7057068/kotlin-rust-by-samoylenkodmitry-8a2i/)
[substack](https://open.substack.com/pub/dmitriisamoilenko/p/8082025-808-soup-servings?r=2bam17&utm_campaign=post&utm_medium=web&showWelcomeOnShare=true)
[youtube](https://youtu.be/teBK2YRCO3M)
![1.webp](/assets/leetcode_daily_images/15f5cc29.webp)
https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

#### Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1074

#### Problem TLDR

Probability A empty first plus both empty /2 #medium #dp #probability


#### Intuition

The probability is the number of good events divided by the total number of events.
Each layer deep result should be divided by current layer number of events: `p_curr = (p deep) / curr_total_events`
```j
    // 50 50
    // 1: 100+0 - end  A first
    // 2: 70+25 - end  A first
    // 3: 50+50 - end  both
    // 4: 25+75 - end  B first
    // P(a first) = 2/4
    // P(both) = 1/4
    // 2/4 + 1/2 * 1/4 = 1/4 * (2 + 0.5) = 0.625

    // 100 100
    // 1: 100+0 A first
    // 2: 70+25     30 75                
    //              1: 100+0      A first
    //              2: 70+25      A first
    //              3: 50+50      A first
    //              4: 20+75      B first
    //              pa = 3/4 pboth = 0   p = 3/4
    // 3: 50+50     50  50
    //              1: 100+0      A first
    //              2: 70+25      A first
    //              3: 50+50      both
    //              4: 20+75      B first
    //              pa = 2/4 pboth = 1/4 p = 1/4 * (2+0.5)
    // 4: 25+75     75    25
    //              1: 100+0      A first
    //              2: 70+25      B first
    //              3: 50+50      B first
    //              4: 20+75      B first
    //              pa = 1/4 pboth=0    p=1/4
    // 
    // p = 1/4 * (1 + 3/4 + 1/4*(2+0.5) + 1/4)
    //   = 1/4 * (2 + 1/4 + 2.5/4) = 0.71875
    // can't use n directly, too big 10^9 660295675
    // maybe after some number the answer is always 1

Approach

  • just remember that on big numbers probabilities distribution collapses into the final value

Complexity

  • Time complexity: \(O(min(5000, n))\),

  • Space complexity: \(O(min(5000, n))\)

Code


// 8ms
    val dp = HashMap<Pair<Int, Int>, Double>()
    fun soupServings(a: Int, b: Int = a): Double = if (a > 5000) 1.0
        else 0.25 * dp.getOrPut(a to b) {
            if (a <= 0 && b <= 0) 2.0 else if (a <= 0) 4.0 else if (b <= 0) 0.0
            else soupServings(a - 100, b) + soupServings(a - 75, b - 25) + 
                 soupServings(a - 50, b - 50) + soupServings(a - 25, b - 75)
        }



// 5ms
    fun soupServings(n: Int): Double {
        if (n > 5000) return 1.0
        val N = 4 + (n+24) / 25; val p = Array(N) { DoubleArray(N) }
        for (j in 0..4) for (i in j..<N) { p[j][i] = 1.0; p[j][j] = 0.5 }
        for (a in 4..<N) for (b in 4..<N) p[a][b] = 0.25 * 
        (p[a-4][b] + p[a-3][b-1] + p[a-2][b-2] + p[a-1][b-3])
        return p[N-1][N-1]
    }



// 0ms
    pub fn soup_servings(n: i32) -> f64 {
        if n > 5000 { return 1.0 }
        let n = ((n+124)/25) as usize; let mut p = vec![vec![0.0;n];n];
        for j in 0..5 { for i in j..n { p[j][i] = 1.0; p[j][j] = 0.5 }}
        for a in 4..n { for b in 4..n { p[a][b] = 0.25 * 
        (p[a-4][b] + p[a-3][b-1] + p[a-2][b-2] + p[a-1][b-3])}}; p[n-1][n-1]
    }



// 0ms
    double soupServings(int n) {
        if (n > 5000) return 1.0;
        int m = (n + 124)/25; double p[201][201]={0};
        for (int j = 0; j < 5; ++j) for (int i = j; i < m; ++i) p[j][i]=1.0, p[j][j]=0.5;
        for (int a = 4; a < m; ++a) for (int b = 4; b < m; ++b) p[a][b] = 0.25 *
        (p[a-4][b] + p[a-3][b-1] + p[a-2][b-2] + p[a-1][b-3]);
        return p[m-1][m-1];
    }



// 9ms
    def soupServings(self, n: int) -> float:
        if n > 5000: return 1.0
        m = (n + 124) // 25
        p = [[0.0]*(m + 1) for _ in range(m + 1)]
        for j in range(5):
            for i in range(j, m): p[j][i] = 1.0
            p[j][j] = 0.5
        for a in range(4, m):
            for b in range(4, m):
                p[a][b] = 0.25*(p[a-4][b] + p[a-3][b-1] + p[a-2][b-2] + p[a-1][b-3])
        return p[m-1][m-1]


7.08.2025

3363. Find the Maximum Number of Fruits Collected hard blog post substack youtube 1.webp https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1073

Problem TLDR

Max 3 paths from corners to bottom end #hard

Intuition

Used the hints.

Two insights:

  1. middle only goes diagonal
  2. two other guys are the two separate searches
    // dfs or bfs?
    // greedy? - i think can be non-optimal
    // either full search with bfs or dp with dfs+cache
    // 3x3x3 = 27 steps by each bfs layer
    // exactly n-1 steps AND reach n,n cell - no non-optimal steps
    // i am writing the dfs+dp, the growth factor is n^27
    // let's use hints
    // nice, child 0 can only move diagonal (as by rules)
    // child 1&2 can't cross diagonal
    // my solution TLE
    // look for other hints, no new information
    // are we expected use raw arrays? bottom up?
    // expected bottom up
    // children b and c can go separate

Approach

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n^2)\)

Code


// 697ms
    fun maxCollectedFruits(f: Array<IntArray>, n: Int = f.lastIndex): Int {
        data class P(val x: Int, val y: Int) { val i = x < 0 || y < 0 || x > n || y > n }
        fun dfs(p: P, d: List<Int>, dp: HashMap<P, Int> = HashMap()): Int = dp.getOrPut(p) {
            f[p.y][p.x] + (0..2).maxOf { 
                val b = P(p.x + d[it*2], p.y + d[it*2 + 1])
                if (!b.i && (b.y - b.x).sign == d[2].sign) dfs(b, d, dp) else 0
            }}
        val b = listOf(1, 1, -1, 1, 0, 1); val c = listOf(1, 0, 1, 1, 1, -1)
        return dfs(P(n, 0), b) + dfs(P(0, n), c) + (0..n).sumOf { f[it][it] }
    }


6.08.2025

3479. Fruits Into Baskets III medium blog post substack youtube 1.webp https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1072

Problem TLDR

Place fruits left to right to first available bucket #medium #segment_tree

Intuition

Use a segment tree: range 4length, 2i+1,2i+2, compare max(l, r)

Approach

  • try to memorize how segment tree code looks like
  • the iterative segment tree: size of 2*next_power_of_two, copy array to the second part

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(n)\)

Code


// 45ms
    fun numOfUnplacedFruits(f: IntArray, b: IntArray): Int {
        var sz = 1; var i = 1; while (sz < b.size) sz *= 2
        val s = IntArray(sz * 2); for (i in b.indices) s[sz + i] = b[i]
        for (i in sz - 1 downTo 1) s[i] = max(s[i*2], s[i*2+1])
        return f.count { f ->
            while (i < sz) { i *= 2; if (s[i] < f) i++ }
            (i >= s.size || s[i] < f).also { if (!it) {
                s[i] = 0; while (i > 1) { s[i/2] = max(s[i], s[i xor 1]); i /= 2 }
            } else i = 1 }
        }
    }



// 58ms
    fun numOfUnplacedFruits(f: IntArray, b: IntArray): Int {
        val s = IntArray(b.size * 4)
        fun make(i: Int, l: Int, h: Int): Int {
            if (l == h) { s[i] = b[l]; return s[i] }
            val m = (l + h) / 2
            s[i] = max(make(2*i+1, l, m), make(2*i+2, m + 1, h))
            return s[i]
        }
        fun check(v: Int, i: Int, l: Int, h: Int): Boolean =
            if (l == h) {
                if (s[i] >= v) { s[i] = 0; true } else false
            } else  if (s[i] < v) false else {
                val m = (l + h) / 2
                val r = check(v, 2*i+1, l, m) || check (v, 2*i+2, m + 1, h)
                s[i] = max(s[2*i+1], s[2*i+2]); r
            }
        make(0, 0, b.lastIndex)
        return f.size - f.count { check(it, 0, 0, b.lastIndex) }
    }



// 40ms
    pub fn num_of_unplaced_fruits(f: Vec<i32>, b: Vec<i32>) -> i32 {
        fn make(i: usize, l: usize, h: usize, s: &mut Vec<i32>, b: &Vec<i32>) {
            if l == h { s[i] = b[l] } else {
                let m = (l + h) / 2; make(2*i+1, l, m, s, b); make(2*i+2, m+1, h, s, b);
                s[i] = s[2*i+1].max(s[2*i+2])
            }}
        fn c(v: i32, i: usize, l: usize, h: usize, s: &mut Vec<i32>) -> bool {
            if l == h {
                if s[i] >= v { s[i] = 0; true } else { false }
            } else if s[i] < v { false } else {
                let m = (l + h) / 2; let r = c(v, 2*i+1, l, m, s) || c(v, 2*i+2, m+1, h, s);
                s[i] = s[2*i+1].max(s[2*i+2]); r
            }}
        let mut s = vec![0; b.len() * 4]; make(0, 0, b.len()-1, &mut s, &b);
        (f.len() - (0..f.len()).filter(|&i| c(f[i], 0, 0, b.len()-1, &mut s)).count()) as _
    }



// 27ms
    pub fn num_of_unplaced_fruits(f: Vec<i32>, b: Vec<i32>) -> i32 {
        let sz = b.len().next_power_of_two(); let mut s = vec![0; 2 * sz];
        s[sz..sz + b.len()].copy_from_slice(&b); let mut r = 0;
        for i in (1..sz).rev() { s[i] = s[2*i].max(s[2*i+1]) }
        for f in f {
            let mut i = 1; while i < sz { i *= 2; if s[i] < f { i += 1 }}
            if i >= sz && s[i] >= f {
                s[i] = 0; while i > 1 { i /= 2; s[i] = s[i*2].max(s[i*2+1]) }
            } else { r += 1 }
        } r
    }



// 45ms
    int numOfUnplacedFruits(vector<int>& f, vector<int>& b) {
        int n = size(b), sz = 1, r = 0; while (sz < n) sz <<= 1;
        vector<int> s(2*sz); copy(begin(b), end(b), begin(s) + sz);
        for (int i = sz-1; i; --i) s[i] = max(s[i<<1], s[i<<1|1]);
        for (int f: f) {
            int i = 1; while (i < sz) { i <<= 1; if (s[i] < f) ++i; }
            if (i < 2*sz && s[i] >= f) {
                s[i] = 0; for (; i; i >>= 1) s[i>>1] = max(s[i], s[i^1]);
            } else ++r;
        } return r;
    }



// 1591ms
    def numOfUnplacedFruits(self, f: List[int], b: List[int]) -> int:
        n = len(b); sz = 1
        while sz < n: sz *= 2
        s = [0] * (2 * sz); s[sz:sz + n] = b; r = 0
        for i in range(sz - 1, 0, -1): s[i] = max(s[i<<1], s[i<<1|1])
        for f in f:
            i = 1
            while i < sz: i <<= 1; i += s[i] < f
            if i < 2 * sz and s[i] >= f:
                s[i] = 0; 
                while i: s[i>>1] = max(s[i], s[i^1]); i >>= 1
            else: r += 1
        return r

5.08.2025

3477. Fruits Into Baskets II easy blog post substack youtube https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1071

Problem TLDR

Place fruits left to right to first available bucket #easy #simulation

Intuition

Simulate the process, brute-force is accepted.

Approach

  • the code is simpler with decreasing result from size
  • refresh your memory about segment trees: range 4length, 2i+1,2i+2, compare max(l, r)

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(1)\) or O(n) if not modyfying the inputs

Code


// 24ms
    fun numOfUnplacedFruits(f: IntArray, b: IntArray) = f.size - 
        f.count { f -> b.indices.any { i -> (b[i] >= f).also { if (it) b[i] = 0}}}



// 13ms
    fun numOfUnplacedFruits(f: IntArray, b: IntArray): Int {
        val s = IntArray(4 * b.size)
        fun make(l: Int, h: Int, i: Int): Int {
            if (l == h) { s[i] = b[l]; return s[i] }
            val m = (l + h) / 2
            s[i] = max(make(l, m, 2 * i + 1), make(m + 1, h, 2 * i + 2))
            return s[i]
        }
        fun q(x: Int, l: Int, h: Int, i: Int): Boolean =
            if (l == h) if (s[i] >= x) { s[i] = 0; true } else false
            else if (s[i] >= x) {
                val m = (l + h) / 2
                val r = q(x, l, m, 2 * i + 1) || q(x, m + 1, h, 2 * i + 2)
                s[i] = max(s[2 * i + 1], s[2 * i + 2]); r
            } else false
        make(0, b.lastIndex, 0)
        return f.size - f.count { q(it, 0, b.lastIndex, 0) }
    }


// 3ms
    fun numOfUnplacedFruits(f: IntArray, b: IntArray): Int {
        var res = f.size
        for (f in f) for (i in b.indices) 
            if (b[i] >= f) { b[i] = 0; res--; break }
        return res
    }



// 0ms
    pub fn num_of_unplaced_fruits(f: Vec<i32>, mut b: Vec<i32>) -> i32 {
        let mut r = f.len() as i32;
        for f in f { for i in 0..b.len() { if b[i] >= f { b[i] = 0; r -= 1; break }}} r
    }



// 0ms
    int numOfUnplacedFruits(vector<int>& f, vector<int>& b) {
        int c = 0;
        for (int f: f) for (int& b: b) if (b >= f) { b = 0, ++c; break; };
        return size(b) - c;
    }



// 19ms
    def numOfUnplacedFruits(self, f: List[int], b: List[int]) -> int:
        r = len(b)
        for f in f:
            for i, v in enumerate(b):
                if v >= f: b[i] = 0; r -= 1; break
        return r


4.08.2025

904. Fruit Into Baskets medium blog post substack youtube https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1070

Problem TLDR

Max consequent two-types range #medium #counting

Intuition

Scan from left to right. Count current type and previous. On a third type drop the previous.

Approach

  • how many extra variables we need?

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 39ms
    fun totalFruit(f: IntArray): Int {
        var p = -1; var c = 0; var j = 0
        return f.withIndex().maxOf { (i, t) ->
            if (t != f[j]) {
                if (t != p) c = i - j
                p = f[j]; j = i
            }
            ++c
        }
    }



// 0ms
    pub fn total_fruit(f: Vec<i32>) -> i32 {
        let (mut p, mut k, mut j) = (-1, 0, 0);
        f.iter().enumerate().map(|(i, &t)| {
            if t != f[j] {
                if t != p { k = j }
                p = f[j]; j = i
            }
            i - k + 1
        }).max().unwrap() as _
    }



// 0ms
    int totalFruit(vector<int>& f) {
        int r = 0;
        for (int i = 0, j = 0, p = -1, k = 0; i < size(f); ++i) {
            if (f[i] != f[j]) {
                if (f[i] != p) k = j;
                p = f[j]; j = i;
            }
            r = max(r, i - k + 1);
        } return r;
    }



// 77ms
    def totalFruit(self, f: List[int]) -> int:
        r = j = k = 0; p = -1
        for i, t in enumerate(f):
            if t != f[j]:
                if t != p: k = j
                p,j = f[j],i
            r = max(r, i - k + 1)
        return r


3.08.2025

2106. Maximum Fruits Harvested After at Most K Steps hard blog post substack youtube https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1069

Problem TLDR

Max values k steps from start point #hard #sliding_window

Intuition

    // k = 30
    // 0      1     2      3      4      5      6      7      8      9      10     11     12     13      14     15      16    17      18
    // [[0,7],[7,4],[9,10],[12,6],[14,8],[16,5],[17,8],[19,4],[20,1],[21,3],[24,3],[25,3],[26,1],[28,10],[30,9],[31,6],[32,1],[37,5],[40,9]]
    //                                                               sp

Sliding window:

  • always move the right border
  • move left until condition
  • update max

The main hardness is to peek the smaller path between the two: go back then forward, or go forward then back.

Approach

  • the queue is not necessary, just a left pointer is enough

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 15ms
    fun maxTotalFruits(f: Array<IntArray>, sp: Int, k: Int): Int {
        var q = 0; var sum = 0
        return f.maxOf { (x, a) ->
            while (min(sp + x - 2*f[q][0], 2*x - sp - f[q][0]) > k) sum -= f[q++][1]
            if (abs(x - sp) > k) { ++q; 0 } else { sum += a; sum }
        }
    }



// 3ms
    fun maxTotalFruits(f: Array<IntArray>, sp: Int, k: Int): Int {
        var q = 0; var sum = 0; var r = 0
        for ((x, a) in f) {
            if (x - sp > k) break; if (sp - x > k) { ++q; continue }
            while (min(sp + x - 2*f[q][0], 2*x - sp - f[q][0]) > k) sum -= f[q++][1]
            sum += a; r = max(r, sum)
        }
        return r
    }



// 11ms
    pub fn max_total_fruits(f: Vec<Vec<i32>>, sp: i32, k: i32) -> i32 {
        let (mut q, mut s) = (0, 0);
        f.iter().map(|v| {
            while (sp + v[0] - 2*f[q][0]).min(2*v[0] - sp - f[q][0]) > k { s -= f[q][1]; q += 1 }
            if (v[0] - sp).abs() > k { q += 1; 0 } else { s += v[1]; s }
        }).max().unwrap()
    }



// 2ms
    int maxTotalFruits(vector<vector<int>>& f, int sp, int k) {
        int q = 0, s = 0, r = 0;
        for (auto& v: f) {
            if (v[0] - sp > k) break; if (sp - v[0] > k) { ++q; continue; }
            while (min(sp + v[0] - 2*f[q][0], 2*v[0] - sp - f[q][0]) > k) s -= f[q++][1];
            r = max(r, s += v[1]);
        } return r;
    }



// 104ms
    def maxTotalFruits(self, f: List[List[int]], s: int, k: int) -> int:
        q = r = t = 0
        for x, a in f:
            if s - x > k: q += 1; continue
            while min(s + x - 2*f[q][0], 2*x - s - f[q][0]) > k: t -= f[q][1]; q += 1
            t += a if x - s <= k else 0; r = max(r, t)
        return r


2.08.2025

2561. Rearranging Fruits hard blog post substack youtube https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1068

Problem TLDR

Min swaps cost to make a==b #hard #greedy

Intuition

Didn’t solved

    // first idea:
    // count freq1, freq2
    // f1[i] % 2 != 0, f2[j] % 2 != 0
    // in f1 and not in f2 (split by half)
    // in f2 and not in f1 (split by half)
    // f1[x] != f2[x] then move
    // 1: 2            0    split, cost = 1 * 2/2 = 1
    // 2: 3            1    move, 3 - (3+1)/2, b[i] * (max(f1,f2) - (f1+f2)/2)
    // we have array of costs:, count should be % 2
    // c1 c2 c3 c4 and have to pick pairs (min,max), 
    // sort, then two pointers
    // wrong answer (14 minute)
    // [84,80,43,8,80,88,43,14,100,88]
    // [32,32,42,68,68,100,42,84,14,8]
    // {84=1, 80=2, 43=2, 8=1, 88=2, 14=1, 100=1}
    // {32=2, 42=2, 68=2, 100=1, 84=1, 14=1, 8=1}
    // 8, 14, 43, 43, 80, 80, 84, 88, 88, 100   a
    // 8, 14, 32, 32, 42, 42, 68, 68, 84, 100   b
    // move x=80 a=2 b=0, cost=80
    // move x=43 a=2 b=0, cost=43
    // move x=88 a=2 b=0, cost=88
    // move x=32 a=0 b=2, cost=32
    // move x=42 a=0 b=2, cost=42
    // move x=68 a=0 b=2, cost=68
    // [32, 42, 43, 68, 80, 88]
    //  b   b   a   b   a   a
    // 43 80 88
    // 32 42 68    32,88 + 43,68 + 42,80 = 32+43+42 = 32+85 = 117
    // wrong answer how is it 48? where is 48 from?
    // took hints (29 minutes)
    // the hint in the comments: `use the minimum element 8 to do 6 swaps.` (what??)
    // how does indirect swap works?
    //
    // 2 2 100 100
    // 3 3 200 200
    //
    // 3 2 100 100       2
    // 3 2 200 200
    //
    // 2 200 100 100     2
    // 3 3 200 2
    //
    // 2 200 2 100       2
    // 3 3 200 100 
    //
    // 2 200 3 100       2         2x4=8
    // 3 2 200 100 
    //
    // or
    // 200 2 100 100     2
    // 3 3 2 200
    //
    // 200 2 3 100       3      2+3=5
    // 100 3 2 200

    // 1 100 100
    // 1 200 200
    //
    // 200 100 100     1
    // 1 1 200
    //
    // 200 1 100       1
    // 1 100 200
    //
    // 4 4 4 4 3
    //  3
    //
    // 4 4 4 3 3       3
    // 5 5 5 5 4
    //
    // 4 4 4 3 5       3
    // 5 5 5 3 4
    //
    // 4 4 4 5 5       3
    // 5 5 3 3 4
    //
    // 4 4 3 5 5       3
    // 5 5 3 4 4             4x3=12
    // 
    // another corner case if smallest itself in the wrong position
    // 28 wrong positions, ans smallest here, so 27

```j

What went wrong:
* I was trying to cut corners with some complex `algorithm` to make greedy work with entire groups
* however, with greedy, we have to simulate each step individually, hence make a greedy choice for each swapped value, between itself and `2 * min` jump

#### Approach

* the solution from https://leetcode.com/problems/rearranging-fruits/solutions/3143735/ordered-map/ has mind blowing trick: `min(sw, abs(f) / 2)`; we `assume` that the optimal swaps count can't be more than `sw` (swaps from one side to another)
* to make greedy optimization for groups is to make at most `sw` swaps

#### Complexity

- Time complexity:
$$O(nlog(n))$$

- Space complexity:
$$O(n)$$

#### Code

```kotlin 

// 101ms
    fun minCost(b1: IntArray, b2: IntArray): Long {
        val f1 = b1.groupBy { it }; val f2 = b2.groupBy { it }
        val min = min(b1.min(), b2.min())
        return (f1.keys + f2.keys).flatMap { x ->
            val a = f1[x]?.size ?: 0; val b = f2[x]?.size ?: 0; 
            if ((a + b) % 2 > 0) return -1L
            List(abs(a - b) / 2) { x }
        }.run { sorted().take(size/2).sumOf { 1L * min(it, 2 * min) }}
    }



// 71ms
    fun minCost(a: IntArray, b: IntArray): Long {
        val m = TreeMap<Int, Int>(); var sw = 0; var r = 0L; val min = min(a.min(), b.min())
        for (x in a) m[x] = (m[x] ?: 0) + 1; for (x in b) m[x] = (m[x] ?: 0) - 1
        for ((x, f) in m) { if (f % 2 != 0) return -1L; sw += max(0, f / 2) }
        for ((x, f) in m) {
            val take = min(sw, abs(f) / 2)
            r += 1L * take * min(x, min * 2)
            sw -= take; if (sw == 0) break
        }
        return r
    }


1.08.2025

118. Pascal’s Triangle easy blog post substack youtube https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1067

Problem TLDR

Pascal’s Triangle #easy

Intuition

Classic problem, reuse the previous row.

Approach

  • many ways to write this: fold, scan, recursion, zip

Complexity

  • Time complexity: \(O(2^n)\)

  • Space complexity: \(O(2^n)\)

Code


// 15ms
    fun generate(n: Int) = (2..n).runningFold(listOf(1)) 
    { r, t -> listOf(1) + r.windowed(2) { it.sum() } + 1 }



// 0ms
    pub fn generate(n: i32) -> Vec<Vec<i32>> {
        (0..n).scan(vec![1], |c, _| { let r = c.clone();
            *c = vec![vec![1], c.windows(2).map(|w| w[0] + w[1]).collect(), vec![1]].concat();
            Some(r)
        }).collect()
    }



// 0ms
    vector<vector<int>> generate(int n) {
        if (n == 1) return 1; auto p = generate(n - 1); vector<int>r{1};
        for (int i = 1; i < size(p[n - 2]); ++i)
            r.push_back(p[n - 2][i - 1] + p[n - 2][i]);
        r.push_back(1); p.push_back(r); return p;
    }



// 0ms
    def generate(self, n: int) -> List[List[int]]:
        r=[]
        for _ in[0]*n:r+=[[1]]if not r else[[1]+[a+b for a,b in zip(r[-1],r[-1][1:])]+[1]]
        return r


31.07.2025

898. Bitwise ORs of Subarrays medium blog post substack youtube https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1066

Problem TLDR

Uniq OR-subarrays #medium #dp #bits

Intuition

    // 101
    // 111
    // 010
    //
    // 001
    // 010
    // 110
    // 100    brainteaser, what's the rule?

    // 1000
    // 1010
    // 1001
    // 1101  should have some bits that are not filled previosly
    //       and propagate this bits up to the latest index where this bit was seen

My idea:

  • store last visited bits positions
  • for each new bit propagate it up to last visited

Other ideas:

  • brute-force, but keep intermediate results in a set to reduce space and time
  • same as mine core, but instead of tracking bits, modify array and go up until a[j] a[i] != a[j]

Approach

  • clever optimization from https://leetcode.com/problems/bitwise-ors-of-subarrays/solutions/166832/c-simplest-fastest-224-ms/ by using the fact: each new bit increases the number, so numbers are growing, no need for set (but still need at the end, as it is a series of growing parts)

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(r)\)

Code


// 165ms
    fun subarrayBitwiseORs(n: IntArray): Int {
        val s = ArrayList<Int>(); var a = 0; var b = 0
        for (x in n) {
            a = b; b = s.size; s += x
            for (j in a..<b) if (s.last() != s[j] or x) s += s[j] or x
        }
        return s.toSet().size
    }



// 155ms
    fun subarrayBitwiseORs(a: IntArray): Int {
        val s = a.toHashSet(); val l = IntArray(30)
        for ((i, x) in a.withIndex()) {
            var j = i; var c = x
            for (b in 0..29) if (x shr b and 1 > 0) {
                while (j > l[b]) { c = c or a[--j]; s += c }
                l[b] = i
            }
        }
        return s.size
    }



// 126ms
    fun subarrayBitwiseORs(a: IntArray): Int {
        val s = a.toHashSet()
        for (i in a.indices) {
            var j = i - 1
            while (j >= 0 && a[i] or a[j] != a[j]) { a[j] = a[i] or a[j]; s += a[j--] }
        }
        return s.size
    }



// 58ms
    pub fn subarray_bitwise_o_rs(a: Vec<i32>) -> i32 {
        let (mut s, mut l) = (vec![], [0; 30]);
        for i in 0..a.len() {
            let x = a[i]; let (mut j, mut c) = (i, x); s.push(x);
            for b in 0..30 { if x >> b & 1 > 0 {
                while j > l[b] { j -= 1; c |= a[j]; s.push(c); }
                l[b] = i
            }}
        } s.sort_unstable(); s.dedup(); s.len() as _
    }



// 42ms
    pub fn subarray_bitwise_o_rs(mut a: Vec<i32>) -> i32 {
        let mut s = vec![];
        for i in 0..a.len() {
            let mut j = i - 1; s.push(a[i]);
            while j < a.len() && a[i] | a[j] != a[j] { a[j] |= a[i]; s.push(a[j]); j -= 1 }
        } s.sort_unstable(); s.dedup(); s.len() as _
    }



// 256ms
    int subarrayBitwiseORs(vector<int>& n) {
        unordered_set<int> s;
        for (int i = 0; i < size(n); ++i) {
            s.insert(n[i]);
            for (int j = i - 1; j >= 0 && ((n[i] | n[j]) != n[j]); --j)
                n[j] |= n[i], s.insert(n[j]);
        } return size(s);
    }



// 499ms
    def subarrayBitwiseORs(self, a: List[int]) -> int:
        s,o=set(),set();[s.update(o:={x|y for y in o}|{x}) for x in a]; return len(s)
 

30.07.2025

2419. Longest Subarray With Maximum Bitwise AND medium blog post substack youtube 1.webp https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1065

Problem TLDR

Longest max OR subarray #medium #counting

Intuition

    // 011
    // 010
    // 111
    // 100

Each new element decreases OR, consider only equal values.

Approach

  • longest subarray of maxes
  • many one-liners possible
  • 09/2024 - 13 minutes, 07/2025 - 10 minutes

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 43ms
    fun longestSubarray(n: IntArray, m: Int = n.max()) =
        n.runningFold(0) { l, x -> if (x == m) l + 1 else 0 }.max()



// 4ms
    fun longestSubarray(n: IntArray): Int {
        var m = 0; var r = 0; var l = 0
        for (x in n) if (x > m) { m = x; r = 1; l = 1 }
            else if (x < m) l = 0 else r = max(r, ++l)
        return r
    }



// 0ms
    pub fn longest_subarray(n: Vec<i32>) -> i32 {
        n.into_iter().dedup_with_count()
        .max_by_key(|&d| (d.1, d.0)).unwrap().0 as _
    }



// 1ms
    int longestSubarray(vector<int>& n) {
        int r = 0;
        for (int l = 0, m = 0; int x: n)
            x > m ? m = x, l = 1, r = 1 :
            x < m ? l = 0 : r = max(r, ++l);
        return r;
    }



// 36ms
    def longestSubarray(self, n: List[int]) -> int:
        m=max(n);return max(sum(1for _ in g) for x, g in groupby(n) if x==m)


29.07.2025

2411. Smallest Subarrays With Maximum Bitwise OR medium blog post substack youtube https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1064

Problem TLDR

Shortest max OR i.. subarrays #medium #two_pointers

Intuition

Go backwards solutions:

  1. Use bits frequency and two pointers: always expand, shrint while frequency is 2
  2. Use nearest bit occurence map, then total length is the max occurence pointer

Go forwards solution:

  • for each i go back and update answer[j–] while it is doing the update n[j] != n[j] n[i]

Approach

  • the bits frequency is the most template-like for two-pointers

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 72ms
    fun smallestSubarrays(n: IntArray): IntArray {
        val f = IntArray(32); val r = IntArray(n.size); var j = n.lastIndex
        for (i in n.lastIndex downTo 0) {
            for (b in 0..31) if (n[i] shr b and 1 > 0) ++f[b]
            while (i < j && (0..31).all { b -> f[b] > 1 || n[j] shr b and 1 < 1 }) {
                for (b in 0..31) if (n[j] shr b and 1 > 0) --f[b]
                j--
            }
            r[i] = j - i + 1
        }
        return r
    }



// 29ms
    fun smallestSubarrays(n: IntArray): IntArray {
        val j = IntArray(30); val r = IntArray(n.size)
        for (i in n.lastIndex downTo 0) {
            for (b in 0..29) if (n[i] shr b and 1 > 0) j[b] = i
            r[i] = max(1, j.max() - i + 1)
        }
        return r
    }



// 6ms
    fun smallestSubarrays(n: IntArray): IntArray {
        val r = IntArray(n.size) { 1 }
        for (i in n.indices) {
            var j = i - 1
            while (j >= 0 && n[j] != n[i] or n[j]) {
                n[j] = n[j] or n[i]
                r[j] = i - j-- + 1
            }
        }
        return r
    }



// 13ms
    pub fn smallest_subarrays(n: Vec<i32>) -> Vec<i32> {
        let (mut j, mut r) = ([0;30], vec![0; n.len()]);
        for i in (0..n.len()).rev() {
            for b in 0..30 { if n[i] >> b & 1 > 0 { j[b] = i } }
            r[i] = 1.max(1 + *j.iter().max().unwrap() as i32 - i as i32)
        } r
    }



// 11ms
    vector<int> smallestSubarrays(vector<int>& n) {
        int j[30]={}, m = 0, k; vector<int> r(size(n));
        for (int i = size(n) - 1; i >= 0; --i, m = 0) {
            for (int b = 0; b < 30; ++b) k = n[i] >> b & 1, m = max(m, j[b] = max(j[b] * (1 - k), i * k));
            r[i] = max(1, m - i + 1);
        } return r;
    }



// 588ms
    def smallestSubarrays(self, n: List[int]) -> List[int]:
        last = [0] * 30
        res = []
        for i in range(len(n) - 1, -1, -1):
            for b in range(30):
                if n[i] >> b & 1:
                    last[b] = i
            res.append(max(1, max(last) - i + 1))
        return res[::-1]


28.07.2025

2044. Count Number of Maximum Bitwise-OR Subsets medium blog post substack youtube https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1063

Problem TLDR

Subsequencies with max OR #medium #bits #backtrack

Intuition

Problem size is small - 16, traverse all subsequencies.

The dp solution: dp[or] - number of subsets, dp[x or_prev] += dp[or_prev]

Approach

  • 0..2^16 are all possible bitmasks
  • the brute-force is slower than backtracking, every time goes from start: n2^n vs 2^n
  • calculate max on the go

Complexity

  • Time complexity: \(O(n2^n)\)

  • Space complexity: \(O(1)\)

Code


// 69ms
    fun countMaxOrSubsets(n: IntArray, o: Int = n.reduce(Int::or)) =
        (0..(1 shl n.size)).count { m ->
            o == n.indices.fold(0) { r, t -> r or (n[t] * (m shr t and 1)) }
        }



// 53ms
    fun countMaxOrSubsets(n: IntArray): Int {
        var res = 0; var max = 0
        for (m in 0..(1 shl n.size)) {
            val v = n.indices.fold(0) { r, t -> r or (n[t] * (m shr t and 1)) }
            if (v > max) { max = v; res = 1 } else if (v == max) ++res
        }
        return res
    }



// 14ms
    pub fn count_max_or_subsets(n: Vec<i32>) -> i32 {
        let (mut r, mut o) = (0, 0);
        for m in 0..=1 << n.len() as i32 {
            let v = (0..n.len()).fold(0, |r, t| r | n[t] * (m >> t & 1));
            if v > o { o = v; r = 0 }; if v == o { r += 1 }
        } r
    }



// 86ms
    int countMaxOrSubsets(vector<int>& n) {
        int max = 0, dp[1<<17]={1};
        for (int x: n) {
            for (int i = max; i >= 0; --i) dp[i | x] += dp[i];
            max |= x;
        } return dp[max];
    }



// 14ms
 def countMaxOrSubsets(self, n: List[int]) -> int:
        return (f:=cache(lambda i,v,o=reduce(or_,n):n[i:] and f(i+1,v)+f(i+1,v|n[i]) or v==o))(0,0)



27.07.2025

2210. Count Hills and Valleys in an Array easy blog post substack youtube https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1062

Problem TLDR

Count hills and valleys #easy

Intuition

We have to remove duplications.

Clever ways to look at the problem:

  • dedup
  • count slopes instead: up, down, up, down…
  • compare only hills or valleys values

Approach

  • duplicates are the corner case, failed the same way 1 year ago
  • each language opens a new angle of implementation, try many

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 16ms
    fun countHillValley(n: IntArray) =
        (1..<n.lastIndex).count { i -> 
            val a = n[0]; val b = n[i]; val c = n[i + 1]
            (a > b && b < c || a < b && b > c).also { if (it) n[0] = b }
        }



// 11ms
    fun countHillValley(n: IntArray): Int {
        var p = 0
        return n.filter { x -> x != p.also { p = x } }
                .windowed(3)
                .count { (a, b, c) -> (a > b) == (b < c) }
    }



// 1ms
    fun countHillValley(n: IntArray): Int {
        var p = n[0]; var s = 0
        return max(0, n.count { x -> 
            val cs = x.compareTo(p)
            cs != 0 && cs != s.also { s = cs; p = x }} - 1)
    }



// 0ms
    pub fn count_hill_valley(mut n: Vec<i32>) -> i32 {
        n.dedup();
        n.windows(3).filter(|w| (w[0] > w[1]) == (w[1] < w[2])).count() as _
    }



// 0ms
    pub fn count_hill_valley(mut n: Vec<i32>) -> i32 {
        n.iter().dedup().tuple_windows::<(_,_,_)>()
        .filter(|(a, b, c)| (a > b) == (b < c)).count() as _
    }



// 0ms
    int countHillValley(vector<int>& n) {
        int r = 0, p = n[0], s = 0;
        for (int x: n) {
            int cs = x > p ? 1 : x < p ? -1 : 0;
            if (cs) r += cs != s, s = cs; p = x;
        } return max(0, r - 1);
    }



// 0ms
    def countHillValley(self, n: List[int]) -> int:
        d = [x for x,_ in groupby(n)]
        return sum((a > b) == (b < c) for a, b, c in zip(d, d[1:], d[2:]))


26.07.2025

3480. Maximize Subarrays After Removing One Conflicting Pair hard blog post substack youtube https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1061

Problem TLDR

Max subarrays count without excluded pairs-1 #hard #greedy #line_sweep

Intuition

Didn’t solved.

    // 1 2 3 4
    // a     b
    //   a b

    // 1 2 3 4 5
    // a b
    //   a     b
    //     a   b

    // subproblem: nuber of subarrays with a and b separated
    // 1 2 3 4 5 6 7 8 9
    //     a     b
    //
    // for a: can't go past b, so it is number subarrays in 1..5 1..b-1
    // 1 2 3 4 5, 12 23 34 45, 123 234 345, 1234 2345, 12345
    // 5 + 4 + 3 + 2 + 1 = 5*(5 + 1)/2=15
    // 
    // for b: can't go before a, 4..9  a+1..n, 6*7/2=21
    // 
    // overlap: 4 5, 45 = b-a-1 = 2 * 3 /2 = 3
    //
    // subarrays 15+21-3=33  (b-1)*b/2 + (n-a)*(n-a+1)/2 - (b-a-1)*(b-a)/2
    //                        n^2/2-na+n/2-a+ab
    //
    // reverse the problem: number of subarrays including a and b
    // f(a) + f(n-b)
    // all is f(n)

    // now what if we have two pairs?
    // 1 2 3 4 5 6 7 8 9
    //       a       b    
    //   a       b
    // . . . . .            valid range
    //         . . . . .    valid range
    //       a   b          is the pair intersection result (28 minute)
    //
    // what if pairs are not intersecting
    // 1 2 3 4 5 6 7 8 9
    //   a   b   
    //           a   b
    // . . .              valid
    //             . . .  valid
    //     . . . . .      valid
    //        
    // more complex
    // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
    //   a     b  
    //     a       b
    //                   a       b
    //                       a       b
    //                                     a     b
    //                                                 a     b
    // . . . .
    //     . . . .
    //       . . . . . . . . . .
    // ..and so on, i use the hint at (36 minute)
    // then i gave up and look for solution https://leetcode.com/problems/maximize-subarrays-after-removing-one-conflicting-pair/solutions/6527930/intuitive-solution-with-sorting-visually-explained/
    // so, initial idea to sort was right
    // then, how to scan and compute?
    // we look for intervals between prev_max_a..max_a and tail after current b
    //  12345678901234567890123
    //  a      b              n
    //      a      b          n
    //          a       b     n
    //  .      ................
    //  .....      ............ c += (max1-max2)*tail = (5-1)*(23-8+1)
    //      .....       .......
    // overlapping case:
    //      a  b
    //  a          b
    //  .....  ................
    //   ....      ............
    // total excluded is sum(max(a) * b_tail)
    // current excluded is sum_overlaping(a1-a2) * b_tail 
    // we adding back maximum excluded value (while keeping track of overlaps)

Approach

  • the overlapping part is the hardest to understand

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(1)\)

Code


// 450ms
    fun maxSubarrays(n: Int, p: Array<IntArray>): Long {
        for (p in p) if (p[0] > p[1]) p[0] = p[1].also { p[1] = p[0] }
        Arrays.sort(p, compareBy{ it[1] })
        var max1 = 0; var max2 = 0; var c = 0L; var maxc = 0L; var exc = 0L
        for (i in p.indices) {
            val (a, b) = p[i]; var tail = (if (i < p.size - 1) p[i + 1][1] else n + 1) - b
            if (a > max1) { max2 = max1; max1 = a; c = 0 } else max2 = max(max2, a)
            c += 1L * (max1 - max2) * tail
            exc += 1L * max1 * tail
            maxc = max(maxc, c)
        }
        return 1L * n * (n + 1) / 2 - exc + maxc
    }


25.07.2025

3487. Maximum Unique Subarray Sum After Deletion easy blog post substack youtube https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1060

Problem TLDR

Max non-empty uniq subsequence sum #easy

Intuition

Remove all negatives, dedup all positives, then sum.

Approach

  • careful with non-empty, should take 1 negative

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 23ms
    fun maxSum(n: IntArray) =
        n.max().takeIf { it < 0 } ?: 
        n.filter { it > 0 }.distinct().sum()



// 12ms
    fun maxSum(n: IntArray): Int {
        val f = IntArray(101)
        for (x in n) if (x >= 0) f[x] = x
        return n.max().takeIf { it < 0 } ?: f.sum()
    }



// 0ms
    pub fn max_sum(mut n: Vec<i32>) -> i32 {
        n.sort_unstable(); n.dedup();
        if n[n.len() - 1] < 0 { n[n.len() - 1] } 
        else { n.retain(|&x| x > 0); n.into_iter().sum() }
    }



// 1ms
    int maxSum(vector<int>& n) {
        int f[101]={}, m = n[0], s = 0;
        for (int x: n) m = max(m, x), s -= x < 0 ? 0 : (f[x] - (f[x] = x));
        return m < 0 ? m : s;
    }


24.07.2025

2322. Minimum Score After Removals on a Tree hard blog post substack youtube https://dmitrysamoylenko.com/2023/07/14/leetcode_daily.html 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1059

Problem TLDR

Min(max_group_xor - min_group_xor) by removing 2 edges from tree #hard #uf

Intuition

Didn’t solved.


   // xor(all) = X
    // xor(B, C) = X xor A
    // A = B xor C xor X
    // min = max xor C xor X
    // score = max - min = max - (max xor C xor X)
    // I need max score
    // score = A - A^C^X, A is max
    // X = A^B^C
    //     A is max
    //       B is min
    //         C is X^max^min
    // A - B = 
    // 
    // score^X = max^X - max^C
    //
    // going circles with xor arithmetics
    //
    // xor can decrease: 1 xor 1 = 0
    // xor can increase: 0 xor 1 = 1
    // 101^10 - 101^01 = 110 - 100 = 100
    // ok forget about math, what about tree walk
    // how to disconnect edge?
    // 25 minutes, use hint
    // first split a single edge
    // A vs BC
    // then choose the best second split point (how? 32 minute)
    // if A is min, then look for max in BC
    // if A is max, then look for min in BC
    // if A is neutral - then it is irrelevant, we will traverse all possible A anyway
    // ...............
    // ..........A____B
    // _____B.........A
    // for each edge we have a pair A-BC
    //                              max(max_A) - min(min_A) ? not that simple
    // 50 minute gave up, gosh I even forgot we have to find the MINIMUM (max-min)


My intuition direction was on Union-Find, but I had a hard time computing the xor cases.

Some stolen solution intuition:

  • precompute Union-Find results for all single edges: group roots, and two values for (xorA, xorBC)
  • then again iterate i, j and calculate 3 xors based on logic

The tricky part, logic and I still have a hard time to really get it.

  • on value we always take, let it be c2 = A
  • we have 4 nodes of 2 disconnected edges (a-/-b), (c-/-d)
  • then the part I don’t fully get, look at the source (https://leetcode.com/problems/minimum-score-after-removals-on-a-tree/solutions/2199132/union-find-c-o-n-2-time-o-n-2-space-code-explanation/)

Approach

  • don’t spend too much time hitting a head against the wall, but at least read, something will be absorbed anyway

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n^2)\)

Code


// 269ms
    fun minimumScore(n: IntArray, es: Array<IntArray>): Int {
        val us = Array(n.size) { IntArray(n.size) { it }}; val xs = Array(n.size) { IntArray(2) }
        operator fun IntArray.div(x: Int): Int = if (get(x) == x) x else (this/get(x)).also { set(x, it) }
        for (a in es.indices) {
            val u = us[a]; val r = IntArray(n.size) { n[it] }
            for (i in es.indices) if (i != a) {
                val a = u/es[i][0]; val b = u/es[i][1]
                if (a != b) { u[a] = b; r[b] = r[b] xor r[a]; r[a] = 0 }
            }
            xs[a][0] = r[u/es[a][0]]; xs[a][1] = r[u/es[a][1]]; us[a] = u 
        }
        var res = Int.MAX_VALUE
        for (i in es.indices) for (j in es.indices) if (i != j) {
            val (a, b) = es[i]; var (c, d) = es[j]; var c1 = 0; var c2 = 0; var c3 = 0
            if (us[i]/a == us[i]/c) {
                c1 = if (us[j]/a == us[j]/c) xs[j][1] else xs[j][0]
                c2 = xs[i][1]; c3 = c1 xor xs[i][0]
            } else {
                c1 = if (us[j]/b == us[j]/c) xs[j][1] else xs[j][0]
                c2 = xs[i][0]; c3 = c1 xor xs[i][1]
            }
            res = min(res, maxOf(c1, c2, c3) - minOf(c1, c2, c3))
        }
        return res
    }


23.07.2025

1717. Maximum Score From Removing Substrings medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1058

Problem TLDR

Max removals ab=x, ba=y #medium #stack

Intuition

Problem is symmetric, reverse for x less than y. Scan, put ‘a’ to stack, pop when meet ‘b’, mark removed. Then scan again, but for ‘ba’.

Notice, there are islands of ‘b’’s and ‘a’’s: we can do a single scan, and check ‘ba’ when we finish the curren island.

Now, the crazy part: notice how the patterns of ‘a’s and ‘b’s are always the same in the stack bbbaaa, so we actually don’t have to use stack, just count.

Approach

  • the finish line can be s + '.' or just do one extra calculation at the end

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 75ms
    fun maximumGain(s: String, x: Int, y: Int): Int {
        var r = 0; val st = Stack<Char>(); val st2 = Stack<Char>()
        val (a, b) = if (x < y) 'b' to 'a' else 'a' to 'b'
        val (x, y) = max(x, y) to min(x, y)
        for (c in s + '.')
            if (c == a) st += a
            else if (c == b) {
                if (st.size > 0 && st.peek() == a) { st.pop(); r += x } else st += b
            } else {
                for (c in st)
                    if (c == b) st2 += c
                    else if (c == a) {
                        if (st2.size > 0 && st2.peek() == b) { st2.pop(); r += y }
                    }
                st.clear(); st2.clear()
            }
        return r
    }


// 31ms
    fun maximumGain(s: String, x: Int, y: Int): Int {
        if (x < y) return maximumGain(s.reversed(), y, x)
        var a = 0; var b = 0; var r = 0
        for (c in s)
            if (c == 'a') ++a
            else if (c == 'b') if (a > 0) { --a; r += x } else ++b
            else { r += y * min(a, b); a = 0; b = 0 } 
        return r + y * min(a, b)
    }



// 4ms
    pub fn maximum_gain(mut s: String, mut x: i32, mut y: i32) -> i32 {
        let s: Vec<_> = if x < y { s.bytes().rev().collect() } else { s.into_bytes() };
        let (mut a, mut b, mut r) = (0, 0, 0); (x, y) = (x.max(y), x.min(y));
        for c in s.into_iter() {
            if c == b'a' { a += 1 }
            else if c == b'b' { if a > 0 { a -= 1; r += x } else { b += 1 } }
            else { r += y * a.min(b); a = 0; b = 0 }
        } r + y * a.min(b)
    }




// 4ms
    int maximumGain(string s, int x, int y) {
        if (x < y) reverse(begin(s), end(s)), swap(x, y);
        int a = 0, b = 0, r = 0;
        for (char c : s)
            if (c == 'a') a++;
            else if (c == 'b') a ? (a--, r += x) : b++;
            else r += y * min(a, b), a = b = 0;
        return r + y * min(a, b);
    }


22.07.2025

1695. Maximum Erasure Value medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1057

Problem TLDR

Max unique subarray sum #medium #sliding_window

Intuition

Sliding window:

  • expand every time
  • shrink until condition

Approach

  • use array for frequency map
  • current index is irrelevant, just decrease the frequency

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 33ms
    fun maximumUniqueSubarray(n: IntArray): Int {
        val f = IntArray(10001); var j = 0; var s = 0
        return n.maxOf { x -> ++f[x]; s += x
            while (f[x] > 1) { s -= n[j]; --f[n[j++]] }; s
        }
    }



// 8ms
    fun maximumUniqueSubarray(n: IntArray): Int {
        val f = IntArray(10001); var j = 0; var r = 0; var s = 0
        for (x in n) {
            ++f[x]; s += x
            while (f[x] > 1) { s -= n[j]; --f[n[j++]] }
            r = max(r, s)
        }
        return r
    }



// 0ms
    pub fn maximum_unique_subarray(n: Vec<i32>) -> i32 {
        let (mut f, mut j, mut s) = ([0; 10001], 0, 0);
        n.iter().map(|&x| {
            f[x as usize] += 1; s += x;
            while f[x as usize] > 1 { s -= n[j]; f[n[j] as usize ] -= 1; j += 1 }; s
        }).max().unwrap()
    }




// 3ms
    int maximumUniqueSubarray(vector<int>& n) {
        int f[10001] = {}, j = 0, r = 0, s = 0;
        for (auto x: n) {
            ++f[x]; s += x;
            while (f[x] > 1) s -= n[j], --f[n[j++]];
            r = max(r, s);
        } return r;
    }


21.07.2025

1957. Delete Characters to Make Fancy String easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1056

Problem TLDR

No three chars repeats #easy

Intuition

Scan, count, filter.

Approach

  • make separate decisions for counter and for appending
  • there are Regex way, chunks way, dedup way
  • leetcode has itertools available

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 193ms
    fun makeFancyString(s: String) = s
    .replace(Regex("(.)\\1{2,}"), "$1$1")



// 24ms
    fun makeFancyString(s: String) = s
    .filterIndexed { i, c -> i < 2 || s[i - 2] != c || s[i - 1] != c }



// 17ms
    fun makeFancyString(s: String) = buildString {
        var p = '.'; var pc = 0
        for (c in s) {
            if (c == p) ++pc else pc = 1
            if (pc < 3) append(c)
            p = c
        }
    }



// 53ms
    pub fn make_fancy_string(mut s: String) -> String {
        s.chars().dedup_with_count().into_iter()
        .map(|(cnt, c)| c.to_string().repeat(2.min(cnt))).collect()
    }



// 11ms
    pub fn make_fancy_string(s: String) -> String {
        String::from_utf8_lossy(
        &s.bytes().enumerate().filter(|&(i, b)| 
        i < 2 || s.as_bytes()[i - 2] != b || s.as_bytes()[i - 1] != b)
        .map(|(i, b)| b).collect::<Vec<_>>()).into()
    }



// 5ms
    pub fn make_fancy_string(mut s: String) -> String {
        let (mut a, mut b) = ('.', '.');
        s.retain(|c| { let r = a != c || b != c; a = b; b = c; r }); s
    }




// 2826ms
    string makeFancyString(string s) {
        return regex_replace(s, regex("(.)\\1\\1+"), "$1$1");
    }


20.07.2025

1948. Delete Duplicate Folders in System hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1055

Problem TLDR

Remove duplicate folder trees #hard #trie

Intuition

    // a
    // c
    // d
    // a/b
    // c/b
    // d/a
    // go backwards: corner case is collision `a with d/a`
    // first avoid parents: a vs a/b, we should skip a, for same startswith, pick longest
    // too complex, maybe should go forward with trie

The hardness is the correct implementation:

  • build the tree keys
  • count them
  • remove all with count > 1

Approach

  • we can do two DFS or a single DFS but with worse time complexity to merge indices

Complexity

  • Time complexity: \(O(nlogn)\), worst case is n^2 for long graph nodes

  • Space complexity: \(O(n)\)

Code


// 189ms
    fun deleteDuplicateFolder(p: List<List<String>>) = buildList<List<String>> {
        class T(val i: HashSet<Int> = HashSet()): TreeMap<String, T>()
        val r = T(); val m = HashMap<String, T>()
        for (j in p.indices) p[j].fold(r) { t, f -> t.getOrPut(f, ::T).also { it.i += j }}
        fun dfs(t: T): String = t.map { (f, nt) -> "$f[${ dfs(nt) }]" }.toString().also { k ->
            if (t !== r) for (nt in t.values) t.i += nt.i
            if (t.size > 0 && k in m) r.i += m[k]!!.i + t.i else m[k] = t
        }
        dfs(r); for (i in p.indices) if (i !in r.i) add(p[i])
    }


19.07.2025

1233. Remove Sub-Folders from the Filesystem hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1054

Problem TLDR

Fold folders #medium

Intuition

Naive way: make set of folders, check each folder sub-paths to be in this set. Clever way: sort folders, naturally the previous would be the parent if match.

Approach

  • Trie gives a worse performance (HashMap based) 27ms vs 5ms

Complexity

  • Time complexity: \(O(nlogn)\) or O(nl)

  • Space complexity: \(O(n)\)

Code


// 116ms
    fun removeSubfolders(f: Array<String>) = buildList<String> {
        val s = f.toSet()
        for (f in f) {
            var pref = ""; var skip = false
            for (x in f.split("/")) {
                pref += "$x"
                if (pref != f && pref in s) { skip = true; break }
                pref += "/"
            }
            if (!skip) add(f)
        }
    }


// 78ms
    fun removeSubfolders(f: Array<String>) = buildList<String> {
        f.sort()
        for (f in f) if (size < 1 || !f.startsWith("${last()}/")) this += f
    }



// 25ms
    pub fn remove_subfolders(mut f: Vec<String>) -> Vec<String> {
        #[derive(Default)] struct T(bool, HashMap<u8, T>);
        let (mut tr, mut r) = (T::default(), vec![]); f.sort_unstable();
        'o: for w in f { let mut t = &mut tr;
            for b in w.bytes().chain(once(b'/')) {
                t = t.1.entry(b).or_default(); if t.0 { continue 'o }
            }
            t.0 = true; r.push(w)
        } r
    }



// 5ms
    pub fn remove_subfolders(mut f: Vec<String>) -> Vec<String> {
        let mut r: Vec<String> = vec![]; f.sort_unstable();
        for f in f { 
            if r.last().map_or(true, |l| f.len() < l.len() || 
                &f[..l.len()] != l || f.as_bytes()[l.len()] != b'/') { r.push(f) }
        } r
    }



// 59ms
    vector<string> removeSubfolders(vector<string>& f) {
        sort(begin(f), end(f)); vector<string> r;
        for (auto f: f) if (!size(r) || f.find(r.back() + "/")) r.push_back(f);
        return r;
    }


18.07.2025

2163. Minimum Difference in Sums After Removal of Elements hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1053

Problem TLDR

Min first half - second half after removing n/3 #hard #heap

Intuition

Used the hint:

  • consider each index as partition point, min sum before - max sum after

    // 795813
    // remove big left, small right
    // order inside parts doesn't matter
    // left = 795     right = 813
    // but if removed parts diff > 2 number migrates
    //          5             813
    //                 8 goes left
    //          58            13

    // 991199
    // 991   199    d =9+9+1 - 1 +9 +9 = 19 - 19 = 0
    // 9 91  199    d = 9+1 - 1+9+9 = 10-19 = -9
    // 99 1  199    d = 1 - 1+9+9 = -18, but 1 goes left
    //                  1+1 - 9+9 = -16
    // 
    //   11 99
    //            ok but how to shift mid if it was removed? (21 minute)
    // used hints: find min/max n-sum for prefix/suffix for every i
   

My own idea was to maintain two heaps and poll elements from them, but I was stuck with how to balance them correctly.

Approach

  • carefull with off-by-ones, sums should not overlap

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n)\), or O(n / 3)

Code


// 109ms
    fun minimumDifference(n: IntArray): Long {
        val q = PriorityQueue<Int>(); val suf = LongArray(n.size)
        var s = 0L; val k = n.size / 3
        for (i in n.lastIndex downTo k) {
            q += n[i]; s += n[i]; if (q.size > k) s -= q.poll()
            suf[i] = s
        }
        q.clear(); var d = s; s = 0
        for (i in 0..<2 * k) {
            q += -n[i]; s += n[i]; if (q.size > k) s += q.poll()
            if (i >= k - 1) d = min(d, s - suf[i + 1])
        }
        return d
    }



// 47ms
    pub fn minimum_difference(n: Vec<i32>) -> i64 {
        let (mut q, k) = (BinaryHeap::new(), n.len() / 3);
        let (mut suf, mut s, mut j) = (vec![0; k + 1], 0i64, 0);
        for i in (k..n.len()).rev() { let n = n[i] as i64;
            q.push(-n); s += n; if q.len() > k { s += q.pop().unwrap(); }
            if q.len() == k { suf[j] = s; j += 1 }
        }
        q.clear(); let mut d = s; s = 0;
        for i in 0..2 * k { let n = n[i] as i64;
            q.push(n); s += n; if q.len() > k { s -= q.pop().unwrap(); }
            if i >= k - 1 { j -= 1; d = d.min(s - suf[j]) }
        } d
    }



// 131ms
    long long minimumDifference(const vector<int>& n) {
        int k = n.size() / 3, j = 0; long long s = 0;
        priority_queue<int> q; vector<long long> suf(k + 1);
        for (int i = n.size() - 1; i >= k; --i) {
            s += n[i]; q.push(-n[i]);
            if (q.size() > k) s += q.top(), q.pop();
            if (q.size() == k) suf[j++] = s;
        }
        q = {}; long long d = s; s = 0;
        for (int i = 0; i < 2 * k; ++i) {
            s += n[i]; q.push(n[i]);
            if (q.size() > k) s -= q.top(), q.pop();
            if (i >= k - 1) d = min(d, s - suf[--j]);
        }
        return d;
    }


17.07.2025

3202. Find the Maximum Length of Valid Subsequence II medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1052

Problem TLDR

Longest same-pair-k-parity subsequence #medium #dp

Intuition

Didn’t solved.

What went right:

  • arithmetics: (a+b)%k == (b + c)%k, a%k == c%k

What went wrong:

  • spent some brainpower on dfs implementations (frist 15 minutes)
  • the way to update length: closes i got is ++len[v][other], should’ve been max(len[v][x%k], 1 + len[v][other]) (wasn’t able to comprehend how to peek max and update current simulteneously)

Mostly irrelevant chain-of-thoughts:

    // abcd
    // (a+b)%k == (b+c)%k
    // (a%k + b%k)%k == (b%k + c%k)%k
    // 1 4 1 4      %3    always ababab pattern, or aaaa ?
    //             (1+4)%3=2
    //                4%3=1, 1%3=1
    //             meet 4, look for (0..k) - 4%k

    // (a + b) % k = c
    // a % k = (c - b%k + k) % k

    // 1 4 2 3 1 4    k=3
    // *
    //   *           4: 1-4  start sequence parity  (1+4)%k=5%3=2
    //         *     for p=2: 2 - 1%k = 1

    // 1 2 3 4 5     k=2
    //     *

Approach

  • no difference between iterations: x in n v in 0..<k or v in 0..<k x in n

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(k)\)

Code


// 92ms
    fun maximumLength(n: IntArray, k: Int): Int {
        val len = Array(k) { IntArray(k) }
        for (v in 0..<k) for (x in n)
            len[v][x % k] = max(len[v][x % k], 1 + len[v][(k + v - (x % k)) % k])
        return len.maxOf { it.max() }
    }



// 92ms
    fun maximumLength(n: IntArray, k: Int): Int {
        val len = Array(k) { IntArray(k) }
        for (x in n) for (v in 0..<k) 
            len[v][x % k] = max(len[v][x % k], 1 + len[v][(k + v - (x % k)) % k])
        return len.maxOf { it.max() }
    }



// 67ms
    pub fn maximum_length(n: Vec<i32>, k: i32) -> i32 {
        (0..k as usize).map(|v| {
            let k = k as usize; let mut len = vec![0; k];
            n.iter().map(|&x| { let x = x as usize;
                len[x % k] = len[x % k].max(1 + len[(k + v - x % k) % k]); len[x % k]
            }).max().unwrap() }).max().unwrap() as _
    }



// 55ms
    int maximumLength(vector<int>& n, int k) {
        int r = 0;
        for (int v = 0; v < k; ++v) for (int l[1000]={}; int x: n) 
            r = max(r, l[x%k] = max(l[x%k], 1 + l[(v - x%k + k) % k]));
        return r;
    }


16.07.2025

3201. Find the Maximum Length of Valid Subsequence I medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1051

Problem TLDR

Longest same-pair-parity subsequence #medium #greedy

Intuition

4 cases to consider, take greedily

    // 00000   -- valid (0+0=0)
    // 1111111 -- valid (1+1=0)
    // 010101  -- valid (1+0=1)
    // 101010 -- valid (1+0=1)
    // 0001010 -- invalid
    // 0001111 -- invalid

Approach

  • write CPU-branchless with bit tricks
  • use a single array for all 4 cases
  • two alterating cases 0-1 and 1-0 collapses into single with initial condition of first element

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 14ms
    fun maximumLength(n: IntArray): Int {
        val c = IntArray(4)
        for (x in n) { ++c[x % 2]; c[2 + x % 2] = 1 + c[3 - x % 2] }
        return c.max()
    }



// 8ms
    fun maximumLength(n: IntArray): Int {
        var zo = 0; var oz = 0
        var zonext = 0; var oznext = 1
        var allZeros = 0; var allOnes = 0
        for (x in n) {
            allZeros += 1 - (x % 2)
            allOnes += x % 2
            if (x % 2 == zonext) { ++zo; zonext = 1 - zonext } 
            if (x % 2 == oznext) { ++oz; oznext = 1 - oznext } 
        }
        return maxOf(allZeros, allOnes, zo, oz)
    }


// 2ms
    fun maximumLength(n: IntArray): Int {
        var az = 0; var ao = 0; var c = 0; var e = n[0] and 1
        for (x in n) {
            val p = x and 1; az += 1 - p; ao += p
            c += 1 - p xor e; e = e xor (1 - p xor e)
        }
        return max(max(az, ao), c)
    }



// 0ms
    pub fn maximum_length(n: Vec<i32>) -> i32 {
        let (mut a, mut b, mut c, mut e) = (0, 0, 0, n[0] & 1);
        for x in n {
            let p = x & 1; a += 1 - p; b += p;
            c += 1 - p ^ e; e = e ^ (1 - p ^ e);
        } a.max(b).max(c)
    }



// 0ms
    int maximumLength(vector<int>& n) {
        int a = 0, b = 0, c = 0, e = n[0] & 1;
        for (int x: n) a += 1 - x&1, b += x&1, c += (x&1) == e, e = e ^ ((x&1) == e);
        return max(max(a, b), c);
    }


14.07.2025

1290. Convert Binary Number in a Linked List to Integer easy blog post substack youtube

1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1049

Problem TLDR

Binary linked list to decimal #easy #linkedlist

Intuition

x = x * 2 + value

  • use recursion
  • use loop
  • use values to hold some data

Approach

  • try to write it in all difference ways

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 128ms
    fun ListNode?.str(): String = if (this == null) ""
        else "" + `val` + next.str()
    fun getDecimalValue(head: ListNode?) = head.str().toInt(2)



// 0ms
    fun getDecimalValue(head: ListNode?): Int = 
        if (head?.next == null) head!!.`val` else
        getDecimalValue(head.next!!.apply { `val` += 2 * head.`val`})



// 0ms
    fun getDecimalValue(head: ListNode?, r: Int = 0): Int = 
        head?.run { getDecimalValue(next, r * 2 + `val`) } ?: r



// 0ms
    fun getDecimalValue(head: ListNode?): Int {
        var x = head; var y = 0
        while (x != null) { y = y * 2 + x.`val`; x = x.next }
        return y
    }



// 0ms
    var max = 1
    fun getDecimalValue(head: ListNode?): Int = head?.run {
        val curr = max++
        getDecimalValue(next) + `val` * (1 shl (max - curr - 1))
    } ?: 0



// 0ms
    fun getDecimalValue(head: ListNode?): Int = head?.run {
        val curr = `val` / 2
        next?.`val` += (curr + 1) * 2
        val tail = getDecimalValue(next)
        val max = max(curr, (next?.`val` ?: 0) / 2)
        `val` = `val` % 2 + max * 2
        (`val` % 2) * (1 shl (max - curr)) + tail
    } ?: 0



// 0ms
    pub fn get_decimal_value(mut head: Option<Box<ListNode>>) -> i32 {
        let mut r = 0;
        while let Some(b) = head {
            r = r * 2 + b.val;
            head = b.next
        } r
    }


// 0ms
    int getDecimalValue(ListNode* head) {
        for (;; head = head->next)
            if (!head->next) return head->val;
            else head->next->val += head->val * 2;
    }


13.07.2025

2410. Maximum Matching of Players With Trainers medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1048

Problem TLDR

Count trainers for players #medium #sort

Intuition

Skip not able trainers, always take smallest player and trainer.

Approach

  • we can iterate over trainers or over players
  • Rust into_iter is slower than iter 7ms vs 3ms
  • Rust iter is slower than for 3ms vs 0ms
  • have to sort both, 10^9 range not suitable for counting sort linear solution
  • players counter and result counter is the same variable

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(1)\)

Code


// 49ms
    fun matchPlayersAndTrainers(ps: IntArray, ts: IntArray): Int {
        ps.sort(); ts.sort(); var t = 0; var cnt = 0
        return ps.count { p ->
            while (t < ts.size && ts[t] < p) ++t
            t++ < ts.size
        }
    }



// 44ms
    fun matchPlayersAndTrainers(ps: IntArray, ts: IntArray): Int {
        ps.sort(); ts.sort(); var p = 0
        for (t in ts) {
            if (t < ps[p]) continue
            if (++p == ps.size) break
        }
        return p
    }



// 3ms
    pub fn match_players_and_trainers(mut ps: Vec<i32>, mut ts: Vec<i32>) -> i32 {
        ps.sort_unstable(); ts.sort_unstable(); let mut t = 0;
        ps.iter().take_while(|&&p| {
            while t < ts.len() && ts[t] < p { t += 1 }
            t += 1; t <= ts.len()
        }).count() as _
    }



// 0ms
    pub fn match_players_and_trainers(mut ps: Vec<i32>, mut ts: Vec<i32>) -> i32 {
        ps.sort_unstable(); ts.sort_unstable(); let mut p = 0;
        for t in ts {
            if t < ps[p] { continue }; p += 1;
            if p == ps.len() { break }
        } p as _
    }



// 32ms
    int matchPlayersAndTrainers(vector<int>& ps, vector<int>& ts) {
        sort(begin(ps), end(ps)); sort(begin(ts), end(ts));
        int p = 0;
        for (int t = 0; t < size(ts) && p < size(ps); ++t) p += ts[t] >= ps[p];
        return p;
    }


12.07.2025

1900. The Earliest and Latest Rounds Where Players Compete hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1047

Problem TLDR

First and last round Alice fight Bob #hard #simulation

Intuition

Didn’t solved (have a hard time to understand the simulation rules)

    // 7 minutes read description, didn't understood
    // let's try simulation
    // round 1
    // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
    // *              s               w   choose 11win, 6middle go 2nd rnd
    // 2, 3, 4, 5, 7, 8, 9, 10
    // w                     *            2 always win
    // 2, 3, 4, 5, 7, 8, 9
    // w        s        *                2 always win, 5 middle go 2nd rnd
    // 2, 3, 4, 7, 8                      
    // w     s     *                      2 win, 4 go 2nd
    // 2 3 7              
    // w s *                              2 win, 3 go 2nd
    // 2                                  2 go 2nd

    // round 2
    // 6 11 2 5 4 3
    // 2 3 4 5 6 11
    // let's start with simulation 28^28
    // how to choose the best?
    // maybe BFS (idea on 51 minute)
    // 1:38 wrong answer for case
    // 1 2 3 4   (2,3)            3,3  vs 1,1
    // w     -
    //   2 3
    //     w
    //   2 3        wrong simulation code
    // is winnder goes fight again? (question at 1:43 :)  )

    // 1, 2, 3, 4, 5, 6  7, 8, 9, 10, 11
    // -              s               w
    //    2, 3, 4, 5,    7, 8, 9, 10    
    //    w                       -
    //       3, 4, 5,    7, 8, 9        
    //       w                 -
    //          4, 5,    7, 8           
    //          w           -
    //             5,    7              
    //             w     
    //             5,    7              

    // 1 2 3 4    (2,3)
    // w     -
    ```

What went wrong: the description comprehension. We stop when first fight with second. The winners are irrelevant. My mistake was leaving the winner.

#### Approach

* sometimes the description is the hardest part

#### Complexity

- Time complexity:
$$O(2^n)$$

- Space complexity:
$$O(n)$$

#### Code

```kotlin

// 343ms
    fun earliestAndLatest(n: Int, fp: Int, sp: Int): IntArray {
        var min = Int.MAX_VALUE; var max = 1; val fp = fp - 1; val sp = sp - 1
        fun dfs(mask: Int, round: Int, i: Int, j: Int) {
            if (i >= j) dfs(mask, round + 1, 0, 27) else
            if ((mask and (1 shl i)) == 0) dfs(mask, round, i + 1, j) else
            if ((mask and (1 shl j)) == 0) dfs(mask, round, i, j - 1) else
            if (i == fp && j == sp) { min = min(min, round); max = max(max, round) } else {
                if (i != fp && i != sp) dfs(mask xor (1 shl i), round, i + 1, j - 1)
                if (j != fp && j != sp) dfs(mask xor (1 shl j), round, i + 1, j - 1)
            }
        }
        dfs((1 shl n) - 1, 1, 0, 27)
        return intArrayOf(min, max)
    }


11.07.2025

2402. Meeting Rooms III hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1046

Problem TLDR

Most frequent meeting room #hard #heap

Intuition

The corner case is int overflow. Write the simulation:

  • peek free room, or shift time to the first ending meeting
  • purge all meetings until the time

Approach

  • to remove the time variable, sort by the room number
  • to use just a single queue, do the rotation: poll, shift time, push back; first free room is a queue size (interesting fact)
  • to do without a queue: track ending times for each [100] room, peek the lowest in a linear time

Complexity

  • Time complexity: \(O(nlog(n))\) or mnlog(n)

  • Space complexity: \(O(n)\)

Code


// 235ms
    fun mostBooked(n: Int, ms: Array<IntArray>): Int {
        ms.sortBy { it[0] }
        val freeRooms = PriorityQueue<Int>()
        val busyRooms = PriorityQueue<Pair<Long, Int>>(compareBy({it.first},{it.second}))
        for (r in 0..<n) freeRooms += r
        val freq = IntArray(n)
        for ((s, e) in ms) {
            while (busyRooms.size > 0 && busyRooms.peek().first <= s)
                freeRooms += busyRooms.poll().second
            if (freeRooms.size > 0) {
                val room = freeRooms.poll()
                ++freq[room]
                busyRooms += 1L * e to room 
            } else {
                val (t, room) = busyRooms.poll()
                ++freq[room]
                busyRooms += (t + e - s) to room 
            }
        }
        return freq.indexOf(freq.max())
    }



// 182ms
    fun mostBooked(n: Int, ms: Array<IntArray>): Int {
        ms.sortBy { it[0] }
        val q = PriorityQueue<Pair<Long, Int>>(compareBy({it.first},{it.second}))
        val freq = IntArray(n)
        for ((s, e) in ms)
            if (q.size > 0 && q.peek().first <= s || q.size >= n) {
                while (q.peek().first < s) q += 1L * s to q.poll().second
                val (end, room) = q.poll()
                ++freq[room]
                q += (1L * e + max(0, end - s)) to room
            } else {
                ++freq[q.size]
                q += 1L * e to q.size
            }
        return freq.indexOf(freq.max())
    }



// 181ms
    fun mostBooked(n: Int, ms: Array<IntArray>): Int {
        ms.sortBy { it[0] }; val freq = IntArray(n); val t = LongArray(n)
        for ((s, e) in ms) {
            val room = (0..<n).firstOrNull { t[it] <= s } ?: t.indexOf(t.min())
            t[room] = 1L * e + max(0, t[room] - s)
            ++freq[room]
        }
        return freq.indexOf(freq.max())
    }



// 173ms
    fun mostBooked(n: Int, ms: Array<IntArray>): Int {
        ms.sortBy { it[0] }
        val freeRooms = PriorityQueue<Int>()
        val busyRooms = PriorityQueue<Pair<Long, Int>>(compareBy{it.first})
        for (r in 0..<n) freeRooms += r
        val freq = IntArray(n); var t = 0L
        for ((s, e) in ms) {
            t = max(t, 1L * s)
            while (busyRooms.size > 0 && busyRooms.peek().first <= t)
                freeRooms += busyRooms.poll().second
            if (freeRooms.size < 1) {
                t = busyRooms.peek().first
                while (busyRooms.size > 0 && busyRooms.peek().first <= t)
                    freeRooms += busyRooms.poll().second
            }
            val room = freeRooms.poll()
            ++freq[room]
            busyRooms += (1L*e + (t - s)) to room 
        }
        return freq.indexOf(freq.max())
    }



// 132ms
    fun mostBooked(n: Int, ms: Array<IntArray>): Int {
        ms.sortBy { it[0] }; val freq = IntArray(n); val t = LongArray(n)
        for ((s, e) in ms) {
            var min = Long.MAX_VALUE; var rmin = -1; var rs = -1
            for (r in 0..<n) {
                if (t[r] <= s) { rs = r; break }
                if (t[r] < min) { min = t[r]; rmin = r }
            }
            val room = max(rs, rmin)
            t[room] = 1L * e + max(0, t[room] - s)
            ++freq[room]
        }
        return freq.indexOf(freq.max())
    }



// 24ms
    pub fn most_booked(n: i32, mut ms: Vec<Vec<i32>>) -> i32 {
        ms.sort_unstable(); let n = n as usize;
        let (mut f, mut t, mut res) = (vec![0; n], vec![0; n], 0);
        for m in ms { let (s, e) = (m[0] as i64, m[1] as i64); 
            let (mut rmin, mut rs, mut m) = (-1, -1, i64::MAX);
            for r in 0..n { if t[r] <= s { rs = r as i32; break }; if t[r] < m { rmin = r as i32; m = t[r] }}
            let room = rmin.max(rs) as usize; t[room] = e + 0.max(t[room] - s); f[room] += 1;
            if f[room] > f[res] { res = room } else if f[room] == f[res] { res = res.min(room) }
        } 
        res as _
    }



// 63ms
int mostBooked(int n, std::vector<std::vector<int>>& ms) {
    sort(begin(ms), end(ms));
    long long t[100] = {}; int f[100] = {}, res = 0;
    for (auto& m : ms) {
        long long s = m[0], e = m[1], rs = -1, rmin = -1, mint = LONG_MAX;
        for (int r = 0; r < n; ++r)
            if (t[r] <= s) { rs = r; break; } 
            else if (t[r] < mint) rmin = r, mint = t[r];
        int room = max(rs, rmin);
        t[room] = 1LL * e + max(0LL, t[room] - s);
        if (++f[room] > f[res] || (f[room] == f[res] && room < res)) res = room;
    }
    return res;
}


10.07.2025

3440. Reschedule Meetings for Maximum Free Time II medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1045

Problem TLDR

Max free time after moving 1 event #medium #sorting

Intuition


    // 0  17..19  24..25   41
    //  17      5        16
    //      2       1
* look for all free windows
* look around each event 
* look if each event can fit into another window
* sort free windows
* track windows indices

Space optimization: do forward and backward pass to track the largest seen gap.

Approach

  • we can do forward & backward pass in a single loop

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\) or O(1)

Code


// 91ms
    fun maxFreeTime(evt: Int, st: IntArray, et: IntArray): Int {
        val free = IntArray(st.size)
        val gaps = Array(3) { 0 to 0 }; gaps[0] = st[0] to 0
        for (i in 0..<st.size) {
            val s = st[i]; val e = et[i]
            val prev = if (i == 0) 0 else et[i - 1]
            val before = s - prev
            val next = if (i < st.size - 1) st[i + 1] else evt
            val after = next - e
            free[i] = before + after
            val g = (0..2).minBy { gaps[it].first }
            if (gaps[g].first < after) gaps[g] = after to (i + 1)
        }
        var res = 0
        for (i in free.indices) {
            var fit = 0
            val curr = et[i] - st[i]
            for (g in 0..2) if (gaps[g].first >= curr && gaps[g].second !in i..i+1)
                fit = curr
            res = max(res, free[i] + fit)
        }
        return res
    }



// 7ms
    fun maxFreeTime(evt: Int, st: IntArray, et: IntArray): Int {
        var left = 0; var right = 0; var res = 0; var j = st.size - 1
        for (i in st.indices) {
            var before = st[i] - if (i == 0) 0 else et[i - 1]
            var after = (if (i < st.size - 1) st[i + 1] else evt) - et[i]
            res = max(res, before + after + if (et[i] - st[i] <= left) et[i] - st[i] else 0)
            left = max(left, before)
            before = (if (j == st.size - 1) evt else st[j + 1]) - et[j]
            after = st[j] - if (j > 0) et[j - 1] else 0
            res = max(res, before + after + if (et[j] - st[j] <= right) et[j] - st[j] else 0)
            right = max(right, before); j--
        }
        return res
    }



// 4ms
    pub fn max_free_time(evt: i32, st: Vec<i32>, et: Vec<i32>) -> i32 {
        let (mut left, mut right, mut res, mut j) = (0, 0, 0, st.len() - 1);
        for i in 0..st.len() {
            let before = st[i] - if i == 0 { 0 } else { et[i - 1] };
            let after = (if i < st.len() - 1 { st[i + 1] } else { evt }) - et[i];
            res = res.max(before + after + if et[i] - st[i] <= left { et[i] - st[i] } else { 0 });
            left = left.max(before);
            let before = (if j == st.len() - 1 { evt } else { st[j + 1] }) - et[j];
            let after = st[j] - if j > 0 { et[j - 1] } else { 0 };
            res = res.max(before + after + if et[j] - st[j] <= right { et[j] - st[j] } else { 0 });
            right = right.max(before); j -= 1
        } res
    }



// 0ms
    int maxFreeTime(int evt, vector<int>& st, vector<int>& et) {
        int left = 0, right = 0, res = 0, j = st.size() - 1;
        for (int i = 0; i < st.size(); ++i) {
            int before = st[i] - (i == 0 ? 0 : et[i - 1]);
            int after = (i < st.size() - 1 ? st[i + 1] : evt) - et[i];
            int dur = et[i] - st[i];
            res = max(res, before + after + (dur <= left ? dur : 0));
            left = max(left, before);
            before = (j == st.size() - 1 ? evt : st[j + 1]) - et[j];
            after = st[j] - (j > 0 ? et[j - 1] : 0);
            dur = et[j] - st[j];
            res = max(res, before + after + (dur <= right ? dur : 0));
            right = max(right, before);
            j--;
        }
        return res;
    }


9.07.2025

3439. Reschedule Meetings for Maximum Free Time I medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1044

Problem TLDR

Max free time after moving k events together #medium #sliding_window

Intuition

    // .. ... .... ....
    // ..    ... ....       ....    ......
    //    a     b       c        d    
    //   a+b    b+c       c+d                 k=1
    //    a+b+c  b+c+d                        k=2
    //    a+b+c+d                             k=3

Only the free intervals matter. Move k+1 intervals together with sliding window.

Approach

  • try to write O(1) memory solution
  • corner cases are start and the end

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(k)\) or O(1)

Code


// 16ms
    fun maxFreeTime(evt: Int, k: Int, st: IntArray, et: IntArray): Int {
        val free = LinkedList<Int>(); var sum = 0
        return (0..st.size).maxOf { i ->
            val t = (if (i < st.size) st[i] else evt) - (if (i > 0) et[i - 1] else 0)
            sum += t; free += t; if (free.size > k + 1) sum -= free.removeFirst()
            sum
        }
    }



// 10ms
    fun maxFreeTime(evt: Int, k: Int, st: IntArray, et: IntArray): Int {
        var sum = 0
        return (0..st.size).maxOf { i ->
            sum += (if (i < st.size) st[i] else evt) - (if (i > 0) et[i - 1] else 0) -
            (if (i > k) st[i - k - 1] else 0) + if (i - k - 2 >= 0) et[i - k - 2] else 0
            sum
        }
    }


// 3ms
    pub fn max_free_time(evt: i32, k: i32, st: Vec<i32>, et: Vec<i32>) -> i32 {
        let (mut sum, k) = (0, k as usize);
        (0..=st.len()).map(|i| {
            sum += if i < st.len() { st[i] } else { evt } - if i > 0 { et[i - 1] } else { 0 } -
            if i > k { st[i - k - 1] } else { 0 } + if i >= k + 2 { et[i - k - 2] } else { 0 };
            sum
        }).max().unwrap_or(0)
    }



// 4ms
    int maxFreeTime(int evt, int k, vector<int>& st, vector<int>& et) {
        int sum = 0, res = 0, n = st.size();
        for (int i = 0; i <= n; ++i) res = max(res, sum += 
            (i < n ? st[i] : evt) - 
            (i > 0 ? et[i - 1] : 0) - 
            (i > k ? st[i - k - 1] : 0) + 
            (i >= k + 2 ? et[i - k - 2] : 0));
        return res;   
    }


8.07.2025

1751. Maximum Number of Events That Can Be Attended II hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1043

Problem TLDR

Max top k valued intervals #hard #binary_search #dp

Intuition

Used a hint: dp + binary search for the next item. The interesting part is bottom up dp:

  • for every interval look up the largest previous result before start
  • append if prev + value > curr
  • the dp row is increased pairs end, sum
  • meaning max value at the end time
  • the longest chain of events is k

Approach

  • sort by start or end, both works

Complexity

  • Time complexity: \(O(nklog(n))\)

  • Space complexity: \(O(nk)\)

Code


// 226ms
    fun maxValue(es: Array<IntArray>, k: Int): Int {
        es.sortBy { it[0] }; val dp = HashMap<Pair<Int, Int>, Int>()
        fun dfs(i: Int, k: Int): Int = if (i == es.size || k == 0) 0 else dp.getOrPut(i to k) {
            val (s, e, v) = es[i]; var lo = i + 1; var hi = es.lastIndex; var j = es.size
            while (lo <= hi) {
                val m = (lo + hi) / 2
                if (es[m][0] > e) { j = min(j, m); hi = m - 1 } else lo = m + 1
            }
            max(dfs(i + 1, k), v + dfs(j, k - 1))
        }
        return dfs(0, k)
    }



// 208ms
    fun maxValue(es: Array<IntArray>, k: Int): Int {
        es.sortBy { it[1] }
        var dp1 = arrayListOf(listOf(0, 0))
        var dp2 = arrayListOf(listOf(0, 0))
        repeat(k) {
            for ((s, e, v) in es) {
                var lo = 0; var hi = dp1.size - 1; var i = -1
                while (lo <= hi) {
                    val m = (lo + hi) / 2
                    if (dp1[m][0] < s) { lo = m + 1; i = max(i, m) } else { hi = m - 1 }
                }
                if (i >= 0 && dp1[i][1] + v > dp2.last()[1]) dp2 += listOf(e, dp1[i][1] + v)
            }
            dp1 = dp2; dp2 = arrayListOf(listOf(0, 0))
        }
        return dp1.last()[1]
    }



// 43ms
    pub fn max_value(mut es: Vec<Vec<i32>>, k: i32) -> i32 {
        es.sort_unstable_by_key(|e| e[1]); let mut dp1 = vec![[0, 0]];
        for x in 0..k { let mut dp2 = vec![[0, 0]];
            for e in &es {
                let mut lo = 0; let mut hi = dp1.len() - 1;
                while lo <= hi {
                    let m = (lo + hi) / 2;
                    if dp1[m][0] < e[0] { lo = m + 1 } else { hi = m - 1 }
                }
                if dp1[hi][1] + e[2] > dp2[dp2.len() - 1][1] { dp2.push([e[1], e[2] + dp1[hi][1]]) }
            } dp1 = dp2
        } dp1[dp1.len() - 1][1]
    }



// 502ms
    int maxValue(vector<vector<int>>& es, int k) {
        sort(es.begin(), es.end()); unordered_map<long long, int> dp;
        auto dfs = [&](this const auto& dfs, int i, int k) -> int {
            if (i == es.size() || k == 0) return 0;
            long long key = ((long long)i << 32) | k;
            if (dp.count(key)) return dp[key];
            int s = es[i][0], e = es[i][1], v = es[i][2],
            lo = i + 1, hi = es.size() - 1;
            while (lo <= hi) {
                int m = (lo + hi) / 2;
                if (es[m][0] > e) hi = m - 1; else lo = m + 1;
            }
            return dp[key] = max(dfs(i + 1, k), v + dfs(lo, k - 1));
        };
        return dfs(0, k);
    }


7.07.2025

1353. Maximum Number of Events That Can Be Attended medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1042

Problem TLDR

Max attended events #medium #heap

Intuition


    //  1  2  3  4
    //  ****
    //  ****
    //     ****
    //        ****
    //
    //  1  2  3  4
    //  **********
    //           *
    //     *
    //        ****
    //  *
    //
    //  1  2  3  4  5
    //  1************
    //  *********4***
    //  ************5
    //     2***
    //     ***3
    //  3  5  5  3  3
    //  2  4  4  2  2  take 1
    //     3  3  2  2  take 1 (until it's end)  
    //        2  2  2  take 1 (until it's end)
    //           1  1  take 1 (until it's end, search for end)
    //              0  take 1
    //
    // 1 2 3 4 5 6 7
    // *
    // ***
    // *****
    // *******
    // *********
    // ***********
    // *************

The greedy strategy is to never waste a day and prioritize those that ends soon.

  • iterate over days
  • close already ended
  • add all started in that day
  • take one that ends sooner (maintain a heap to take min)

Approach

  • iteration over days range is almost as fast as manual day adjusting

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(n)\)

Code


// 97ms
    fun maxEvents(es: Array<IntArray>): Int {
        val days = Array(100002) { ArrayList<Int>() }
        for ((s, e) in es) days[s] += e
        var cnt = 0; val pq = PriorityQueue<Int>()
        for (d in 0..100000) {
            while (pq.size > 0 && pq.peek() < d) pq.poll()
            pq += days[d]
            if (pq.size > 0) { pq.poll(); cnt++ }
        }
        return cnt
    }



// 96ms
    fun maxEvents(es: Array<IntArray>): Int {
        es.sortWith(compareBy({ it[0] }, { it[1] }))
        val pq = PriorityQueue<Int>()
        var d = 0; var i = 0; var cnt = 0
        for (d in 1..100000) {
            while (pq.size > 0 && pq.peek() < d) pq.poll()
            while (i < es.size && es[i][0] == d) pq += es[i++][1]
            if (pq.size > 0) { pq.poll(); ++cnt }
        }
        return cnt
    }



// 94ms
    fun maxEvents(es: Array<IntArray>): Int {
        es.sortWith(compareBy({ it[0] }, { it[1] }))
        val pq = PriorityQueue<Int>()
        var d = 0; var i = 0; var cnt = 0
        while (pq.size > 0 || i < es.size) {
            if (pq.size < 1) d = es[i][0]
            while (i < es.size && es[i][0] == d) pq += es[i++][1]
            pq.poll(); ++cnt; ++d
            while (pq.size > 0 && pq.peek() < d) pq.poll()
        }
        return cnt
    }



// 24ms
    pub fn max_events(mut es: Vec<Vec<i32>>) -> i32 {
        es.sort_unstable();
        let (mut pq, mut i, mut cnt) = (BinaryHeap::new(), 0, 0);
        for d in 1..=100000 {
            while pq.len() > 0 && -pq.peek().unwrap() < d { pq.pop(); }
            while i < es.len() && es[i][0] == d { pq.push(-es[i][1]); i += 1 }
            if let Some(_) = pq.pop() { cnt += 1 }
        } cnt 
    }



// 69ms
    int maxEvents(vector<vector<int>>& es) {
        sort(begin(es), end(es));
        priority_queue<int, vector<int>, greater<int>> pq;
        int i = 0, cnt = 0;
        for (int d = 1; d <= 100000; ++d) {
            while (size(pq) && pq.top() < d) pq.pop();
            while (i < size(es) && es[i][0] == d) pq.push(es[i++][1]);
            if (size(pq)) { pq.pop(); ++cnt; }
        } return cnt;
    }


6.07.2025

1865. Finding Pairs With a Certain Sum medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1041

Problem TLDR

Design pairs counter; two lists, one changes #medium #hashmap

Intuition

The brute-force is accepted: maintain two frequencies map, iterate over the first.

Approach

  • sort first and exit early
  • remove 0 frequency elements

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n)\)

Code


// 231ms
class FindSumPairs(vararg val n: IntArray): HashMap<Int, Int>() {
    init { for (x in n[1]) merge(x, 1, Int::plus) }
    fun add(i: Int, v: Int) {
        merge(n[1][i].also { n[1][i] += v }, -1, Int::plus)
        merge(n[1][i], 1, Int::plus)
    }
    fun count(t: Int) = n[0].sumOf { get(t - it) ?: 0 }
}



// 186ms
class FindSumPairs(vararg val n: IntArray): HashMap<Int, Int>() {
    val f1 by lazy { 
        val f1 = HashMap<Int, Int>()
        for (x in n[0]) f1.merge(x, 1, Int::plus)
        val af = Array(f1.size) { IntArray(2) }
        var i = 0
        for ((a, f) in f1) { af[i][0] = a; af[i++][1] = f }
        Arrays.sort(af, compareBy { it[0] })
        af
    }
    init { for (x in n[1]) merge(x, 1, Int::plus) }
    fun add(i: Int, v: Int) {
        merge(n[1][i].also { n[1][i] += v }, -1, Int::plus)
        merge(n[1][i], 1, Int::plus)
    }
    fun count(t: Int): Int {
        var r = 0
        for ((a, f) in f1) 
            if (a > t) break
            else r += f * (get(t - a) ?: 0)
        return r
    }
}



// 41ms
#[derive(Default)] struct FindSumPairs(Vec<i32>, HashMap<i32, i32>, Vec<i32>);
impl FindSumPairs {
    fn new(mut n1: Vec<i32>, n2: Vec<i32>) -> Self {
        n1.sort_unstable(); let mut m = HashMap::new();
        for &x in &n2 { *m.entry(x).or_insert(0) += 1 }
        Self(n1, m, n2)
    }
    fn add(&mut self, i: i32, v: i32) {
        let x = self.2[i as usize]; self.2[i as usize] = x + v;
        *self.1.entry(x).or_insert(0) -= 1;
        *self.1.entry(x + v).or_insert(0) += 1
    }
    fn count(&self, t: i32) -> i32 {
        self.0.iter().map(|x| self.1.get(&(t - x)).unwrap_or(&0)).sum()
    }
}




// 19ms https://leetcode.com/problems/finding-pairs-with-a-certain-sum/submissions/1688214588
#[derive(Default)] struct FindSumPairs(Vec<(i32, i32)>, HashMap<i32, i32>, Vec<i32>);
impl FindSumPairs {
    fn new(mut n1: Vec<i32>, n2: Vec<i32>) -> Self {
        n1.sort_unstable(); let mut m = HashMap::new();
        for &x in &n2 { *m.entry(x).or_insert(0) += 1 }
        Self(n1.chunk_by(|a, b| a == b).map(|c| (c[0], c.len() as i32)).collect(), m, n2)
    }
    fn add(&mut self, i: i32, v: i32) {
        let x = self.2[i as usize]; self.2[i as usize] = x + v;
        *self.1.entry(x).or_insert(0) -= 1;
        if self.1[&x] == 0 { self.1.remove(&x); }
        *self.1.entry(x + v).or_insert(0) += 1
    }
    fn count(&self, t: i32) -> i32 {
        let mut r = 0;
        for &(x, c) in &self.0 {
            if x > t { break }
            r += c * self.1.get(&(t - x)).unwrap_or(&0)
        } r
    }
}



// 147ms
class FindSumPairs {
public:
    vector<int> n1, n2; unordered_map<int, int> m;
    FindSumPairs(vector<int>& ns1, vector<int>& ns2) {
        n1 = ns1; n2 = ns2; sort(begin(n1), end(n1));
        for (int x: n2) ++m[x];
    }
    void add(int i, int v) { --m[n2[i]]; n2[i] += v; ++m[n2[i]]; }
    int count(int t) {
        int r = 0;
        for (int x: n1) if (x > t) break; else r += m[t - x];
        return r;
    }
};



// 49ms
class FindSumPairs {
public:
    vector<int> n1, n2; unordered_map<int, int> m;
    FindSumPairs(vector<int>& ns1, vector<int>& ns2) {
        swap(n1, ns1); swap(n2, ns2); sort(begin(n1), end(n1));
        for (int x: n2) ++m[x];
    }
    void add(int i, int v) { --m[n2[i]]; n2[i] += v; ++m[n2[i]]; }
    int count(int t) {
        int r = 0;
        for (int x: n1) if (x > t) break; else {
            auto it = m.find(t - x);
            if (it != end(m)) r += it->second;
        } return r;
    }
};


5.07.2025

1394. Find Lucky Integer in an Array easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1040

Problem TLDR

Max x == freq(x) #easy

Intuition

The most brute-force is O(n^2), the fastest is O(n) and O(1) memory.

Approach

  • how many ways to write this code?
  • skip all numbers bigger than size
  • sort, group, chunk, build a table, bit shift

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 14ms
    fun findLucky(arr: IntArray): Int {
        arr.sortDescending(); var c = 0; var p = -1
        for (x in arr) if (x == p) ++c else { if (c == p) return p; c = 1; p = x }
        return if (c == p) p else -1
    }



// 13ms
    fun findLucky(arr: IntArray) =
        (500 downTo 1).firstOrNull { x -> x == arr.count { it == x } } ?: -1



// 6ms
    fun findLucky(arr: IntArray) =
        arr.groupBy { it }.maxOf { (k, v) -> if (v.size == k) k else -1 }



// 2ms
    fun findLucky(a: IntArray): Int {
        for (x in a) if ((x and 0xfff) <= a.size) a[(x and 0xfff) - 1] += 1 shl 12
        for (x in a.size downTo 1) if (x == a[x - 1] shr 12) return x
        return -1
    }



// 1ms
    fun findLucky(arr: IntArray): Int {
        val f = IntArray(501); for (x in arr) ++f[x]
        for (x in arr.size downTo 1) if (x == f[x]) return x
        return -1
    }



// 0ms
    pub fn find_lucky(mut a: Vec<i32>) -> i32 {
        a.sort_unstable(); a.chunk_by(|a, b| a == b)
        .filter(|c| c.len() as i32 == c[0]).map(|c| c[0] as i32).max().unwrap_or(-1)
    }



// 0ms
    int findLucky(vector<int>& a) {
        int f[501]={}, r = -1; f[0] = 1; 
        for (int x: a) ++f[x];
        for (int x: f) if (x == f[x]) r = max(r, x);
        return r;
    }


4.07.2025

3307. Find the K-th Character in String Game II hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1039

Problem TLDR

kth char in double+shift by ops[i] string #hard #bit_manipulation

Intuition

Took me too long to spot the reversive order of operations.

    // a
    // ab
    // 1234
    // abab

    // 12345678910
    //          *
    //     *
    //  *
    // *

    // 0123456789
    // abbcbccdbc
    // 0112122312
    //   . .    *+1 op = 1  single conversion
    //   . *+0 op=0
    //   *+0 op=1
    //  *+1 op=0
    // *0

    // 0123456789
    // abbcbccdbc    k=3   op=[1,0]
    // 0112122312
    //   *+0 op=0
    //  *+1 op=1
    // *0  

    // a - ab op=1
    // ab - abab op=0 notice the reversive order of `op`
    // 0123
    // abab
    //   *
  • each time string doubles
  • the left part is always skips shift
  • the right part do shift if operations[op] == 1
  • given position x can be from the left if x % 2 == 0 or from the right if x % 2 == 1
  • as we go from child to parent, operations[] are inversed

Approach

  • this time overflow of z is actually possible, don’t forget %26

Complexity

  • Time complexity: \(O(o)\)

  • Space complexity: \(O(1)\)

Code


// 1ms
    fun kthCharacter(k: Long, operations: IntArray): Char {
        var x = 0L; var p = 1L
        for (o in operations) { x += p * o; p *= 2 }
        return 'a' + (x and (k - 1)).countOneBits() % 26
    }



// 1ms
    fun kthCharacter(k: Long, operations: IntArray, i: Int = 0, l: Long = 1L): Char =
        if (k == l) 'a' else 'a' + (kthCharacter((k - l) / 2, operations, i + 1, 0) + ((k - l) % 2).toInt() * operations[i] - 'a') % 26



// 0ms
    pub fn kth_character(k: i64, operations: Vec<i32>) -> char {
       let (mut x, mut p) = (0, 1); for o in operations { x += p * o as i64; p *= 2 }
       "abcdefghijklmnopqrstuvwxyz".as_bytes()[((x & (k - 1)).count_ones() % 26) as usize] as char
    }



// 0ms
    char kthCharacter(long long k, vector<int>& o) {
        --k; char c = 'a';
        for (int o: o) c = 'a' + (c + ((k & 1) & o) - 'a') % 26, k /= 2;
        return c;
    }


3.07.2025

3304. Find the K-th Character in String Game I easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1038

Problem TLDR

kth char after appending rotated self #easy

Intuition

Simulation is accepted.

Some patterns:

    // 01 23 4567 8910     16               32
    // 01 12 1223 13 
    // ab bc bccd bccd.... bccd............ bccd........
    //                 cdde
    //                 12
  • the b is always at pos power of two
  • each time we double into the left part and right part
  • left is untouched, right is shifted once against previous
  • left is at POS%2 == 0, right is at POS%2 > 0

Approach

  • do shift at each set bit
  • ‘a’ will never overflow ‘z’, the first ‘z’ is at (1 << 25) - 1 position

Complexity

  • Time complexity: \(O(k^2)\)

  • Space complexity: \(O(k)\)

Code


// 13ms
    fun kthCharacter(k: Int): Char {
        var s = listOf('a')
        while (s.lastIndex < k - 1) s += s.map { it + 1 }
        return s[k - 1]
    }



// 1ms
    fun kthCharacter(k: Int): Char {
        var k = k - 1; var c = 'a'
        while (k > 0) { c += k % 2; k /= 2 }
        return c
    }



// 0ms
    fun kthCharacter(k: Int): Char {
        fun x(k: Int): Char = if (k == 0) 'a' else x(k / 2) + k % 2
        return x(k - 1)
    }



// 0ms
    fun kthCharacter(k: Int, l: Int = 1): Char =
        if (k == l) 'a' else kthCharacter((k - l) / 2, 0) + (k - l) % 2



// 0ms
    fun kthCharacter(k: Int) = 'a' + (k - 1).countOneBits()



// 0ms
    pub fn kth_character(k: i32) -> char {
        "abcdefghi".as_bytes()[(k - 1).count_ones() as usize] as char
    }



// 0ms
    char kthCharacter(int k) {
        return 'a' + __builtin_popcount(k - 1);
    }


2.07.2025

3333. Find the Original Typed String II hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1037

Problem TLDR

ways to remove duplicates, preserve length at least k #hard #dp

Intuition

Didn’t solved.


    // aaabbb   k=3   len=6
    // aaabbb
    //
    // aaabb   b=3, 3-1=2, 6-2=4
    // aaab

    // aabbb   a:2, 6-2=4
    // abbb
    //
    // aabb  combinatorics? a_variants * b_variants - bad_comb
    // aab
    // abb
    //
    // bad:
    // ab
    // dp? it is 10^5 * 2000 will give TLE, use hint(14 minute)
    // at most k - 1
    // bad combination length is at most k - 1

    // ab - single bad
    //      if k=5
    // ab, abb, abbb, aab, aabb, aaab - bad
    // how to count them?
    // aaabbbcccbbb    k=7
    // a  b  c  b      min=4, can take +2 on each or +1 +1 on any pair
    // aa                
    // aaa
    // aa bb
    // aa    cc
    // aa       bb
    //    bb
    //    bbb
    //(aa bb)
    //    bb cc
    //    bb    bb
    //       cc
    //       ccc
    //(aa    cc)
    //   (bb cc)
    //       cc bb
    //          bb
    //          bbb
    //(aa       bb)
    //   (bb    bb)
    //      (cc bb)     (15 bad), total=1*3a*3b*3c*3b = 9*9=81
    //                  ans = 81-15 = 66

    // choose up to 2 from aa|bb|cc|bb = choose 1 + choose 2
    // C(1, 4) + C(2, 4) ??? how to choose from: a|bbbb|cc

    // choose (k - 1 - min) from islands  a|bbb|cc|b|aa
    //                           only non-singles
    //                                    bb|c|a
    // 43 minute, look for solution

  • the main hardness is how to choose bad variants from a non-equal buckets (after we remove all the minimal required chars)
  • n - size of minimum non-repeating buckets
  • g - groups, with filtered out minimal required values aa becomes a, b becomes `` and filtered out; we only interested in the repeating_count - 1 values to choose from
  • use DP[curr_bucket] = sum_{kk-g(i)}(DP[prev_bucket]) = PS[curr]-PS[kk-g(i)]

Approach

  • good solution from /u/votrubac/ https://leetcode.com/problems/find-the-original-typed-string-ii/solutions/5982440/optimized-tabulation/

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 416ms
    fun possibleStringCount(w: String, k: Int): Int {
        val M = 1_000_000_007L; val g = ArrayList<Int>()
        var c = 1; var all = 1L; var n = k
        for (i in 1..w.length) if (i < w.length && w[i] == w[i - 1]) ++c
            else { --n; if (c - 1 > 0) g += c - 1; all = (all * c) % M; c = 1 }
        if (n <= 0) return all.toInt()
        val dp = Array(2) { LongArray(n) }; dp[0][0] = 1L; val ps = LongArray(n + 1) 
        for (i in 0..<g.size) for (kk in 0..<n) {
            ps[kk + 1] = (ps[kk] + dp[i % 2][kk]) % M
            dp[1 - (i % 2)][kk] = (ps[kk + 1] - ps[max(0, kk - g[i])]) % M
        }
        var bad = 0L; for (i in 0..<n) bad = (bad + dp[g.size % 2][i]) % M
        return ((all + M - bad) % M).toInt()
    }



// 49ms
    pub fn possible_string_count(w: String, k: i32) -> i32 {
        let g = w.as_bytes().chunk_by(|a, b| a == b).map(|c| c.len() as i64).collect::<Vec<_>>(); 
        let M = 1_000_000_007; let mut all = 1; for &c in &g { all = (all * c) % M }; 
        if k as usize <= g.len() { return all as i32 }; let n = k as usize - g.len();
        let g = g.iter().filter(|&&c| c > 1).map(|&c| c - 1).collect::<Vec<_>>();
        let mut dp = vec![vec![0; n]; 2]; dp[0][0] = 1i64; let mut ps = vec![0; n + 1];
        for i in 0..g.len() { for kk in 0..n {
            ps[kk + 1] = (ps[kk] + dp[i % 2][kk]) % M;
            dp[1 - (i % 2)][kk] = (ps[kk + 1] - ps[(0.max(kk as i64 - g[i])) as usize]) % M;
        }}
        let mut bad = 0; for i in 0..n { bad = (bad + dp[g.len() % 2][i]) % M }
        ((all + M - bad) % M) as i32
    }


1.07.2025

3330. Find the Original Typed String I easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1036

Problem TLDR

ways to remove duplicates #easy #counting

Intuition

Count duplicates, answer is sum of count - 1. Corner case: duplicates must be adjacent.

Approach

  • count same chars islands
  • or just count equal adjacent pairs

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 136ms
    fun possibleStringCount(w: String) = 1 +
        w.windowed(2).count { it[0] == it[1] }



// 108ms
    fun possibleStringCount(w: String): Int {
        var cnt = 1; var p = '.'
        for (c in w) if (c == p) ++cnt else p = c
        return cnt
    }



// 98ms
    fun possibleStringCount(w: String): Int {
        var cnt = 1; var r = 0; var p = '.'
        for (c in w) if (c == p) ++r else { cnt += r; r = 0; p = c  }
        return cnt + r
    }



// 2ms
    pub fn possible_string_count(w: String) -> i32 {
       w.as_bytes().chunk_by(|a, b| a == b).collect::<Vec<_>>() 
       .iter().map(|w| 0.max(w.len() as i32 - 1)).sum::<i32>() + 1
    }



// 0ms
    pub fn possible_string_count(w: String) -> i32 {
       1 + w.as_bytes().windows(2).filter(|w| w[0] == w[1]).count() as i32
    }



// 0ms
    int possibleStringCount(string w) {
        int cnt = 1; char p = '.';
        for (char c: w) c == p ? ++cnt : p = c;
        return cnt;
    }


30.06.2025

594. Longest Harmonious Subsequence easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1035

Problem TLDR

Longest subsequence with max-min=1 #easy #counting #sort #two_pointers

Intuition

Calculate the frequencies. For each value x find count x-1 and x+1.

Another was: sort, then linear scan.

Approach

  • should be exactly 1, not at most
  • we can check only the x + 1 (because we x - 1 would still be checked)

Complexity

  • Time complexity: \(O(n\)

  • Space complexity: \(O(n)\)

Code


// 25ms
    fun findLHS(n: IntArray): Int {
        val f = n.groupBy { it }
        return f.maxOf { (k, v) -> v.size + (f[k + 1]?.size ?: -v.size) }
    }



// 0ms
    pub fn find_lhs(mut n: Vec<i32>) -> i32 {
        n.sort_unstable(); n.chunk_by(|a, b| b - a < 1)
        .collect::<Vec<_>>().windows(2)
        .map(|w| if w[1][0] - w[0][0] == 1 { w[0].len() + w[1].len() } else { 0 })
        .max().unwrap_or(0) as _
    }



// 6ms
    int findLHS(vector<int>& n) {
        sort(begin(n), end(n)); int r = 0;
        for (int i = 1, j = 0; i < size(n); ++i) {
            while (j < i && n[i] - n[j] > 1) j++;
            if (n[i] - n[j] == 1) r = max(r, i - j + 1);
        } return r;
    }


29.06.2025

1498. Number of Subsequences That Satisfy the Given Sum Condition medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1034

Problem TLDR

Subsequencies target in 0..min+max #medium #binary_search #two_pointers

Intuition

Observe the problem:

    // 2,3,3,4,6,7 target = 10
    //       * * *

    // 7 2 7  72 27 2 727     -77 -7 -7
    // 2 7 7  27 27 2 277     -77 -7 -7
    // order doesn't matter, can sort

    // binary search target / 2 right border

    // for each value x find with bs t=(target - x)

    // 0 1 2 3 4 5
    // 2 3 3 4 6 7     t=12
    // j       i      6+2 =8 6+6=12
    // j         i    7+2 =9 7+7=14, 7+6=13, 7+4=11
    // f     t                               t=4
    // 4 + 3 + 2 + 1 = 10 = 4 * 5 / 2
  • order doesn’t matter -> can sort (subsequencies are different, but count is the same; for every min,max pair we can take any subset of others)
  • now min..max is a subarray (not subsequence)
  • at every position we count subarrays ending on that position
  • count good or bad
  • naive: binary search target - n[i], bad is i - j
  • clever: the right border only goes from the right to the left, no need for binary search

Approach

  • optimize memory to O(1) using 2^x%m exponentiation technique: a^x = (a^2^x/2 + a^x%2)
  • write a short joke solution with BigInteger
  • precompute 2^x in one go counting bad subarrays

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(n)\)

Code


// 177ms
    fun numSubseq(n: IntArray, t: Int): Int {
        var i = 0; var j = n.size - 1; n.sort(); var c = 0.toBigInteger(); val one = 1.toBigInteger()
        while (i <= j) if (n[i] + n[j] > t) j-- else c = c.add(one.shiftLeft(j - i++))
        return c.mod(1_000_000_007.toBigInteger()).intValueExact()
    }



// 75ms
    fun numSubseq(n: IntArray, t: Int): Int {
        val M = 1_000_000_007; n.sort(); var cnt = 0
        val f = IntArray(n.size + 2); f[1] = 1
        for ((i, x) in n.withIndex()) {
            f[i + 2] = (f[i + 1] * 2) % M
            var lo = 0; var hi = i; var j = -1
            while (lo <= hi) {
                val m = (lo + hi) / 2
                if (x + n[m] <= t) { j = max(j, m); lo = m + 1 } 
                else hi = m - 1
            }
            cnt = (cnt + f[i - j]) % M
        }
        return (f[n.size + 1] - cnt - 1 + M) % M
    }



// 57ms
    fun numSubseq(n: IntArray, t: Int): Int {
        val M = 1_000_000_007; n.sort(); var cnt = 0
        val f = IntArray(n.size + 2); f[1] = 1; var j = n.size - 1
        for ((i, x) in n.withIndex()) {
            f[i + 2] = (f[i + 1] * 2) % M
            while (j >= 0 && x + n[j] > t) j--
            if (j <= i) cnt = (cnt + f[i - j]) % M
        }
        return (f[n.size + 1] - cnt - 1 + M) % M
    }



// 55ms
    fun numSubseq(n: IntArray, t: Int): Int {
        val M = 1_000_000_007; var c = 0; var i = 0; var j = n.size - 1; n.sort()
        fun f(a: Long, x: Int): Long = if (a == 2L && x < 63) (1L shl x) % M else
            if (x == 0) 1L else (f((a * a) % M, x / 2) * if (x % 2 > 0) a else 1) % M
        while (i <= j) if (n[i] + n[j] > t) j--
                       else c = (c + f(2L, j - i++).toInt()) % M
        return c
    }


// 47ms
    fun numSubseq(n: IntArray, t: Int): Int {
        val M = 1_000_000_007; val f = IntArray(n.size); f[0] = 1
        var c = 0; var i = 0; var j = n.size - 1; n.sort()
        for (i in 1..<n.size) f[i] = (2 * f[i - 1]) % M
        while (i <= j) if (n[i] + n[j] > t) j--
                       else c = (c + f[j - i++]) % M
        return c
    }



// 45ms
    fun numSubseq(n: IntArray, t: Int): Int {
        val M = 1_000_000_007; n.sort(); var cnt = 0
        val f = IntArray(n.size); f[0] = 1; var j = n.size - 1
        for (i in 1..<n.size) f[i] = (2 * f[i - 1]) % M
        for ((i, x) in n.withIndex()) {
            while (j >= 0 && x + n[j] > t) j--
            if (j < i) break
            cnt = (cnt + f[j - i]) % M
        }
        return cnt
    }



// 5ms
    pub fn num_subseq(mut n: Vec<i32>, t: i32) -> i32 {
        let (M, mut c, mut j) = (1_000_000_007, 0, n.len());
        n.sort_unstable(); let mut f = vec![0; n.len() + 2]; f[1] = 1;
        for (i, x) in n.iter().enumerate() {
            f[i + 2] = (f[i + 1] * 2) % M;
            while j > 0 && x + n[j - 1] > t { j -= 1 }
            if i + 1 >= j { c = (c + f[i + 1 - j]) % M }
        } (f[n.len() + 1] - c - 1 + M) % M
    }



// 0ms
    int numSubseq(vector<int>& a, int t) {
        int n = a.size(), m = 1e9+7; vector<int> p(n,1);
        sort(a.begin(), a.end());
        for(int i = 1; i < n; ++i)  p[i] = (p[i-1]*2) % m;
        int i = 0, j = n-1, r = 0;
        while(i <= j) if(a[i] + a[j] > t) --j;
                      else r = (r + p[j-i++]) % m;
        return r;
    } 


28.06.2025

2099. Find Subsequence of Length K With the Largest Sum easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1033

Problem TLDR

Subsequence of k largest #easy #sort

Intuition

Sort, take k, restore original order.

Approach

  • use sort or heap
  • try to write quickselect (Hoare is the fastest)
  • corner case is the duplicate numbers, count how many included in largest k

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(n)\)

Code


// 36ms
    fun maxSubsequence(n: IntArray, k: Int) = n
    .withIndex().sortedBy { -it.value }.take(k)
    .sortedBy { it.index }.map { it.value }



// 31ms
    fun maxSubsequence(n: IntArray, k: Int) = 
        n.toMutableList().apply {
            while (size > k) remove(min())
        }



// 26ms
    fun maxSubsequence(n: IntArray, k: Int): List<Int> {
        val q = PriorityQueue<Pair<Int, Int>>(compareBy { it.first })
        for ((i, x) in n.withIndex()) {
            q += x to i
            if (q.size > k) q.poll()
        }
        return q.sortedBy { it.second }.map { it.first }
    }



// 17ms
    fun maxSubsequence(n: IntArray, k: Int): IntArray {
        val src = n.clone(); var i = 0
        var lo = 0; var hi = n.lastIndex
        while (lo < hi) {
            var l = lo; var h = hi
            val t = (n[lo] + n[hi]) / 2
            while (l <= h) {
                while (n[l] < t) ++l
                while (n[h] > t) --h
                if (l <= h) n[l] = n[h].also { n[h--] = n[l++] }
            }
            if (n.size - k > h) lo = l else hi = h
        }
        val min = n[n.size - k]
        var cnt = (n.size - k..<n.size).count { n[it] == min }
        return IntArray(k) { while (src[i] < min || src[i] == min && --cnt < 0) ++i; src[i++] }
    }



// 0ms
    pub fn max_subsequence(mut n: Vec<i32>, k: i32) -> Vec<i32> {
        for i in 0..n.len() { n[i] = (n[i] << 11) | i as i32 }
        n.sort_unstable(); let l = n.len() - k as usize;
        (&mut n[l..]).sort_unstable_by_key(|x| x & ((1 << 11) - 1));
        for x in &mut n { *x >>= 11 } n[l..].to_vec()
    }



// 0ms
    vector<int> maxSubsequence(vector<int>& a, int k) {
        auto b = a; sort(begin(b), end(b), greater<>());
        int m = b[k-1], c = count(begin(b), begin(b) + k, m); 
        vector<int> r;
        for (int x: a) if (x > m || (x == m && c-- > 0)) r.push_back(x);
        return r;
    }


27.06.2025

2014. Longest Subsequence Repeated k Times hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1032

Problem TLDR

Longest k-repeating subsequence #hard #backtracking

Intuition

Used the hints.

  1. find all good characters (at least k frequent)
  2. do DFS with backtracking
  3. prune by only taking at most n/k chars, each frequency at most f[c] / k

Approach

  • great speed up: don't build subsequence further if current is not k-repeating (300ms to 90ms)
  • another way is BFS, explore new length layer by layer (Rust code, no pruning optimizations)

Complexity

  • Time complexity: \(O(n^r)\) r = max_freq[a..z] / k

  • Space complexity: \(O(r)\) recursion depth

Code


// 91ms
    fun longestSubsequenceRepeatedK(s: String, k: Int): String {
        var res = ""; val f = IntArray(26); for (c in s) ++f[c - 'a']
        val cnt = IntArray(26); val seq = CharArray(s.length / k); var sz = 0
        fun check() {
            var i = 0; var fr = if (sz > 0) 0 else k 
            if (sz > 0) for (c in s) if (c == seq[i % sz]) if (++i % sz == 0) fr++
            if (fr < k) return
            if (sz > res.length) res = String(seq, 0, sz)
            for (c in 25 downTo 0) if (f[c] >= k && cnt[c] < f[c] / k) {
                ++cnt[c]; seq[sz++] = 'a' + c
                check()
                --cnt[c]; --sz 
            }
        }
        check()
        return res
    }


// 416ms
    pub fn longest_subsequence_repeated_k(s: String, k: i32) -> String {
        let (mut q, mut q1, mut res) = (vec![String::from("")], vec![], "".into());
        while q.len() > 0 {
            for sub in &q {
                for c in 'a'..='z' {
                    let next = format!("{}{}", sub.clone(), c);
                    let mut i = 0; let mut r = next.len() * (k as usize);
                    for c in s.bytes() {
                        if c == next.as_bytes()[i % next.len()] {
                            i += 1; if i == r { break }}}
                    if i == r { res = next.clone(); q1.push(next) }
                }}
            (q, q1) = (q1, q); q1.clear()
        } res
    }



// 92ms
    string longestSubsequenceRepeatedK(string s, int k) {
        int f[26] = {}, c[26] = {}; for (char x : s) f[x - 'a']++;
        string res, seq;
        auto dfs = [&](this const auto& dfs) {
            int sz = seq.size(), i = 0, cnt = sz ? 0 : k;
            if (sz)
                for (char x : s)
                    if (x == seq[i % sz] && ++i % sz == 0)
                        if (++cnt == k) break;
            if (cnt < k) return;
            if (sz > (int)res.size()) res = seq;
            for (int x = 25; x >= 0; x--) {
                if (f[x] >= k && c[x] < f[x] / k) {
                    c[x]++; seq.push_back('a' + x);
                    dfs();
                    seq.pop_back(); c[x]--;
                }
            }
        };
        dfs();
        return res;
    }


26.06.2025

2311. Longest Binary Subsequence Less Than or Equal to K medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1031

Problem TLDR

Longest binary subsequence less than K #medium

Intuition

    // take all zeros
    // 1001010       k=5
    //  ** * *
    //      1        take rightmost 1 while no more than k
    //
    // 1000001110    k=8
    //       

    // 1001010     k=5
    //   .   *       l=1
    //   .  *    x=4 l=2
    //   . *         l=3
    //   .-
    //   *           l=4
    //  *            l=5

    // 101001010111100001111110110010011   k=522399436

Greedily take from the tail if condition is ok. Spent too much time trying to build the number, then gave up and just used strings. (what was missing: check bitshift less than 31)

Approach

  • sometimes more hacky solution is the only one that can be written without off-by-ones
  • to not overflow, check number is not negative, and check the bitshift is less than 31

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n)\)

Code


// 30ms
    fun longestSubsequence(s: String, k: Int) = s.reversed()
        .fold("") { r, c -> 
            if ("$c$r".toIntOrNull(2) ?: k + 1 <= k) "$c$r" else r
        }.length


// 7ms
    fun longestSubsequence(s: String, k: Int): Int {
        var x = 0; var l = 0
        for (i in s.lastIndex downTo 0)
            if (s[i] == '0') ++l else if (l < 31) {
                val y = x + (1 shl l)
                if (y in 0..k) { x = y; ++l }
            }
        return l
    }



// 0ms
    pub fn longest_subsequence(s: String, k: i32) -> i32 {
        let (mut x, mut l, s) = (0, 0, s.as_bytes());
        for i in (0..s.len()).rev() {
            if s[i] == b'0' { l += 1 }
            else if l < 31 {
                let y = x + (1 << l);
                if y <= k { x = y; l += 1 }
            }
        } l
    }



// 0ms
    int longestSubsequence(string s, int k) {
        int x = 0, l = 0;
        for (int i = size(s) - 1; i >= 0; --i)
            if (s[i] == '0') ++l; else if (l < 31) {
                int y = x + (1 << l);
                if (y <= k) { x = y; ++l; }
            }
        return l;
    }


25.06.2025

2040. Kth Smallest Product of Two Sorted Arrays hard blog post substack youtube

1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1030

Problem TLDR

K-th increasing product from two arrays #hard #binary_search

Intuition

The intuition is simple (i used the hints though):

  • search result with binary search
  • count by iterating over one array and finding how many to take using the binary search in the other.

The implementation is scary.

    // 1 2 3       1x1 1x2 2x1 1x3 3x1 2x2 2x3 3x2 3x3
    // 1 2 3

    // 2 5    2x3 2x4 5x3 5x4 
    // 3 4      6   8  15  20

    // ----++++    ----+++
    //               
    // inverted for ----- + classic for +++++   

Approach

  • we only need one classic binary search and one inverted
  • for the negative current array use the inverted search; divide array into negative and positive part
  • search for the maximum index you can take
  • for inverted, subtract inverted result from all possible pairs

Complexity

  • Time complexity: \(O(nlog^2(n))\)

  • Space complexity: \(O(1)\)

Code


// 1022ms
    fun kthSmallestProduct(n1: IntArray, n2: IntArray, k: Long): Long {
        fun bs(n1: IntArray, n2: IntArray, from: Int, to: Int, cmp: (Long) -> Boolean): Long {
            var cnt = 0L
            for (i in from..to) {
                var l = 0; var h = n2.lastIndex; var jmax = -1
                while (l <= h) {
                    val j = (l + h) / 2
                    if (cmp(1L * n1[i] * n2[j])) { jmax = max(jmax, j); l = j + 1 } else h = j - 1
                }
                cnt += jmax + 1
            }
            return cnt
        }
        fun classic(n1: IntArray, n2: IntArray, m: Long, from: Int, to: Int): Long =
            bs(n1, n2, from, to) { it <= m }
        fun inverted(n1: IntArray, n2: IntArray, m: Long, from: Int, to: Int): Long =
            1L * n2.size * (to - from + 1) -  bs(n1, n2, from, to) { it > m }
        val div = (0..<n1.size - 1).firstOrNull { (n1[it] < 0) != (n1[it + 1] < 0) } ?: -1
        fun count(m: Long): Long = if (div >= 0)
            classic(n1, n2, m, div + 1, n1.lastIndex) + inverted(n1, n2, m, 0, div)
            else if (n1[0] < 0) inverted(n1, n2, m, 0, n1.lastIndex) else classic(n1, n2, m, 0, n1.lastIndex)
        val peaks = listOf(1L * n1[0] * n2[0], 1L * n1[0] * n2.last(), 1L * n1.last() * n2[0], 1L * n1.last() * n2.last())
        var lo = peaks.min(); var hi = peaks.max(); var res = Long.MAX_VALUE
        while (lo <= hi) {
            val m = lo + (hi - lo) / 2
            if (count(m) < k) lo = m + 1 else { hi = m - 1; res = min(res, m) }
        }
        return res
    }


24.06.2025

2200. Find All K-Distant Indices in an Array easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1029

Problem TLDR

Indices k-distant to key #easy

Intuition

The brute force: scan -k..k at each index. More optimal: build suffix array to predict where is the next key, scan and save the last key position.

Approach

  • use brute-force for easy problems

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n)\)

Code


// 32ms
    fun findKDistantIndices(n: IntArray, key: Int, k: Int) =
        n.indices.filter { (max(0, it - k)..min(n.size - 1, it + k)).any { n[it] == key} }



// 1ms
    pub fn find_k_distant_indices(n: Vec<i32>, key: i32, k: i32) -> Vec<i32> {
        (0..n.len() as i32).filter(|i| 
        (0.max(i - k)..(i + k + 1).min(n.len() as i32)).any(|j| n[j as usize] == key)).collect()
    }



// 0ms
    vector<int> findKDistantIndices(vector<int>& n, int key, int k) {
        int last = -2 * size(n); vector<int> res{}, next(size(n));
        for (int i = size(n) - 1; i >= 0; --i)
            next[i] = n[i] == key ? i : (i + 1 < size(n) ? next[i + 1] : 2 * size(n));
        for (int i = 0; i < size(n); ++i) {
            if (n[i] == key) last = i;
            if (next[i] - i <= k || i - last <= k) res.push_back(i);
        }
        return res;
    }

23.06.2025

2081. Sum of k-Mirror Numbers hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1028

Problem TLDR

n palindromes in both 10 and k-base #hard #math

Intuition

The simple intuition: brute-force all palindromes. The trick is how to build palindromes in increasing order.

  • subproblem: Closest Palindrome, hard (https://leetcode.com/problems/find-the-closest-palindrome/description/)

My own solution was accepted:

  • iterate halves 1..some_max_value
  • build two possible tails, with doubled or not center value
  • collect those values and then sort

The trick is how to find the max_value to be sure we got all first n values. I just brute-forced it and hardcoded, the function is max(n) = f(2^x) with some constants.

More optimal approach: generate palindromes in increasing order.

  • iterate over length of the palindrome
  • and iterate halves = start..end, where start is 10^half, end is 10^(half+1)-1
  • then build a tail, and check

Approach

  • even non optimal solution feels good if its your own
  • however, let’s try to understand and remember how to build the palindromes in order

Complexity

  • Time complexity: \(O(2^n)\)

  • Space complexity: \(O(n)\)

Code


// 1265ms
    fun kMirror(k: Int, n: Int): Long {
        val k = k.toLong(); val res = ArrayList<Long>()
        fun check(v: Long) {
            var x = v; var vk = 0L
            while (x > 0) { vk = vk * k + x % k; x /= k }
            if (vk == v) res += v
        }
        for (vd in 1..(1 shl ((7 * n + 166) / 18))) {
            val vd = vd.toLong(); var x = vd
            var v = vd; var v2 = vd
            while (x > 0) {
                v = v * 10L + x % 10L; x /= 10L
                if (x > 0) v2 = v2 * 10L + x % 10L
            }
            check(v); check(v2)
        }
        res.sort()
        return (0..<n).sumOf { res[it] }
    }



// 87ms
    fun kMirror(k: Int, n: Int): Long {
        var ans = 0L; var cnt = 0; var len = 0; val k = 1L * k
        while (cnt < n && ++len > 0) {
            val half = (len + 1) / 2
            var start = 1; for (i in 1..<half) start *= 10
            val end = start * 10 - 1;
            for (pref in start..end) {
                var pal = 1L * pref; var tail = 1L * pref
                if (len % 2 > 0) tail /= 10
                while (tail > 0) { pal = pal * 10 + (tail % 10); tail /= 10 }
                var t = pal; var rev = 0L
                while (t > 0) { rev = rev * k + (t % k); t /= k }
                if (rev == pal) { ans += pal; if (++cnt == n) break }
            }
        }
        return ans
    }



// 69ms
    pub fn k_mirror(k: i32, mut n: i32) -> i64 {
        let (mut ans, mut len, k) = (0i64, 0, k as i64);
        while n > 0 {
            len += 1; let half = (len + 1) / 2;
            let mut start = 1i64; for _ in 1..half { start *= 10; }
            let end = start * 10 - 1;
            for pref in start..=end {
                let mut pal = pref;
                let mut tail = if len % 2 == 0 { pref } else { pref / 10 };
                while tail > 0 { pal = pal * 10 + (tail % 10); tail /= 10; }
                let mut t = pal; let mut rev = 0i64;
                while t > 0 { rev = rev * k + (t % k); t /= k; }
                if rev == pal { ans += pal; n -= 1; if n == 0 { break } }
            }
        }  ans
    }



// 107ms
    long long kMirror(int k, int n) {
        long long ans = 0;
        for (int len = 1; n; ++len) {
            int halfLen = (len + 1) / 2;
            long long start = 1; for (int i = 1; i < halfLen; ++i) start *= 10;
            long long end = start * 10 - 1;
            for (long long prefix = start; prefix <= end && n; ++prefix) {
                long long pal = prefix; long long tail = prefix;
                if (len & 1) tail /= 10;
                while (tail) pal = pal * 10 + (tail % 10), tail /= 10;
                long long t = pal, rev = 0;
                while (t) rev = rev * k + (t % k), t /= k;
                if (rev == pal) ans += pal, --n;
            }
        }
        return ans;
    }


22.06.2025

2138. Divide a String Into Groups of Size k easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1027

Problem TLDR

k-chunked string, filled tail #easy

Intuition

Pad then chunk, or chunk then pad. Prefill everything, or write a precise filling code. Great task to learn the language built-ins.

Approach

  • if you know Kotlin padEnd & chunked you don’t have to think
  • Rust doesn’t allow fmt with dynamic fill character
  • 1 + (size - 1) / k or (k + size - 1) / k will pad to % k
  • Kotln / Java String has CharArray constructor arguments
  • Rust has resize to pad-fill a Vec

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 14ms
    fun divideString(s: String, k: Int, fill: Char) =
        s.chunked(k).map { it.padEnd(k, fill) }



// 9ms
    fun divideString(s: String, k: Int, fill: Char) =
        Array(1 + (s.length - 1) / k) {  s.drop(it * k).take(k).padEnd(k, fill) }



// 8ms
    fun divideString(s: String, k: Int, fill: Char) =
        s.padEnd((1 + (s.length - 1) / k) * k, fill).chunked(k)



// 1ms
    fun divideString(s: String, k: Int, fill: Char): Array<String> {
        val s = s.toCharArray()
        return Array(1 + (s.size - 1) / k) { i ->
            val sz = min(s.size - i * k, k)
            if (sz == k) String(s, i * k, k)
            else {
                val tmp = CharArray(k) { fill }; 
                System.arraycopy(s, i * k, tmp, 0, sz)
                String(tmp)
            }
        }
    }



// 0ms
    pub fn divide_string(s: String, k: i32, fill: char) -> Vec<String> {
        let mut s = s.chars().collect::<Vec<_>>(); let k = k as usize;
        s.resize((1 + (s.len() - 1) / k) * k, fill);
        s.chunks(k).map(|c| c.iter().collect()).collect()
    }



// 0ms
    vector<string> divideString(string s, int k, char fill) {
        vector<string> r(1 + (size(s) - 1) / k, string(k, fill));
        for (int i = 0; i < size(s); ++i) r[i / k][i % k] = s[i];
        return r;
    }


21.06.2025

3085. Minimum Deletions to Make String K-Special medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1026

Problem TLDR

Min remove to make frequencies k-narrow #medium

Intuition

(spent too much time thinking about optimizing 26^2 brute force to 26log(26))

    // calc freq
    // 13579    k=4
    //   *** remove 1 and 3, 4 chars
    // ***55 remove 2 and 4, 6 chars

    // aabcaba
    // a=4 b=2 c=1
    // 1 2 4       k=0
    // * 1 1    remove 1+3=4
    //   * 2    remove 1+2=3 
    //     *    remove 1+2=3
    // optimal way to peek the baseline?
    // prefix sum
    // 1 2 4
    //     4  
    //   6
    // 7
    // baseline:
    // 1   total_right = 6, new_total_right = 2 * 1 = 2, diff=6-2=4
    //   2 left `1` is removed, right=4, new_right=1*2=2, diff=4-2=2, 
    //     4 right=0, left sum=3 is removed
    // actually we only have 26 chars, can brute-force
  • only the frequencies matters

Approach

  • pay attention to the intermediate gathered data size

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 19ms
    fun minimumDeletions(w: String, k: Int): Int {
        val f = IntArray(26); for (c in w) ++f[c - 'a']
        return f.minOf { x -> f.sumOf { if (it < x) it else max(0, it - x - k) }}
    }


// 5ms
    fun minimumDeletions(w: String, k: Int): Int {
        val f = IntArray(26); for (c in w) ++f[c - 'a']
        var res = w.length
        for (x in f) if (x > 0) {
            var remove = 0
            for (f in f) if (f > 0) remove += if (f < x) f else max(0, f - x - k)
            res = min(res, remove)
        }
        return res
    }


// 0ms
    pub fn minimum_deletions(w: String, k: i32) -> i32 {
        let mut f = [0; 26]; for c in w.bytes() { f[(c - b'a') as usize] += 1 }
        (0..26).map(|x| (0..26).map(|c| if f[c] < f[x] { f[c] } else { 0.max(f[c] - f[x] - k)}).sum()).min().unwrap()
    }



// 6ms
    int minimumDeletions(string w, int k) {
        int f[26]={}, r = size(w); for (auto& c: w) ++f[c - 'a'];
        for (int x: f) {
            int remove = 0;
            for (int c: f) remove += c < x ? c: max(0, c - x - k);
            r = min(r, remove);
        } return r;
    }


20.06.2025

3443. Maximum Manhattan Distance After K Changes medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1025

Problem TLDR

Max distance after k flips #medium

Intuition

Used the hints.


    // find final vector dx dy
    // change k negative parts
    // SWWEW    k=1
    //     .    dy=-1
    //   ...    dx=-2
    // order doesn't matter



    // NWSE        . N E     NWNE
    //             . W N
    //             . . .


    // i solved the wrong problem, the MAX is ON the path, not final
    // the order MATTER

  • we have to check each step
  • at each step remove the opposite to the maximum direction

Another clever intuition is min(total, dist + 2k):

  • each flip do +2
  • max flips we can do is total

Approach

  • pay attention to the description, don’t solve the wrong problem

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 86ms
    fun maxDistance(str: String, k: Int): Int {
        var n = 0; var e = 0; var w = 0; var s = 0
        return str.withIndex().maxOf { (i, c) ->
            when (c) { 'N' -> ++n; 'S' -> ++s; 'W' -> ++w; 'E' -> ++e }
            i + 1 - 2 * max(0, minOf(w + s, e + n, w + n, e + s) - k)
        }
    }



// 58ms
    fun maxDistance(str: String, k: Int): Int {
        var res = 0; var n = 0; var e = 0; var w = 0; var s = 0
        for (c in str) {
            when (c) { 'N' -> ++n; 'S' -> ++s; 'W' -> ++w; 'E' -> ++e }
            if (e >= w && n >= s) {
                val bad = max(0, w + s - k)
                val good = w + s - bad
                res = max(res, e + n - bad + good)
            } else if (e < w && n < s) {
                val bad = max(0, e + n - k)
                val good = e + n - bad
                res = max(res, w + s - bad + good)
            } else if (e >= w && n < s) {
                val bad = max(0, w + n - k)
                val good = w + n - bad
                res = max(res, e + s - bad + good)
            } else {
                val bad = max(0, e + s - k)
                val good = e + s - bad
                res = max(res, w + n - bad + good)
            }
        }
        return res
    }



// 90ms
    pub fn max_distance(st: String, k: i32) -> i32 {
        let (mut n, mut e, mut w, mut s) = (0, 0, 0, 0); 
        st.bytes().enumerate().map(|(i, c)| {
            match (c) { b'N' => n += 1, b'S' => s += 1, b'E' => e += 1, _ => w += 1 }
            i as i32 + 1 - 2 * 0.max((w + s).min(e + n).min(w + n).min(e + s) - k)
        }).max().unwrap()
    }



// 32ms
    pub fn max_distance(st: String, k: i32) -> i32 {
        let (mut n, mut e, mut w, mut s, mut r) = (0, 0, 0, 0, 0); 
        for (i, b) in st.bytes().enumerate() {
            match (b) { b'N' => n += 1, b'S' => s += 1, b'E' => e += 1, _ => w += 1 }
            r = r.max(i as i32 + 1 - 2 * 0.max((w + s).min(e + n).min(w + n).min(e + s) - k))
        } r
    }



// 31ms
    pub fn max_distance(st: String, k: i32) -> i32 {
        let (mut x, mut y, mut r) = (0i32, 0i32, 0); 
        for (i, b) in st.bytes().enumerate() {
            match (b) { b'N' => y += 1, b'S' => y -= 1, b'E' => x += 1, _ => x -= 1 }
            r = r.max((i as i32 + 1).min(x.abs() + y.abs() + 2 * k))
        } r
    }



// 22ms
    int maxDistance(string s, int k) {
        int x = 0, y = 0, r = 0, total = 1;
        for (char c: s) {
            y += (c == 'N') - (c == 'S'); x += (c == 'E') - (c == 'W');
            r = max(r, min(total++, abs(x) + abs(y) + 2 * k));
        } return r;
    }


19.06.2025

2294. Partition Array Such That Maximum Difference Is K medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1024

Problem TLDR

k-narrow subsequences #medium #sort

Intuition

Sort, then expand each subsequence as much as possible, the tail with thank you.

Approach

  • we can use bucket sort or a bitset

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n)\)

Code


// 61ms
    fun partitionArray(n: IntArray, k: Int): Int {
        n.sort(); var l = -k - 1
        return n.count { r -> (r - l > k).also { if (it) l = r } }
    }



// 9ms
    fun partitionArray(n: IntArray, k: Int): Int {
        val f = java.util.BitSet(100001); for (x in n) f.set(x)
        var cnt = 0; var l = -k-1; var r = f.nextSetBit(0)
        while (r >= 0) {
            if (r - l > k) { l = r; ++cnt }
            r = f.nextSetBit(r + 1)
        }
        return cnt
    }



// 8ms
    fun partitionArray(n: IntArray, k: Int): Int {
        val f = IntArray(100001); for (x in n) f[x] = x + 1
        var cnt = 0; var l = -k
        for (r in f) if (r - l > k) { l = r; ++cnt }
        return cnt
    }



// 1ms
    pub fn partition_array(n: Vec<i32>, k: i32) -> i32 {
        let (mut f, mut l) = ([0; 100001], -k);
        for x in n { f[x as usize] = x + 1 }
        f.iter().filter(|&&r| { let w = r - l > k; if w { l = r }; w }).count() as _
    }



// 4ms
    int partitionArray(vector<int>& n, int k) {
        bitset<100001>f; int l = -k-1, c = 0;
        for (int x: n) f[x] = 1;
        for (int r = 0; r < 100001; ++r) if (f[r] && r - l > k) ++c, l = r;
        return c;
    }


18.06.2025

2966. Divide Array Into Arrays With Max Difference medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1023

Problem TLDR

List of k-narrow tripplets #medium

Intuition

Sort to minimize distance betwee siblings

Approach

  • Kotlin has a chunked

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(n)\)

Code


// 200ms
    fun divideArray(n: IntArray, k: Int) = n.sorted().chunked(3)
        .takeIf { it.all { it[2] - it[0] <= k }} ?: listOf()



// 23ms
    fun divideArray(n: IntArray, k: Int): Array<IntArray> {
        val f = IntArray(100001); for (x in n) ++f[x]; var x = 0
        val r = Array(n.size / 3) { IntArray(3) }
        for (r in r) {
            while (f[x] < 1) ++x; --f[x]; r[0] = x; val m = k + x
            while (x < m && f[x] < 1) ++x; --f[x]; r[1] = x
            while (x < m && f[x] < 1) ++x; --f[x]; r[2] = x
            if (f[x] < 0) return emptyArray()
        }
        return r
    }



// 3ms
    pub fn divide_array(mut n: Vec<i32>, k: i32) -> Vec<Vec<i32>> {
        n.sort_unstable(); n.chunks(3)
        .map(|c| if c[2] - c[0] > k { None } else { Some(c.to_vec()) })
        .collect::<Option<_>>().unwrap_or_default()
    }



// 0ms
    vector<vector<int>> divideArray(vector<int>& n, int k) {
        vector<vector<int>> r; sort(begin(n), end(n));
        for (int i = 0; i < size(n); i += 3) 
            if (n[i + 2] - n[i] > k) return {};
            else r.push_back({n[i], n[i + 1], n[i + 2]});
        return r;
    }


17.06.2025

3405. Count the Number of Arrays with K Matching Adjacent Elements hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1022

Problem TLDR

Combinations k equal siblings 1..m in [n] array #hard #combinatorics #math

Intuition

Didn’t solve. Some thougths:

    // n = 4, m = 2, k = 2
    // [1, 1, 1, 2], [1, 1, 2, 2], [1, 2, 2, 2], [2, 1, 1, 1], [2, 2, 1, 1] [2, 2, 2, 1]
    // dp[i] = (1..m).sum { a  (1..m).sum { b  (a == b) + dp[i + 2] } }
    // 10^5 x 10^5 will give TLE/MLE
    // combinatorics? all perimutations excluding the banned
    // 1 1 2  1 2 2  2 1 1  2 2 1 k = 1
    // 1 2 1         2 1 2        k = 0  ban
    // 1 1 1         2 2 2        k = 2  ban
    //                            k max = n - 1
    // (0..kMax) = all perm "111".toString(2)
    // stil don't know how to count perm for each `k`
    // hints are pointing to the DP, but how it is not TLE?
    // (26 minute, give up, its combinatorics)
    // m * C(n - 1, k) * (m - 1) ** (n - 1 - k)

If I understood it right:

  • stars and bars: the bars are equal parts, we have k of them on n-1 positions: C(n-1,k)
  • first is 1..m
  • the stars can be 1..m - 1(prev) at (n-1) - k positions (after bars are placed): (m-1)^(n-1-k)

Approach

  • this time I recognized my inability to solve combinatorics much faster than 1 hour (26 minute gave up)
  • memoize a^b % m: it is derived from math a ^ b = (a^2)^(b/2) * a^(b%2), b /= 2, a = a * a
  • memoize combinations nCr (n choose r): n!/(n-r)!r! = (1..n)/(1..r)(1..n-r) = (1..n)/(1..n-r) / (1..r) = (n-r+1)..n/1..r
  • memoize how to calculate this with % M: Fermat theorem x^(m-1)=1 %m is eq x^(m-2)=x^-1 %m, so 1/1..r % m is eq (1..r)^m-2 % m or den^-1 % m = den^(m-2) %m https://en.wikipedia.org/wiki/Fermat%27s_little_theorem
  • of course it is impossible for me to solve without some huge investment into combinatorics theory, but some tricks are worth to learn

Complexity

  • Time complexity: \(O(nlogn)\)

  • Space complexity: \(O(1)\)

Code


// 28ms
    fun countGoodArrays(n: Int, m: Int, k: Int): Int {
        val M = 1_000_000_007; val m = 1L * m; var nCr = 1L; var den = 1L
        fun pow(a: Long, b: Int): Long =
            if (b == 0) 1L else (pow((a * a) % M, b / 2) * if (b % 2 > 0) a else 1) % M
        for (i in 1..k) { nCr = (nCr * (n - i)) % M; den = (den * i) % M }
        nCr = (nCr * pow(den, M - 2)) % M
        return ((((m * nCr) % M) * pow(m - 1, n - k - 1)) % M).toInt()
    }



// 28ms
    pub fn count_good_arrays(n: i32, m: i32, k: i32) -> i32 {
        let (M, n, m, k, mut nCr, mut den) = (1_000_000_007, n as i64, m as i64, k as i64, 1, 1); 
        fn pow(a: i64, b: i64, M: i64) -> i64 {
            if b == 0 { 1 } else { (pow((a * a) % M, b / 2, M) * if (b % 2 > 0) { a } else { 1 }) % M }
        }
        for i in 1..=k { nCr = (nCr * (n - i)) % M; den = (den * i) % M }
        nCr = (nCr * pow(den, M - 2, M)) % M;
        ((((m * nCr) % M) * pow(m - 1, n - k - 1, M)) % M) as i32
    }



// 25ms
#define M 1000000007
int countGoodArrays(int n, int m, int k) {
    auto p = [](long a, long b) {
        long r = 1;
        while (b) { if (b & 1) r = r * a % M; a = a * a % M; b >>= 1; }
        return r;
    };
    long x = 1, y = 1;
    for (int i = 1; i <= k; ++i) { x = x * (n - i) % M; y = y * i % M; }
    return x * p(y, M - 2) % M * m % M * p(m - 1, n - k - 1) % M;
}


16.06.2025

2016. Maximum Difference Between Increasing Elements easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1021

Problem TLDR

Max increasing pair diff #easy

Intuition

Brute-force works. Or, compute running min and search max(current - min).

Approach

  • shortest code can be the optimal too

Complexity

  • Time complexity: \(O(n^2)\), or O(n)

  • Space complexity: \(O(1)\)

Code


// 78ms
    fun maximumDifference(n: IntArray) =
        (0..<n.lastIndex).maxOf { i -> n.drop(i + 1).maxOf { it - n[i] }}
        .takeIf { it > 0 } ?: -1



// 37ms
    fun maximumDifference(n: IntArray) =
        (0..<n.lastIndex).maxOf { i -> 
        (i + 1..<n.size).maxOf { j -> n[j] - n[i] }}
        .takeIf { it > 0 } ?: -1



// 3ms
    fun maximumDifference(n: IntArray) =
        n.fold(n[0] to 0) { (m, r), t -> min(t, m) to max(r, t - m) }
        .second.takeIf { it > 0 } ?: -1



// 1ms
    fun maximumDifference(n: IntArray): Int {
        var min = n[0]; var r = 0
        for (x in n) {
            r = max(r, x - min)
            min = min(min, x)
        }
        return if (r > 0) r else -1
    }



// 0ms
    pub fn maximum_difference(n: Vec<i32>) -> i32 {
        let x = n.iter().fold((0, n[0]), |(r, m), &x| (r.max(x - m), m.min(x))).0;
        if x > 0 { x } else { -1 }
    }



// 0ms
    int maximumDifference(vector<int>& n) {
        int r = 0, m = n[0];
        for (int x: n) r = max(r, x - m), m = min(m, x);
        return r > 0 ? r : -1;
    }


15.06.2025

1432. Max Difference You Can Get From Changing an Integer medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1020

Problem TLDR

Max - min, replacing any digit, no leading zeros #medium

Intuition

The brute force is fast enough. More optimized:

  • max is first non-nine replaced by 9
  • min is if first is non-one, replace by 1
  • else first non-zero replaced by 0 BUT

Approach

  • also can be solved without convertion to strings

Complexity

  • Time complexity: \(O(1)\), 10 digits, 10x10 runs, total is 1000 operations; 10 ops for optimized

  • Space complexity: \(O(1)\)

Code


// 12ms
    fun maxDiff(n: Int): Int {
        var max = n; var min = n
        for (a in "$n") for (b in "0123456789") {
            val x = "$n".replace(a, b)
            if (x == "0" || x[0] == '0') continue
            max = max(max, x.toInt())
            min = min(min, x.toInt())
        }
        return max - min
    }



// 8ms
    fun maxDiff(n: Int) =
        "$n".replace("$n".find { it != '9' } ?: '.', '9').toInt() -
        if ("$n"[0] > '1') "$n".replace("$n"[0], '1').toInt()
        else "$n".replace("$n".find { it != "$n"[0] && it > '0' } ?: '.', '0').toInt()




// 0ms
    pub fn max_diff(n: i32) -> i32 {
        let (s, mut a, mut b) = (n.to_string(), n, n);
        for c in s.chars() {
            for d in '0'..='9' {
                let x: String = s.chars().map(|x| if x == c { d } else { x }).collect();
                if x == "0" || x.starts_with("0") { continue }
                let x = x.parse().unwrap();
                a = a.max(x); b = b.min(x)
            }
        } a - b
    }



// 0ms
    int maxDiff(int n) {
        string s = to_string(n);
        int a = n, b = n;
        for (char c: s) for (char d = '0'; d <= '9'; ++d) {
            string t = s;
            for (char& x: t) if (x == c) x = d;
            if (t == "0" || t[0] == '0') continue;
            int x = stoi(t); a = max(a, x); b = min(b, x);
        } return a - b;
    }


14.06.2025

2566. Maximum Difference by Remapping a Digit easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1019

Problem TLDR

Max - min, replacing any digit #easy

Intuition

Brute-force: replace any digit to any other digit, no thinking. Brute-force2: replace any digit to ‘9’ for max, and to ‘0’ for min, small thinking. Galaxy brain: replace first non-nine to nine for max, first non-zero to zero for min.

Approach

  • we can do this in one forward pass by dividing 10^8 / 10
  • instead of min and max compute diff
  • we can use two arraya of transformations or just to variables to check

Complexity

  • Time complexity: \(O(1)\), 10 digits, 10x10 runs, total is 1000 operations; 10 ops for optimized

  • Space complexity: \(O(1)\)

Code


// 12ms
    fun minMaxDifference(n: Int) =
        ('0'..'8').maxOf { "$n".replace(it, '9').toInt() } - 
        "$n".replace("$n"[0], '0').toInt()



// 8ms
    fun minMaxDifference(n: Int) =
        "$n".replace("$n".find { it != '9'} ?: '9', '9').toInt() - 
        "$n".replace("$n"[0], '0').toInt()


// 0ms
    fun minMaxDifference(num: Int): Int {
        var n = num; var pow = 100000000; var diff = 0
        while (n > 0 && n / pow == 0) pow /= 10
        var nine = 9; val zero = n / pow
        while (pow > 0) {
            val d = n / pow
            if (nine == 9 && d != 9) nine = d
            diff = diff * 10 + (if (d == nine) 9 else d) - (if (d == zero) 0 else d)
            n -= d * pow; pow /= 10
        }
        return diff
    }


// 0ms
    pub fn min_max_difference(mut n: i32) -> i32 {
        let mut p = 100000000; while n > 0 && n / p == 0 { p /= 10 }
        let (mut nine, zero, mut diff) = (9, n / p, 0);
        while p > 0 {
            let d = n / p; n -= d * p; p /= 10; diff *= 10;
            if nine == 9 && d != 9 { nine = d }
            diff += (if d == nine { 9 } else { d }) -
                     if d == zero { 0 } else { d }
        } diff
    }



// 0ms
    int minMaxDifference(int n) {
        auto s = to_string(n), t = s; int m = 0;
        for (char c = '0'; c <= '9'; ++c) {
            t = s; for (char& x: t) if (x == c) x = '9';
            m = max(m, stoi(t));
        }
        t = s; for (char& x: t) if (x == s[0]) x = '0';
        return m - stoi(t);
    }


13.06.2025

2616. Minimize the Maximum Difference of Pairs medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1018

Problem TLDR

Min max diffs non-overlapped pairs #medium #binary_search

Intuition

Didn’t solve.

    // 1 1 2 3 7 10 10
    // a a b b
    // * x * x   b  b
    //   a a
    //   * x
    // take `p` min diffs
    // 1 1 1 2
    // * .
    //   *
    //     *
    // how to deal with overlaps? maybe gredily skip
    // 18 minute 1, 2, 2, 2, 3, 3, 4 wrong result
    //              a  a     b  b
    // hint1 use DP
    // 36 minute: all hints+TLE
    // 43 minute MLE the hint was misleading
    // hint: binarysearch    (again overlapping pairs?)
    // 54 minute, giveup (ok, missing idea was to solve overlaps by greedily take)

The working hint:

  • binary search of the max allowed diff
  • take diffs greedily from a sorted order

Approach

  • we can skip abs
  • exit early on cnt >= p
  • there is an actual DP solution without MLE

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(1)\)

Code


// 31ms
    fun minimizeMax(n: IntArray, p: Int): Int {
        n.sort(); var lo = 0; var hi = n[n.size - 1] - n[0]
        while (lo <= hi) {
            val m = (lo + hi) / 2; var cnt = if (n[n.size - 1] - n[0] <= m) 1 else 0; var i = 1
            while (i < n.size) 
                if (n[i] - n[i - 1] > m) i++ else if (++cnt >= p) break else i += 2
            if (cnt >= p) hi = m - 1 else lo = m + 1
        }
        return lo
    }



// 7ms
    pub fn minimize_max(mut n: Vec<i32>, p: i32) -> i32 {
        n.sort_unstable(); let (mut lo, mut hi, l) = (0, n[n.len() - 1] - n[0], n.len());
        while lo <= hi {
            let m = (lo + hi) / 2; let (mut cnt, mut i) = ((m >= n[l - 1] - n[0]) as i32, 1);
            while i < l {
                if m >= n[i] - n[i - 1] 
                    { cnt += 1; i += 2; if cnt >= p { break }} else { i += 1 }}
            if cnt >= p { hi = m - 1 } else { lo = m + 1 }
        } lo
    }



// 22ms
    int minimizeMax(vector<int>& n, int p) {
        sort(begin(n), end(n));
        int l = size(n), lo = 0, ld = n.back() - n[0]; int hi = ld;
        while (lo <= hi) {
            int m = (lo + hi) / 2; int c = ld <= m, i = 1;
            while (i < l) if (n[i] - n[i - 1] > m) i++;
                else if (++c >= p) break; else i += 2;
            if (c >= p) hi = m - 1; else lo = m + 1;
        } return lo;
    }


12.06.2025

3423. Maximum Difference Between Adjacent Elements in a Circular Array easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1017

Problem TLDR

Max abs sibling diff #easy

Intuition

There are many surprising ways to write that code, try all of them.

Approach

  • kotlin’s last() makes runtime worse 12ms vs 1ms of n[n.size - 1]
  • we can windowed
  • we can zip
  • we can zip with 0..100
  • we can minimize the array reading

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 24ms
    fun maxAdjacentDistance(n: IntArray) =
        n.zip(n.drop(1) + n[0]).maxOf { (a, b) -> abs(a - b) }



// 22ms
    fun maxAdjacentDistance(n: IntArray) =
        (n + n[0]).asList().windowed(2).maxOf { abs(it[0] - it[1]) }



// 17ms
    fun maxAdjacentDistance(n: IntArray) = 
        n.indices.maxOf { abs(n[(it + 1) % n.size] - n[it]) }



// 15ms
    fun maxAdjacentDistance(n: IntArray) =
        n.zip(intArrayOf(n.last()) + n).maxOf { (a, b) -> abs(a - b) }



// 11ms
    fun maxAdjacentDistance(n: IntArray): Int {
        var r = abs(n[0] - n.last())
        for (i in 1..<n.size) r = max(r, abs(n[i] - n[i - 1]))
        return r
    }



// 1ms
    fun maxAdjacentDistance(n: IntArray): Int {
        var r = abs(n[0] - n[n.size - 1])
        for (i in 1..<n.size) r = max(r, abs(n[i] - n[i - 1]))
        return r
    }



// 0ms
    pub fn max_adjacent_distance(n: Vec<i32>) -> i32 {
       (0..n.len()).map(|i| (n[(i + 1) % n.len()] - n[i]).abs()).max().unwrap() 
    }


// 0ms
    pub fn max_adjacent_distance(n: Vec<i32>) -> i32 {
        (0..100).zip([&n[1..], &n[..1]].concat())
        .map(|(a, b)| (n[a] - b).abs()).max().unwrap()
    }



// 0ms
    int maxAdjacentDistance(vector<int>& n) {
        int r = 0, p = n[size(n) - 1];
        for (int x: n) r = max(r, abs(p - x)), p = x;
        return r;
    }


11.06.2025

3445. Maximum Difference Between Even and Odd Frequency II hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1016

Problem TLDR

Max odd - min even frequency, window at least k #hard

Intuition

Didn’t solve.

Irrelevant chain-of-thoughts:

    // 0 1 2 3 4   odd-even
    //
    // 1111122    at least k
    //         3-2 k=6
    // small number of digits, maybe solve for each pair
    // even should be the smallest = 2
    // odd should be the largest BUT substring length >= k (so can't shrink less than k to make odd)
    // for every two numbers ..a...a... find the best start..end for odds
    // this is O(n^2) algo, as the window size k up to n
    // can we do it in a one go?
    // 112211221122
    //     eeo        for example consider those even positions
    //    oee         odds with different lengths
    //   ooeeo
    //    oeeoo
    //   ooeeooeeo adds two more evens, no gaps allowed
    //    oeeooeeoo adds two more evens, no gaps allowed
    //                                                                  (17 minute)
    //      eooeo
    // can optimal evens be more than 2?
    // 111112222111111    5-2=3 vs 11-4=5 yes
    // 5    2 2 6
    // ok, maybe FIX the window size and binary search it? - will not work, no criteria for binary search
    //                                                                   (26 minute, 0 lines of code)
    // idea: the only reason to shrink window is to make odd from even   (29 minute)
    //       or, maybe to decrease even frequency                        (33 minute)
    // ok, look for hints, no working ideas yet
    // hint1: fix 2 chars (kind of was close)
    // hint2: prefix sum
    //
    // 111111222211111    5-2=3 vs 11-4=5 yes
    // 6     2 2 5
    //             but how to use the prefix sum?                        (56 minute)
    // (60 minute, give up look for solution)
    // a odd b odd  complementary to   a odd  b even, a even b odd
    // a odd b even complementary to   a even b even, a odd b odd
    // a even b odd complementary to   a even b even, a odd b odd
    // a even b even complementary to  a odd b even, a even b odd  (but what about k?, 75 minute)

The missing part for me even after hints was how to shrink the window. Basically, we moving until last a or b, shrinking to size of 2: aa or bb but preserving at least k.

The working solution:

  • for every pair of digits a and b
  • compute prefix sum of frequencies fa, fb
  • and maintain sliding window with left pointer j
  • move j while window at least k and until fa[j] == fa   fb[j] == fb (until last a or b)
  • compute diff and put to seen[key]=diff, key is a mask of parity (a%2, b%2)
  • then the current complementary key is inversion of parity (1 - fa%2)
  • and diff = diff - complementary_diff

Approach

  • felt close, but not enough
  • the rule for shrinking window is crucial here; why shrink to size of 2 gives optimal, and don’t make worse other pointer expansion?
  • the initial condition to prefixes array is tricky, use sentinel 0 at start
  • rotate a b and b a to simplify complementary state matching
  • store the diff=fa[j]-fb[j] in seen instead of indices, and we have to subtract it as complementary
  • or we can skip the prefix array entirely, as we only interested in the latest count

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 54ms
    fun maxDifference(s: String, k: Int): Int {
        var res = -s.length
        for (a in "01234") for (b in "01234") if (a != b) {
            val fa = IntArray(s.length + 1); val fb = IntArray(s.length + 1)
            val seen = IntArray(4) { s.length }; var j = 0
            for ((i, c) in s.withIndex()) {
                val l = i + 1; fa[l] = fa[i]; fb[l] = fb[i]
                if (c == a) ++fa[l]; if (c == b) ++fb[l]
                while (j <= i - k + 1 && fb[j] < fb[l]) {
                    val key = (fa[j] % 2) * 2 + (fb[j] % 2)
                    seen[key] = min(fa[j] - fb[j], seen[key])
                    j++
                }
                res = max(res, fa[l] - fb[l] - seen[(1 - fa[l] % 2) * 2 + (fb[l] % 2)])
            }
        }
        return res
    }



// 26ms
    pub fn max_difference(s: String, k: i32) -> i32 {
        let (k, s, n, mut r) = (k as usize, s.as_bytes(), s.len(), -(s.len() as i32));
        for &a in b"01234" { for &b in b"01234" { if a == b { continue; }
            let (mut fa, mut pa, mut fb, mut pb, mut seen, mut j) = 
                (0, 0, 0, 0, vec![n as i32; 4], 0);
            for (i, &c) in s.iter().enumerate() {
                fa += (c == a) as i32; fb += (c == b) as i32;
                while j + k <= i + 1 && fb >= 2 + pb {
                    let key = ((pa % 2) * 2 + (pb % 2)) as usize;
                    seen[key] = seen[key].min(pa - pb);
                    pa += (s[j] == a) as i32; pb += (s[j] == b) as i32;
                    j += 1;
                }
                r = r.max(fa - fb - seen[((1 - fa % 2) * 2 + (fb % 2)) as usize]);
        }}} r      
    }



// 39ms
    int maxDifference(string s, int k) {
        int n = s.size(), r = -n;
        for (char a : {'0','1','2','3','4'})
        for (char b : {'0','1','2','3','4'}) if (a != b) {
            int fa = 0, fb = 0, pa = 0, pb = 0, j = 0, seen[4] = {n,n,n,n};
            for (int i = 0; i < n; ++i) {
                fa += s[i] == a; fb += s[i] == b;
                while (j + k <= i + 1 && fb >= pb + 2) {
                    int key = pa % 2 * 2 + pb % 2;
                    seen[key] = min(seen[key], pa - pb);
                    pa += s[j] == a; pb += s[j] == b; ++j;
                }
                int key = (1 - fa % 2) * 2 + fb % 2;
                r = max(r, fa - fb - seen[key]);
            }
        } return r;
    }


10.06.2025

3442. Maximum Difference Between Even and Odd Frequency I easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1015

Problem TLDR

Max odd - min even frequency #easy

Intuition

Find all frequencies, then do the search.

Approach

  • use built-in methods like groupBy
  • compare with hand-crafted iterative code performance

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 24ms
    fun maxDifference(s: String) = s.groupingBy { it }
      .eachCount().values.groupBy { it % 2 }
      .let { it[1]!!.max() - it[0]!!.min() }



// 23ms
    fun maxDifference(s: String) = s.groupingBy { it }
      .eachCount().values.partition { it % 2 > 0 }
      .let { (a, b) -> a.max() - b.min() }



// 8ms
    fun maxDifference(s: String) = s.groupBy { it }.values
      .groupBy { it.size % 2 }
      .let { it[1]!!.maxOf { it.size } - it[0]!!.minOf { it.size } }



// 7ms
    fun maxDifference(s: String) = with(s.groupBy { it }.values) {
        filter { it.size % 2 > 0 }.maxOf { it.size } - 
        filter { it.size % 2 < 1 }.minOf { it.size }
    }



// 6ms
    fun maxDifference(s: String) = with(s.groupBy { it }.values) {
        maxOf { (it.size % 2) * it.size } - 
        minOf { it.size + (it.size % 2) * (99 - it.size) }
    }



// 1ms
    fun maxDifference(s: String): Int {
        val f = IntArray(26); for (c in s) ++f[c - 'a']
        var a = 0; var b = s.length
        for (f in f) if (f > 0)
            if (f % 2 > 0) a = max(f, a) else b = min(f, b)
        return a - b
    }



// 0ms
    pub fn max_difference(mut s: String) -> i32 {
        let (mut a, mut b, mut f) = (0, 99, [0; 26]);
        for b in s.bytes() { f[(b - b'a') as usize] += 1 }
        for f in f { if (f > 0 && f % 2 < 1) { b = b.min(f) } else { a = a.max(f) }} 
        a - b
    }



// 0ms
    pub fn max_difference(mut s: String) -> i32 {
        let mut s = unsafe { s.as_bytes_mut() }; s.sort_unstable();
        let (a, b): (Vec<_>, Vec<_>) = s[..].chunk_by(|a, b| a == b)
        .map(|c| c.len()).partition(|l| l % 2 > 0);
        (a.iter().max().unwrap() - b.iter().min().unwrap()) as _
    }



// 0ms
    int maxDifference(string s) {
        int f[26]={}, a = 0, b = 99;
        for (auto c: s) ++f[c - 'a'];
        for (int c: f) if (c > 0 && !(c & 1)) b = min(b, c); else a = max(a, c);
        return a - b;
    }


09.06.2025

440. K-th Smallest in Lexicographical Order hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1014

Problem TLDR

k-th lexicographical number of 1..n #hard

Intuition

Didn’t solve. (previous attempt were passed but not optimal https://leetcode.com/problems/k-th-smallest-in-lexicographical-order/solutions/5819960/kotlin-rust/)

// generate all - will give TLE, 10^9 range
    // [1, 10, 
    //        100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 
    //     11, 
    //        110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 
    //     12, 
    //        120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 
    //     13, 
    //        130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 
    //     14, 
    //        140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 
    //     15, 
    //        150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 
    //     16, 
    //        160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 
    //     17, 
    //        170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 
    //     18, 
    //        180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 
    //     19, 
    //        190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 
    // 2, 20, 
    //        200, 
    //        21, 22, 23, 24, 25, 26, 27, 28, 29, 
    // 3, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 
    // 4, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 
    // 5, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 
    // 6, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 
    // 7, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 
    // 8, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 
    // 9, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
    // (8 minute) no ideas
    // ok, let's try brute-force maybe it will be fast enough
    // (15 minute) TLE n = 957747794  k = 424238336
    // from hints: look for digits in n to form a subtree
    // 1 - subtree of 1 has size of sz1 (110)
    // 2 - subtree of 2 has size of sz2 (10 + 1), 200=200, 1 extra child
    // 3 - subtree of 3 has size of sz3 (10)  300 bigger than 200, no extra
    // 4 - subtree of 4 has size of sz4 (10)
    // ...
    // 9 - subtree of 9 has size of sz9 (10)
    // 
    // then remove first digit and go deeper at 1 (the first digit of solution k = 3,n=200)
    // 10 - (10) 
    // 11 - (10)
    // ...
    // 19 - (10)
    // then go deeper at 10 (the second digit of solution k = 3-1=2, n=20)
    // 100 - (0) the third digit of solution, k = 2-1=1, n= 2? (how to adjust n?)
    // 101 - (0)
    // ...
    // 109 - (0)
    // (50 minute) still didn't know how to adjust n
    // 54 look for solution

The solution:

  • start with root of the tree x = 1
  • calculate subtree size from..to by doing from *= 10, to = to * 10 + 9
  • if i + count > k, we found the digit, go deeper subtree x *= 10
  • if i + count <= k, skip the node x++, i += count

Approach

  • the previous approach of just stealing the solution didn’t give good results as I am unable to solve it again; better spend more time to understand the logic

Complexity

  • Time complexity: \(O(lg(n)lg(k))\)

  • Space complexity: \(O(1)\)

Code


// 0ms
    fun findKthNumber(n: Int, k: Int): Int {
        var x = 1L; var i = 1; var n = n.toLong(); var k = k.toLong()
        while (i < k) {
            var cnt = 0L; var from = x; var to = x
            while (from <= n) {
                cnt += min(to, n) - from + 1
                from *= 10; to = to * 10 + 9
            }
            if (i + cnt <= k) { i += cnt.toInt(); x++ } else { i++; x *= 10 }
        }
        return x.toInt()
    }



// 0ms
    pub fn find_kth_number(n: i32, k: i32) -> i32 {
        let (mut x, n, mut k) = (1i64, n as i64, k as i64);
        while k > 1 {
            let (mut skip, mut from, mut to) = (0, x, x);
            while from <= n {
                skip += to.min(n) - from + 1;
                from *= 10; to = to * 10 + 9
            }
            if k - skip < 1 { k -= 1; x *= 10 } else { k -= skip; x += 1 }
        } x as _
    }



// 0ms
    int findKthNumber(int n, int k) {
        long long x = 1; k--;
        while (k) {
            long long skip = 0, from = x, to = x;
            while (from <= n)
                skip += min(to, 1LL * n) - from + 1,
                from *= 10, to = to * 10 + 9;
            if (k - skip < 0) --k, x *= 10; else ++x, k -= skip;
        } return (int) x;
    }

08.06.2025

386. Lexicographical Numbers medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1013

Problem TLDR

Generate lexicographical numbers 1..n #medium

Intuition

    // 1 10 100 1000 11 12 120 2 20 200 21

There is a DFS pattern in the order: 1, 2, 3 are the headers, with fillers in-between.

Approach

  • the iterative variant is clever: go deep by *10, then increment, then remove all zeros
  • by rewriting the order, some interesting implementations are possible, like runningFold/scan

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 22ms
    fun lexicalOrder(n: Int) = buildList<Int> {
        var x = 1
        repeat(n) {
            add(x)
            if (x * 10 <= n) x *= 10
            else {
                if (x == n) x /= 10
                x++
                while (x % 10 == 0) x /= 10
            }
        }
    }



// 19ms
    fun lexicalOrder(n: Int) = buildList<Int> {
        fun dfs(p: Int) {
            if (p > n) return@dfs
            add(p); for (d in 0..9) dfs(p * 10 + d)
        }
        for (d in 1..9) dfs(d)
    }



// 18ms
    fun lexicalOrder(n: Int) =
        (1..<n).runningFold(1) { r, t -> var x = r
            if (x * 10 <= n) x *= 10
            else {
                if (x == n) x /= 10
                x++
                while (x % 10 == 0) x /= 10
            }
            x
        }



// 6ms
    fun lexicalOrder(n: Int): List<Int> {
        var x = 0
        return List<Int>(n) {
            if (x > 0 && x * 10 <= n) x *= 10
            else {
                if (x == n) x /= 10
                x++
                while (x % 10 == 0) x /= 10
            }
            x
        }
    }



// 0ms
    pub fn lexical_order(n: i32) -> Vec<i32> {
        (0..n).scan(0, |x, t| {
            if *x > 0 && *x * 10 <= n { *x *= 10 }
            else {
                if *x == n { *x /= 10 }
                *x += 1;
                while *x % 10 == 0 { *x /= 10 }
            }; Some(*x)
        }).collect()
    }



// 1ms
    vector<int> lexicalOrder(int n) {
        int x = 1; vector<int>r(n);
        for (int i = 0; i < n; ++i) {
            r[i] = x;
            if (x * 10 <= n) x *= 10;
            else {
                if (x == n) x /= 10;
                ++x;
                while (x % 10 == 0) x /= 10;
            }
        } return r;
    }


07.06.2025

3170. Lexicographically Minimum String After Removing Stars medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1012

Problem TLDR

Smallest string by remove min to the left of * #medium

Intuition

    // aab*b*c*c*
    //  . *         should go left to right
    // .    *
    //     .  *
    //   .      *

We have to remove rightmost of the smallest.

Approach

  • track indices
  • can use a heap

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 381ms
    fun clearStars(s: String): String {
        val a = s.toCharArray()
        val q = PriorityQueue<Int>(compareBy({ s[it] }, { -it }))
        for (i in s.indices) if (a[i] == '*') a[q.poll()] = '*' else q += i
        return a.filter { it != '*' }.joinToString("")
    }



// 60ms https://leetcode.com/problems/lexicographically-minimum-string-after-removing-stars/submissions/1656351997
    fun clearStars(s: String): String {
        val a = s.toCharArray(); var j = 0; var k = 26
        val f = Array(26) { ArrayList<Int>() }
        for (i in s.indices) if (a[i] == '*') {
            a[f[k].removeLast()] = '*'
            while (k < 26 && f[k].size == 0) k++
        } else { f[a[i] - 'a'] += i; k = min(k, a[i] - 'a') }
        for (i in a.indices) if (a[i] != '*') a[j++] = a[i]
        return String(a, 0, j)
    }



// 19ms
    pub fn clear_stars(mut s: String) -> String {
        let (mut b, mut k, mut f) = (unsafe { s.as_bytes_mut() }, 26, vec![vec![]; 26]);
        for i in 0..b.len() {
            if b[i] == b'*' {
                b[f[k].pop().unwrap()] = b'*';
                while k < 26 && f[k].len() == 0 { k += 1 }
            } else { let b = (b[i] - b'a') as usize; f[b].push(i); k = k.min(b) }}
        s.retain(|c| c != '*'); s
    }



// 29ms
    string clearStars(string s) {
        array<vector<int>, 26> f; int k = 26;
        for (int i = 0; i < size(s); ++i)
            if (s[i] != '*') f[s[i] - 'a'].push_back(i), k = min(k, s[i] - 'a');
            else { s[f[k].back()] = '*'; f[k].pop_back(); while (k < 26 && !size(f[k])) ++k; }
        erase(s, '*'); return s;
    }


06.06.2025

2434. Using a Robot to Print the Lexicographically Smallest String medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1011

Problem TLDR

Smallest string by writing to stack #medium #string

Intuition

Kind of solved myself.

Chain-of-thougths:

    // bac
    //       b
    //       ba
    //           ab
    //       c
    //           abc

    // bddac           -> ac ddb
    //      bd
    //          db
    //      da
    //          dbad
    //          dbadc
    //          db ad c  so, we can rotate any part of the string
    //                       but only once, non-intersecting
    //                       and can swap intervals
    //                       how to do it in O(n) and optimally?
    //                       (11 minute)
    //       bdda
    //            a
    //       bddc
    //            ac
    //            acddb

    // bddacab
    //      *  -> abcaddb (wrong), aabcddb is correct, hot to get it?
    //     bdd  a
    //     bddc aa
    //     bddc aab
    //     ok, so it looks like we can skip any chars
    //         and skipped chars would be the prefix (reversed)
    //         (19 minute)
    //  abcabcbcadac
    //                 what the strategy for skipping?
    //                 let's take all 'a''s
    //  bcbcbcdc aaaa -> aaaa cdcbcbcb   looks like it works 
    //                                   (21 minute)
    //  ok, it is not working for "bac" -> abc
    //                             we can leave all the suffix
    //  bacaaccccbbb  
    //  bc aaa ccccbbb, after the last 'a' we do the same for suffix
    //  cb     cccc bbb    
    //         bbb cccc
    //  aaa bbb cccc cb 

    // bacaabccbeb -> aaa bbb e ccc b
    // bc aaa bccbeb
    //        cce bbb
    // bc cce
    //    aaa bbb ecc cb   (32 minute)

    // ok, 40 minute, "bac" wrong (acb instead of abc)
    // the strategy was wrong, after 'a' better to take 'b' then 'c'

    // 45 minute, another corner case "vzhofnpo"
    // look for hints
    // hint1: knew
    // hint2: knew
    // hint3: knew, so it is all about the implementation details

    // vzhofnpo    abcdefghijklmnopqrstuvwxyz
    //     *. .         *       ..            vzho    f
    //   *  . .           *     .. 
    //      * .                 *.            vzho    fn
    //        *                  *            vzh     fno
    //                                        vzhp    fnoo > fnoh (57 minute)
    //        *                  *            vzh     fno

    // (62 minute) TLE (and I'm happy)

Observations:

  • take the smallest chars first
  • take all the current chars, skip others adding them to stack, stop at the rightmost
  • increment the current char
  • before going to the right, get all the smaller chars from the stack

Another solutions from u/votrubac/ is counting:

  • build the frequencies
  • put every char to stack as you go
  • if all current chars are taken, drain all the smaller chars from the stack

Approach

  • strictly synchronize variables, current char and its index
  • attention to the order of operations: before increment, increment current, after increment
  • we can write for c in s or for c in 'a'..'z' for the same algorithm

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 68ms
    fun robotWithString(s: String) = buildString {
        val ix = IntArray(26) { -1 }; val t = Stack<Char>()
        var c = 'a'; for (i in s.indices) ix[s[i] - 'a'] = i
        for (i in 0..s.length) {
            while (ix[c - 'a'] < i && ++c <= 'z')
                while (t.size > 0 && t.last() <= c) append(t.pop())
            if (i < s.length) if (s[i] == c) append(c) else t += s[i]
        }
    }



// 63ms
    fun robotWithString(s: String) = buildString {
        val idx = IntArray(26) { -1 }; val t = ArrayList<Char>()
        var i = 0; for (i in s.indices) idx[s[i] - 'a'] = i
        for (c in 'a'..'z') {
            while (t.size > 0 && t.last() <= c) append(t.removeLast())
            while (i <= idx[c - 'a']) {
                if (s[i] == c) append(c) else t += s[i]
                i++
            }
        }
        while (i < s.length) t += s[i++]
        for (i in t.lastIndex downTo 0) append(t[i])
    }



// 50ms
    fun robotWithString(s: String) = buildString {
        val f = IntArray(26); for (c in s) ++f[c - 'a']
        var j = 0; val t = ArrayList<Char>()
        for (c in s) {
            t += c; --f[c - 'a']
            while (j < 25 && f[j] < 1) ++j
            while (t.size > 0 && t.last() <= 'a' + j) append(t.removeLast())
        }
    }



// 44ms
    fun robotWithString(s: String) = buildString {
        val ix = IntArray(27) { -1 }; val t = ArrayList<Char>()
        var c = 'a' - 1; for (i in s.indices) ix[s[i] - 'a'] = i
        var j = -1; ix[26] = s.length
        for ((i, si) in s.withIndex()) {
            while (j < i) {
                c++; j = ix[c - 'a']
                while (t.size > 0 && t.last() <= c) append(t.removeLast())
            }
            if (si == c) append(c) else t += si
        }
        for (i in t.lastIndex downTo 0) append(t[i])
    }


// 9ms
    pub fn robot_with_string(s: String) -> String {
        let mut f = [0; 26]; for b in s.bytes() { f[(b - b'a') as usize] += 1 }
        let (mut j, mut t, mut r) = (0, vec![], String::new());
        for b in s.bytes() {
            t.push(b); f[(b - b'a') as usize] -= 1;
            while j < 25 && f[j] < 1 { j += 1 }
            while t.len() > 0 && t[t.len() - 1] <= b'a' + j as u8 { r.push(t.pop().unwrap() as char) }
        } r
    }



// 48ms
    string robotWithString(string s) {
        int f[26]={}, j = 0; string r, t;for (auto& c: s) ++f[c - 'a'];
        for (auto& c: s) {
            t += c; --f[c - 'a']; while (j < 25 && f[j] < 1) ++j;
            while (size(t) > 0 && t.back() <= 'a' + j) r += t.back(), t.pop_back();
        } return r;
    }


05.06.2025

1061. Lexicographically Smallest Equivalent String medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1010

Problem TLDR

Map by smallest in group from associate s1 with s2 #medium

Intuition

We can do DFS or use a Union-Find to track groups.

Approach

  • we can find minimum in-place by always picking it as root
  • no reason to optimize (compression, ranking) Union-Find of just 26 elements

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\), for the result

Code


// 30ms
    fun smallestEquivalentString(s1: String, s2: String, bs: String): String {
        val u = HashMap(('a'..'z').associateBy { it })
        fun f(x: Char): Char = if (x == u[x]) x else f(u[x]!!)
        for ((a, b) in s1.zip(s2)) if (f(a) < f(b)) u[f(b)] = f(a) else u[f(a)] = f(b)
        return bs.map(::f).joinToString("")
    }



// 2ms
    fun smallestEquivalentString(s1: String, s2: String, bs: String): String {
        val u = IntArray(26) { it }; val a = bs.toCharArray()
        fun f(a: Int): Int { var x = a; while (x != u[x]) x = u[x]; u[a] = x; return x }
        for (i in s1.indices) {
            val a = f(s1[i] - 'a'); val b = f(s2[i] - 'a')
            if (a < b) u[b] = a else u[a] = b
        }
        for (i in a.indices) a[i] = 'a' + f(a[i] - 'a'); return String(a)
    }



// 0ms
    pub fn smallest_equivalent_string(s1: String, s2: String, bs: String) -> String {
        let mut u: Vec<_> = (0..26).collect();
        fn f(x: u8, u: &mut Vec<usize>) -> usize { let x = x as usize; while u[x] != u[u[x]] { u[x] = u[u[x]] }; u[x] }
        for (a, b) in s1.bytes().zip(s2.bytes()) {
            let (a, b) = (f(a - b'a', &mut u), f(b - b'a', &mut u)); if a < b { u[b] = a } else { u[a] = b }
        }
        bs.bytes().map(|b| (b'a' + f(b - b'a', &mut u) as u8) as char).collect()
    }



// 0ms
    string smallestEquivalentString(string s1, string s2, string bs) {
        int u[26] = {}; iota(u, u + 26, 0);
        auto f = [&](int x) { while (x != u[x]) x = u[x]; return x; };
        for (int i = 0; i < size(s1); ++i) {
            int a = f(s1[i] - 'a'), b = f(s2[i] - 'a');
            u[max(a, b)] = min(a, b);
        }
        for (char& c: bs) c = 'a' + f(c - 'a'); return bs;
    }


04.06.2025

3403. Find the Lexicographically Largest String From the Box I medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1009

Problem TLDR

Max string of every split by n #medium

Intuition

Observe an example, find a way to iterate over all possible strings.

    // abcdefgh     n=3

    // a b cdefgh
    // a bc defgh
    // a bcd efgh
    // a bcde fgh
    // a bcdef gh
    // a bcdefg h

    // ab c defgh
    // ab cd efgh
    // ab cde fgh
    // ab cdef gh
    // ab cdefg h

    // abc d efgh
    // abc de fgh
    // abc def gh
    // abc defg h

    // abcd e fgh
    // abcd ef gh
    // abcd efg h

    // abcde f gh
    // abcde fg h

    // abcdef g h
    // a, ab, abc, abcd, abcde, abcdef   (length - (n-1))
    //  b bc bcd bcde bcdef bcdefg (length - (n-2) - i) 
  • for every position i
  • the first before = min(i, n - 1) goes to friends
  • and the last after = n - 1 - before goes to friends, then trim

Approach

  • there is also O(1) memory solution, just don’t do substring, save positions and compare
  • there is also O(n) time solution, 1163. Last Substring in Lexicographical Order (hard) - take the last substring, then trim; the trick is to jump to the next of i or j pointers by largest s[i] or s[j]

Complexity

  • Time complexity: \(O(n^2)\), O(n) c++

  • Space complexity: \(O(n)\), O(result) c++

Code


// 28ms
    fun answerString(w: String, n: Int) =
        if (n == 1) w else w.indices.maxOf { i ->
            w.slice(i..w.length - n + min(n - 1, i))
        }



// 3ms
    pub fn answer_string(w: String, n: i32) -> String {
        if n == 1 { w } else { let n = n as usize; (0..w.len())
        .map(|i| w[i..=w.len() - n + i.min(n - 1)].to_string()).max().unwrap() }
    }



// 79ms
    string answerString(string w, int n) {
        if (n == 1) return w; string res = "";
        for (int i = 0; i < size(w); ++i) {
            int before = min(i, n - 1);
            int after = n - 1 - before;
            string s = w.substr(i, size(w) - i - after);
            if (s > res) res = s;
        } return res;
    }



// 0ms
    string answerString(string w, int n) {
        if (n == 1) return w; string res = "";
        int i = 0, j = 1;
        while (j < size(w)) {
            int k = 0; while (j + k < size(w) && w[j + k] == w[i + k]) ++k;
            if (k == size(w)) break;
            if (w[j + k] > w[i + k]) i += k + 1, j = i + 1; else j += k + 1;
        }
        int sz = size(w) - n + 1; int sz1 = size(w) - i;
        return w.substr(i, min(sz, sz1));
    }


03.06.2025

1298. Maximum Candies You Can Get from Boxes hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1008

Problem TLDR

Open boxes graph with keys simulation #hard

Intuition

Just the simulation steps in a BFS

Approach

  • make sure keys didn’t add unvisited box

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 5ms https://leetcode.com/problems/maximum-candies-you-can-get-from-boxes/submissions/1652437683
    fun maxCandies(st: IntArray, cs: IntArray, ks: Array<IntArray>, cb: Array<IntArray>, ib: IntArray): Int {
        val q = LinkedList<Int>(); var res = 0; for (b in ib) if (st[b] > 0) { st[b] = -1; q += b } else st[b] = 2
        while (q.size > 0) {
            val b = q.removeFirst(); res += cs[b]
            for (c in cb[b]) if (st[c] > 0) { st[b] = -1; q += c } else st[c] = 2
            for (k in ks[b]) if (st[k] > 1) { st[k] = -1; q += k } else if (st[k] == 0) st[k] = 1
        }
        return res
    }



// 0ms
    pub fn max_candies(mut st: Vec<i32>, cs: Vec<i32>, ks: Vec<Vec<i32>>, cb: Vec<Vec<i32>>, ib: Vec<i32>) -> i32 {
        let (mut q, mut r) = (VecDeque::from_iter(ib), 0);
        while let Some(b) = q.pop_front() { let b = b as usize;
            if st[b] > 0 {
                st[b] = -1; r += cs[b]; q.extend(&cb[b]);
                for &k in &ks[b] { let k = k as usize; if st[k] > 1 { q.push_back(k as i32) } else if st[k] == 0 { st[k] = 1 }}
            } else if st[b] == 0 { st[b] = 2 }
        } r
    }



// 0ms
    int maxCandies(vector<int>& st, vector<int>& cs, vector<vector<int>>& ks, vector<vector<int>>& cb, vector<int>& ib) {
        queue<int> q; int r = 0;
        for (int b: ib) if (st[b]) { st[b] = -1; q.push(b); } else st[b] = 2;
        while (size(q)) {
            int b = q.front(); q.pop(); r += cs[b];
            for (int c: cb[b]) if (st[c] > 0) { st[c] = -1; q.push(c); } else st[c] = 2;
            for (int k: ks[b]) if (st[k] > 1) { st[k] = -1; q.push(k); } else if (!st[k]) st[k] = 1;
        } return r;
    }


02.06.2025

135. Candy hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1007

Problem TLDR

Min candies, fair siblings by ratings #hard #greedy

Intuition

I was busy to find a single-pass solution, trying to sum the monotonic lengths sums, but it didn’t worked. So, looked for hints.

The hint: two passes works.

Chain-of-thoughts:

    // 1 2    2 
    // a a+1  1
    // 1 2 1 2 1 2 3 4 5
    // 
    // 5 4 3 2 1 2 3 4 5 4 3
    // 6 5 4 3 2 3 4 5 6 5 4 -1 to all

    // 1 0 2     +1 to all
    // 2 1 2
    // 1 2 2 2 3
    //   1     1
    // 1 2 1 1 2

    // 2 2 1 1 1 2 2 2 3 3 2 2  12
    //   1       1     1 1      +4

    // 1 2 3 5 4 3   6
    //   1 1 1 1     

    // 1 2 3 4 2 1
    //

    // 1 2 5 3 4 1 2
    // 1 2 3 1 2 1 2
    //       ^ if (next is bigger && prev is bigger) give 1
    //
    // 1 2 5 3 2 1    
    //       ^ if (next is smaller && prev is bigger) give prev - 1

    //  1 2 3 4 5 4 5 6 7
    //  1 2 3 4 5 1 2 3 4
    //
    // ok what if we are decreasing
    // 7 6 3 4 3 2 1
    // a b c            3*4/2=6
    //     1
    //   2
    // 3     a b c d    4*5/2=10
    //             1
    //           2
    //         3
    //       4
    // 1 2 3 4 7 6 3 4 3 2 1

    // 1 2 4 3 2 1
    // * * 
    //     * * * *
    //    vs
    // * * *
    //       * * * two passes works
    // 1 2 3 0 0 0
    // 0 0 4 3 2 1

    // 1 0 2
    // * *
    //     *

    // 1 2 3 4 7 6 3 4 3 2 1
    // 1 2 3 4 5 1 1 2 1 1 1
    //           2 1 4 3 2 1

Here is the correct single pass intuition:

    //    5*3      3*5    3 and 5 is in conflict
    //   4*.*2    2*.*4   choose max(3,5) = 5, so subtract min(3, 5)=-3
    //  3* . *1  1* . *3  or just shorten the smallest length by 1
    // 2*  . .    . .  *2
    //1*   . .    . .   *1
    // i   j k    i j   k

Approach

  • single pass solution can be more trickier to find, start with several passes (forward, back)

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\) or O(1)

Code


// 16ms
    fun candy(r: IntArray): Int {
        val c = IntArray(r.size) { 1 }
        for (i in 1..<r.size) if (r[i] > r[i - 1]) c[i] = c[i - 1] + 1
        for (i in r.lastIndex - 1 downTo 0) if (r[i] > r[i + 1]) c[i] = max(c[i], c[i + 1] + 1)
        return c.sum()
    }




// 4ms
    fun candy(r: IntArray): Int {
        var i = 1; var res = r.size
        while (i < r.size) {
            if (r[i] == r[i - 1]) { i++; continue }
            var j = i; while (j < r.size && r[j] > r[j - 1]) ++j
            var k = j; while (k < r.size && r[k] < r[k - 1]) ++k
            var a = min(j - i, k - j) - 1; var b = max(j - i, k - j)
            res += a * (a + 1) / 2 + b * (b + 1) / 2; i = k
        }
        return res
    }


// 0ms
    pub fn candy(r: Vec<i32>) -> i32 {
        let (mut i, mut res, mut a, mut b) = (1, r.len() as i32, 0, 0);
        while i < r.len() {
            if r[i] == r[i - 1] { i += 1; continue }
            a = 0; while i < r.len() && r[i] > r[i - 1] { i += 1; a += 1  }
            b = 0; while i < r.len() && r[i] < r[i - 1] { i += 1; b += 1  }
            (a, b) = (a.min(b) - 1, a.max(b)); res += a * (a + 1) / 2 + b * (b + 1) / 2
        } res
    }



// 0ms
    int candy(vector<int>& r) {
        int i = 1, res = size(r), a, b;
        while (i < size(r)) {
            if (r[i] == r[i - 1]) { ++i; continue; }
            a = 0; while (i < size(r) && r[i] > r[i - 1]) ++i, res += ++a;
            b = 0; while (i < size(r) && r[i] < r[i - 1]) ++i, res += ++b;
            res -= min(a, b);
        } return res;
    }


01.06.2025

2929. Distribute Candies Among Children II medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1006

Problem TLDR

Ways to give limited from n candies to 3 kids #medium #math #combinations

Intuition

Didn’t solved this, as hint4 gave the exact answer.

Useful hint instead of hint4:

  • for each first kid loked i = 0..min(n, limit)
  • do a running sum
  • of allowed range that both second and third kid can take
  • n - i - limit .. n - i
  • trim the range: max(0, n - i - limit)..min(limit, n - i)
  • the length of range a..b = b - a + 1

Chain-of-thoughts:


    // 10^6 (should  be faster then linear?)
    // is this completely math problem? like Cr(a, b)?
    // 4 hints, acceptance rate <50% (shold be hard problem?)
    // ok let's think how the distribution works:
    // 5 candles, limit 2
    // always 3 chilren
    // | A | B | C |
    // (0..limit) | (0..limit) | (0..limit)
    // the number of ways is countA * countB * countC
    // is n <= 3 * limit ? (let's run test case n=4, limit = 1, yes, the number of ways is 0)
    // no, do we have to handle the symmetry:
    // 0..limit | 0..min(n - countA, limit) | 0..min(n - countA - countB, limit)
    // consider n = 5 limit = 2
    // 1 2 2
    // 2 1 2
    // 2 2 1 symmetry with 1 2 2, counts separately
    //
    // so, we have 3 numbers, 
    // A=0..min(n, limit)
    // B=0..min(n - A, limit)
    // C=0..min(n - A - B, limit)
    // the result is A * B * C (is this correct?, no, b=0, c=0)
    // should we do a 3-step dfs dp? (10^6 will give TLE, but let's try)
    // ok, dp works, but TLE
    // probably requires some math idea from combinatorics
    // let's look for hints (22 minute)
    // enumerate first 0..min(n, limit) (already knew)
    // second is 0..j..limit, i + j less n (interesting way to write this)
    //                        j less n - i
    //           0..min(n - i, limit) (already knew)
    // hint: "after some transformations"
    // basically give you the answer on the hint4


There is a math solution:

  1. total n stars and 2 bars (to separate candies to three kids: * * * * * * )
  2. trick is how to count invalid combinations
  3. there is a math theory for this https://en.wikipedia.org/wiki/Inclusion%E2%80%93exclusion_principle
  4. good explanation: https://leetcode.com/problems/distribute-candies-among-children-ii/solutions/4278816/o-1-combinatorics/

Let’s try to summarize explanation for counding the invalid combinations:

  1. one kid has more than a limit, (limit + 1), 3 kids, remove limit + 1 and count ways to set bars C(n - (limit+1), 2), call those combinations as A
  2. two kids has more than a limit, (limit + 1), 3 pairs of kids, remove 2 * (limit + 1) and count ways to set bars C(n-2*(limit+1), 2), call those combinations as B
  3. three kids has more than a limit, single tripple of kids, remove 3 * (limit + 1), count ways to set bars C(n-3(limit+1), 2)
  4. important trick: the A combinations are including the B combinations already, so we have to subract the B (weak point)
  5. some math for stars and bars:
//  1 2 3 4 5   | |  
// . . . . . .
// (n+1) positions, choose 2
// C(n+1, 2) = n!/(r!*(n-r)!) = (n+1)!/(2!*(n+1-2)!) = (n+1)*n*(n-1)!/(2 *(n-1)!) = n(n+1)/2

Approach

  • try to understand the combinatorics, it seems the level has been raised to require this
  • c++ solution for this

Complexity

  • Time complexity: \(O(n)\) or O(1) if you are genius

  • Space complexity: \(O(1)\)

Code


// 123ms
    fun distributeCandies(n: Int, limit: Int) =
        (0..min(n, limit)).sumOf { i ->
            1L * max(0, min(limit, n - i) - max(0, n - i - limit) + 1) }



// 15ms
    pub fn distribute_candies(n: i32, limit: i32) -> i64 {
        (0..=n.min(limit)).map(|i|
            0.max(limit.min(n - i) - 0.max(n - i - limit) + 1) as i64
        ).sum()
    }



// 0ms
    long long distributeCandies(int n, int limit) {
        auto c = [&](this const auto& c, long n) -> long {return n*(n+1)/2;};
        n++; // stars are places between candies to put the bars
        long long nStarsTwoBars = 1LL * c(n);
        long long oneOutOfLimit = 1LL * max(0, n - (limit + 1));
        long long twoOutOfLimit = max(0, n - 2 * (limit + 1));
        long long threeOutOfLimit = max(0, n - 3 * (limit + 1));
        long long invalidCombinations = 3 * c(oneOutOfLimit)
                                       -3 * c(twoOutOfLimit)
                                       +1 * c(threeOutOfLimit);
        return nStarsTwoBars - invalidCombinations;
    }


31.05.2025

909. Snakes and Ladders medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1005

Problem TLDR

Shortest path bottom-top in zig-zag matrix with jumps #medium #bfs

Intuition

Surprisingly, didn’t covered all corener cases.

    // 1:15, still some corner case not covered, looking for solutions....

My issue was a premature optimization, trying to inline visited set with jumps. After making a separate visited set it all worked out.

Approach

  • LinkedList vs ArrayDeque is 5ms vs 20ms drop-in replacement difference in Kotlin
  • don’t premature optimize on the first go
  • read instructions slowly: we never do jump-jump, even in 2 ticks

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n^2)\)

Code


// 6ms
    fun snakesAndLadders(b: Array<IntArray>): Int {
        var s = -1; val n = b.size; var (q, q1) = List(2) { ArrayList<Int>(400) }; q1 += 1
        while (q1.size > 0 && ++s >= 0.also { q = q1.also { q1 = q }; q1.clear() })
            for (i in q) for (j in i + 1..min(i + 6, n * n)) {
                val y = n - 1 - (j - 1) / n
                val x = if (y % 2 != n % 2) (j - 1) % n else n - 1 - (j - 1) % n
                if (b[y][x] < -1) continue 
                val k = if (b[y][x] >= 0) b[y][x] else j; b[y][x] = -2; q1 += k
                if (k == n * n) return s + 1
            }
        return -1
    }



// 0ms
    pub fn snakes_and_ladders(mut b: Vec<Vec<i32>>) -> i32 {
        let (mut s, mut n, mut q, mut q1) = (0, b.len(), vec![1], vec![]);
        while q.len() > 0 { 
            for &i in &q { for j in i + 1..=(i + 6).min(n * n) { 
                let y = n - 1 - (j - 1) / n;
                let x = if y % 2 != n % 2 { (j - 1) % n } else { n - 1 - (j - 1) % n };
                if b[y][x] < -1 { continue }
                let k = if b[y][x] >= 0 { b[y][x] } else { j as i32 }; b[y][x] = -2;
                if k == (n * n) as i32 { return s + 1 }
                q1.push(k as usize) }}
            s += 1; (q, q1) = (q1, q); q1.clear();
        }; -1
    }



// 0ms
    int snakesAndLadders(vector<vector<int>>& b) {
        int n = b.size(), s = -1; vector<int> q, q1 = {1};
        while (!q1.empty()) {
            s++; q.swap(q1); q1.clear();
            for (int i : q) for (int j = i + 1, end = min(i + 6, n * n); j <= end; j++) {
                int y = n - 1 - (j - 1) / n;
                int x = (y % 2 != n % 2) ? (j - 1) % n : n - 1 - (j - 1) % n;
                if (b[y][x] < -1) continue;
                int k = (b[y][x] >= 0 ? b[y][x] : j); b[y][x] = -2;
                if (k == n * n) return s + 1; q1.push_back(k);
            }
        }
        return -1;
    }


30.05.2025

2359. Find Closest Node to Given Two Nodes medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1004

Problem TLDR

Closest common node #medium #bfs

Intuition

Walk from two nodes in a parallel BFS by using two queues. First intersection is the answer.


    // 0 1 2 
    // 2 0 0

    // 1 -. 0 .-. 2    a = 2, b = 0

    // 0 1 2 3 4 5  6
    // 5 4 5 4 3 6 -1

    // 0 -. 5 -. 6      a = 0 b = 1
    // 2 -.^
    //
    // 1 -. 4 .-. 3

Approach

  • start with parallel BFS
  • replace queues with single variables
  • replace visited sets with marker variables in the edges

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 4ms
    fun closestMeetingNode(e: IntArray, a: Int, b: Int): Int {
        var a = a; var b = b; var r = e.size
        while (a >= 0 || b >= 0) {
            if (a >= 0) if (e[a] == -2) r = a else a = e[a].also { e[a] = -3 }
            if (b >= 0) if (e[b] == -3) r = min(r, b) else b = e[b].also { e[b] = -2 }
            if (r < e.size) return r
        }
        return -1
    }




// 54ms
    fun closestMeetingNode(e: IntArray, a: Int, b: Int): Int {
        val qa = ArrayDeque<Int>(); qa += a; var res = e.size
        val qb = ArrayDeque<Int>(); qb += b
        val va = HashSet<Int>(); val vb = HashSet<Int>();
        while (qa.size > 0 || qb.size > 0) {
            for (i in 0..<qa.size) {
                val x = qa.removeFirst()
                if (x in vb) res = min(res, x)
                if (va.add(x) && e[x] >= 0) qa += e[x]
            }
            for (i in 0..<qb.size) {
                val x = qb.removeFirst()
                if (x in va) res = min(res, x)
                if (vb.add(x) && e[x] >= 0) qb += e[x]
            }
            if (res < e.size) return res
        }
        return -1
    }




// 0ms
    pub fn closest_meeting_node(mut e: Vec<i32>, mut a: i32, mut b: i32) -> i32 {
        while a >= 0 || b >= 0 { let (i, j) = (a as usize, b as usize);
            if a >= 0 && e[i] == -2 { return if b >= 0 && e[j] == -3 { a.min(b) } else { a }}
            if a >= 0 { let x = e[i]; e[i] = -3; a = x }
            if b >= 0 { if e[j] == -3 { return b } else { let x = e[j]; e[j] = -2; b = x }}
        } -1
    }




// 0ms
    int closestMeetingNode(vector<int>& e, int a, int b) {
        while (a >= 0 || b >= 0) {
            if (a >= 0 && e[a] == -2) return b >= 0 && e[b] == -3 ? min(a, b) : a;
            if (a >= 0) { int t = e[a]; e[a] = -3; a = t; }
            if (b >= 0) if (e[b] == -3) return b; else { int t = e[b]; e[b] = -2, b = t; }
        } return -1;
    }



29.05.2025

3373. Maximize the Number of Target Nodes After Connecting Trees II hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1003

Problem TLDR

Max even-edged siblings after merging trees #hard #graph

Intuition

2.png

1. node either in the odd or even set
2. mark nodes, calculate count_odd, count_even

Approach

  • track parent or just check mark[y] == 0
  • use DFS or BFS

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 110ms
    fun maxTargetNodes(e1: Array<IntArray>, e2: Array<IntArray>): IntArray {
        val (cm1, cm2) = listOf(e1, e2).map { e -> 
            val g = Array(e.size + 1) { ArrayList<Int>() }
            for ((a, b) in e) { g[a] += b; g[b] += a }
            val m = IntArray(g.size); val c = IntArray(3)
            fun dfs(x: Int, o: Int) {
                m[x] = o; c[o]++; for (y in g[x]) if (m[y] < 1) dfs(y, 3 - o) }
            dfs(0, 1); c to m
        }
        val (c1, m1) = cm1; val (c2, m2) = cm2; val cmax = c2.max()
        return IntArray(m1.size) { c1[m1[it]] + cmax }
    }




// 63ms
    pub fn max_target_nodes(e1: Vec<Vec<i32>>, e2: Vec<Vec<i32>>) -> Vec<i32> {
        let [(c1, m1), (c2, m2)] = [e1, e2].map(|e| {
            let (mut g, mut m, mut c, mut q, mut q1, mut o) = 
                (vec![vec![]; e.len() + 1], vec![0; e.len() + 1], [0; 3], vec![0], vec![], 1);
            for e in e { let (a, b) = (e[0] as usize, e[1] as usize); 
                g[a].push(b); g[b].push(a) }
            while q.len() > 0 { for &x in &q { 
                m[x] = o; c[o] += 1; for &y in &g[x] { if m[y] < 1 { q1.push(y) }}}
                (q, q1) = (q1, q); o = 3 - o; q1.clear()
            }; (c, m)
        }); 
        let cmax = c2[1].max(c2[2]); m1.into_iter().map(|m1| c1[m1] + cmax).collect()
    }




// 277ms
    vector<int> maxTargetNodes(vector<vector<int>>& e1, vector<vector<int>>& e2) {
        auto f = [&](auto& e){
            vector<vector<int>> g(size(e) + 1);
            for (auto& p: e) g[p[0]].push_back(p[1]), g[p[1]].push_back(p[0]);
            vector<int> m(size(g)), c(3); queue<int> q; q.push(0); m[0] = 1; c[1]++;
            while (size(q)) {
                int u = q.front(); q.pop();
                for(int v: g[u]) if(!m[v]) m[v] = 3 - m[u], c[m[v]]++, q.push(v); }
            return pair {c, m};
        };
        auto [c1, m1] = f(e1); auto [c2, m2] = f(e2);
        int cm = max(c2[1], c2[2]); vector<int> r(size(m1));
        for (int i = 0; i < size(m1); ++i) r[i] = c1[m1[i]] + cm;
        return r;
    }


28.05.2025

3372. Maximize the Number of Target Nodes After Connecting Trees I medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1002

Problem TLDR

Max k-reachable nodes of merged trees #medium #dfs

Intuition

The brute-force DFS is accepted.

Chain-of-thoughts:


    // for k - 1
    // find the most optimal spot on edges2
    // how many nodes can be (k-1) reached from each node
    // solve same problem for edges1(k) and edges2(k-1)
    // 1000 edges, brute-force bfs from each 1000*k, n^2
    // lets write brute-force, no good ideas (23 minutes)

Approach

  • sometimes it is better to start with brute-force, then spending too much time thinking about a better algorithm

Complexity

  • Time complexity: \(O(n^2)\), n = 1000

  • Space complexity: \(O(n)\)

Code


// 147ms
    fun maxTargetNodes(e1: Array<IntArray>, e2: Array<IntArray>, k: Int): IntArray {
        val (g1, g2) = listOf(e1, e2).map { e ->
            Array(e.size + 1) { ArrayList<Int>() }.also { g ->
                for ((a, b) in e) { g[a] += b; g[b] += a }}}
        fun dfs(x: Int, g: Array<ArrayList<Int>>, p: Int, k: Int): Int =
            if (k < 0) 0 else 1 + g[x].sumOf { if (it == p) 0 else dfs(it, g, x, k - 1) }
        val cnt2 = g2.indices.maxOf { dfs(it, g2, -1, k - 1) }
        return IntArray(g1.size) { cnt2 + dfs(it, g1, -1, k) }
    }




// 67ms
    pub fn max_target_nodes(e1: Vec<Vec<i32>>, e2: Vec<Vec<i32>>, k: i32) -> Vec<i32> {
        let [g1, g2] = [e1, e2].map(|e| { let mut g = vec![vec![]; e.len() + 1];
            for e in e { let (a, b) = (e[0] as usize, e[1] as usize); 
            g[a].push(b); g[b].push(a) }; g });
        fn dfs(x: usize, g: &[Vec<usize>], p: usize, k: i32) -> i32 {
            if k < 0 { 0 } else { 
                1 + g[x].iter().map(|&s| if s == p { 0 } else { dfs(s, g, x, k - 1)}).sum::<i32>() }}
        let cnt2 = (0..g2.len()).map(|x| dfs(x, &g2, 1001, k - 1)).max().unwrap();
        (0..g1.len()).map(|x| cnt2 + dfs(x, &g1, 1001, k)).collect()
    }




// 95ms
    vector<int> maxTargetNodes(vector<vector<int>>& e1, vector<vector<int>>& e2, int k) {
        int n = size(e1) + 1, m = size(e2) + 1, c2 = 0; vector<vector<int>> g1(n), g2(m);
        for (auto& e: e1) g1[e[0]].push_back(e[1]), g1[e[1]].push_back(e[0]);
        for (auto& e: e2) g2[e[0]].push_back(e[1]), g2[e[1]].push_back(e[0]);
        auto dfs = [&](this const auto& dfs, int x, vector<vector<int>>& g, int p, int k) -> int {
            if (k < 0) return 0; int cnt = 1; for (int s: g[x]) if (s != p) cnt += dfs(s, g, x, k - 1);
            return cnt;
        }; vector<int> r(n);
        for (int i = 0; i < m; ++i) c2 = max(c2, dfs(i, g2, -1, k - 1));
        for (int i = 0; i < n; ++i) r[i] = c2 + dfs(i, g1, -1, k); return r;
    }



27.05.2025

2894. Divisible and Non-divisible Sums Difference easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1001

Problem TLDR

Sum non-divisible minus sum divisible #easy #math

Intuition

I was happy to spot we can do this in a single iteration, sum += x % m ? x : -x

There is an arithmetic math solution however:


    // a + b = n*(n+1)/2
    // b = m * k*(k+1)/2, k = n/m, m, 2m, 3m...km
    // a - b = (a + b) - 2b
    // a - b = n*(n+1)/2 - 2*m*k*(k+1)/2

Approach

  • how short can it be?

Complexity

  • Time complexity: \(O(n)\), or O(1)

  • Space complexity: \(O(1)\)

Code


// 5ms (52 symbols)
    fun differenceOfSums(n: Int, m: Int) = 
        (1..n).sumOf { if (it % m < 1) -it else it }


// 0ms (49 symbols)
    fun differenceOfSums(n: Int, m: Int) =
        n * (n + 1) / 2 - n / m * (n / m + 1) * m



// 13ms (47 symbols)
    fun differenceOfSums(n: Int, m: Int) =
        (1..n).sum() - n / m * (n / m + 1) * m



// 12ms (46 symbols)
    fun differenceOfSums(n: Int, m: Int) =
        (1..n).sum() - (1..n/m).sum() * m * 2



// 0ms
    pub fn difference_of_sums(n: i32, m: i32) -> i32 {
        n * (n + 1) / 2 - n / m * (n / m + 1) * m
    }



// 0ms
    int differenceOfSums(int n, int m) {
        return n * (n + 1) / 2 - n / m * (n / m + 1) * m;
    }


26.05.2025

1857. Largest Color Value in a Directed Graph hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/1000

Problem TLDR

Max color freq path #hard #dp #toposort

Intuition

    // for every node
    // (freq of colors)
    // we want max(freq)

As graph is directed asyclic graph, we can assume each node has definite answer of top color frequencies of all path from it. Walk those paths in DFS or BFS with toposort.

Approach

  • to check cycle use a hashset, don’t forget to remove from it after we done, as we can have two different valid paths to the same node
  • the toposort is: 1) count incoming nodes 2) always add to the queue zero incoming nodes

Complexity

  • Time complexity: \(O(VE)\)

  • Space complexity: \(O(V + E)\)

Code


// 1213ms
    fun largestPathValue(c: String, e: Array<IntArray>): Int {
        val g = Array(c.length) { ArrayList<Int>() }; for ((a, b) in e) g[a] += b
        val v = HashSet<Int>(); val dp = HashMap<Int, IntArray>()
        fun dfs(i: Int): IntArray? = dp.getOrPut(i) { val res = IntArray(26)
            for (s in g[i]) {
                if (!v.add(s)) return@dfs null; val next = dfs(s) ?: return@dfs null
                v.remove(s); for (j in 0..25) res[j] = max(res[j], next[j])
            }; res[c[i] - 'a']++; res
        }
        return c.indices.maxOf { dfs(it)?.max() ?: return -1 }
    }



// 802ms
    fun largestPathValue(c: String, e: Array<IntArray>): Int {
        val d = IntArray(c.length); val g = Array(d.size) { ArrayList<Int>() }
        val cnt = Array(d.size) { IntArray(26) }; for ((a, b) in e) { g[a] += b; ++d[b] }
        var q = ArrayList<Int>(); var q1 = ArrayList<Int>(); var r = 0; var v = 0;
        for (i in d.indices) if (d[i] == 0) q += i;
        while (q.size > 0) {
            for (i in q) {
                ++v; r = max(r, ++cnt[i][c[i] - 'a'])
                for (j in g[i]) {
                    for (k in 0..25) cnt[j][k] = max(cnt[j][k], cnt[i][k])
                    if (--d[j] == 0) q1 += j
                }
            }
            q = q1.also { q1 = q; q1.clear() }
        }
        return if (v == d.size) r else -1
    }



// 69ms
    pub fn largest_path_value(c: String, e: Vec<Vec<i32>>) -> i32 {
        let (mut g, c, mut d, mut q) = (vec![vec![]; c.len()], c.as_bytes(), vec![0; c.len()], vec![]);
        let (mut cnt, mut q1, mut r, mut v) = (vec![vec![0; 26]; c.len()], vec![], 0, 0);
        for e in e  { let (a, b) = (e[0] as usize, e[1] as usize); g[a].push(b); d[b] += 1; }
        for i in 0..d.len() { if d[i] == 0 { q.push(i) }}
        while q.len() > 0 {
            for &i in &q { let c = (c[i] - b'a') as usize; 
                v += 1; cnt[i][c] += 1; r = r.max(cnt[i][c]);
                for &j in &g[i] {
                    for k in 0..26 { cnt[j][k] = cnt[j][k].max(cnt[i][k]); }
                    d[j] -= 1; if d[j] == 0 { q1.push(j) } }
            }  (q, q1) = (q1, q); q1.clear()
        } if v == d.len() { r } else { -1 }
    }



// 312ms
    int largestPathValue(string c, vector<vector<int>>& e) {
        int n = size(c), v = 0, r = 0; vector<array<int,26>> cnt(n);
        vector<vector<int>> g(n); vector<int> d(n); queue<int> q;
        for (auto& p : e) { g[p[0]].push_back(p[1]); ++d[p[1]]; }
        for (int i = 0; i < n; i++) if (!d[i]) q.push(i);
        while (!q.empty()) {
            int i = q.front(); q.pop(); ++v; r = max(r, ++cnt[i][c[i] - 'a']);
            for (int j: g[i]) {
                for (int k = 0; k < 26; k++) cnt[j][k] = max(cnt[j][k], cnt[i][k]);
                if (--d[j] == 0) q.push(j);
            }
        }
        return v == n ? r : -1;
    }


25.05.2025

2131. Longest Palindrome by Concatenating Two Letter Words medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/999

Problem TLDR

Max palindrome length from 2 char words #medium

Intuition

Calculate frequencies.

  • count mirrors, take min f[ab], f[ba]
  • take a single odd from twins f[aa] % 2

Approach

  • don’t forget *2
  • take half of twins: f[aa] / 2
  • we can do it one-pass, runtime is worse as we are doing more operations in the longest loop O(10^5)

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 38ms
    fun longestPalindrome(w: Array<String>): Int {
        val f = w.groupBy { it }; var o = 0
        return 2 * f.entries.sumOf { (w, f1) ->
            if (w[0] == w[1]) { if (f1.size % 2 > 0) o = 2; 2 * (f1.size / 2)  }
            else min(f1.size, f[w.reversed()]?.size ?: 0) } + o
    }



// 20ms
    fun longestPalindrome(w: Array<String>): Int {
        val f = IntArray(676); var o = 0; var r = 0
        for (w in w) {
            val a = w[0] - 'a'; val b = w[1] - 'a'
            val w = a * 26 + b
            if (f[w] > 0) { --f[w]; r += 4 } else ++f[b * 26 + a]
            if (a == b) o += 2 * (f[w] and 1) - 1
        }
        return r + if (o > 0) 2 else 0
    }



// 7ms https://leetcode.com/problems/longest-palindrome-by-concatenating-two-letter-words/submissions/1643834111
    fun longestPalindrome(w: Array<String>): Int {
        val f = IntArray(676); var o = 0; var r = 0
        for (w in w) ++f[(w[0] - 'a') * 26 + (w[1] - 'a')]
        for (w in 0..675) if (f[w] > 0) r +=
            if (w / 26 == w % 26) { o = o or (f[w] and 1); f[w] and (-2) }
            else min(f[w], f[(w % 26) * 26 + w / 26])
        return 2 * (r + o)
    }



// 20ms
    pub fn longest_palindrome(words: Vec<String>) -> i32 {
        let (mut f, mut r, mut o) = ([0; 676], 0, 0);
        for w in words { let w = w.as_bytes();
            let (a, b) = ((w[0] - b'a') as usize, (w[1] - b'a') as usize);
            let w = a * 26 + b;
            if f[w] > 0 { f[w] -= 1; r += 4 } else { f[b * 26 + a] += 1 }
            if a == b { o += 2 * (f[w] & 1) - 1 }
        } r + (o > 0) as i32 * 2
    }



// 6ms https://leetcode.com/problems/longest-palindrome-by-concatenating-two-letter-words/submissions/1643877476
    pub fn longest_palindrome(words: Vec<String>) -> i32 {
        let (mut f, mut o) = ([0; 676], 0);
        for w in words { let w = w.as_bytes();
            let (a, b) = ((w[0] - b'a') as usize, (w[1] - b'a') as usize);
            f[a * 26 + b] += 1
        }
        (0..26).flat_map(|a| (a..26).map(move |b| (a, b, f[a * 26 + b])))
        .map(|(a, b, fw)| if a == b { o |= fw & 1; fw >> 1 } 
            else { fw.min(f[b * 26 + a]) }).sum::<i32>() * 4 + o * 2
    }



// 1ms
    int longestPalindrome(vector<string>& words) {
        int f[676]={}, o = 0, r = 0;
        for (auto& s: words) {
            int a = s[0] - 'a', b = s[1] - 'a';
            int w = a * 26 + b;
            if (f[w]) --f[w], r += 4; else ++f[b * 26 + a];
            if (a == b) o += 2 * (f[w] & 1) - 1;
        } return r + 2 * (o > 0);
    }


24.05.2025

2942. Find Words Containing Character easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/998

Problem TLDR

Indices with x #easy

Intuition

Do what is asked

Approach

  • the answer can be in any order suggests some interesting optimizations: what if we unroll loops or even start work in parallel? (however, in Kotlin I wasnt able to gain any performance)

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 25ms
    fun findWordsContaining(w: Array<String>, x: Char) =
        w.indices.filter { x in w[it] }


// 9ms
    fun findWordsContaining(w: Array<String>, x: Char): List<Int> {
        val res = ArrayList<Int>(w.size)
        for (i in w.indices) if (x in w[i]) res += i
        return res
    } 



// 3ms
    fun findWordsContaining(w: Array<String>, x: Char): List<Int> {
        val res = ArrayList<Int>(w.size)
        for (i in w.indices) 
            for (c in w[i]) if (c == x) { res += i; break }
        return res
    } 



// 0ms
    pub fn find_words_containing(w: Vec<String>, x: char) -> Vec<i32> {
        (0..w.len()).filter(|&i| w[i].contains(x)).map(|i| i as _).collect()
    }



// 0ms
    vector<int> findWordsContaining(vector<string>& w, char x) {
        vector<int> r;
        for (int i = 0; i < size(w); ++i) if (w[i].contains(x)) r.push_back(i);
        return r;
    }


23.05.2025

3068. Find the Maximum Sum of Node Values hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/997

Problem TLDR

Max sum by k-xoring edges #hard #tree #dp

Intuition

Didn’t solved the second time (2024 was the previous attempt)


    // 1 - 0 - 2
    // a - b - c 
    // ^k  ^k
    //     ^k  ^k   a^k - b - c^k
    // a - b - c - d
    // ^   ^
    //     ^   ^
    //         ^   ^   a^k - b - c - d^k
    //
    // a^k b   c   d^k
    // a^k b   c^k d
    // a^k b^k c   d
    // a^k b^k c^k d^k
    // a   b^k c^k d
    // a   b   c^k d^k
    // a   b^k c   d^k

    // a - b - c    a*- b*- c - e*
    //     |            |
    //     d            d*
    // didn't see any simple law
    // maybe full search?
    // wong answer: careful with flipping the last (it flips the previous?)
    // 0-2-4-3
    //   |
    //   1
    // 
    // 5-0-1*-3*-6-2*
    //     |
    //     4*
    // flip current without flipping previous:
    // 1. if has next
    // 51 minutes, use hints, looks like the same dp (and what is parity?)
    // looks like i did the same mistake in 2024 (and didn't finished dp)

What was missing:

  • I didn’t paid attention to the detail: only even number of flipped numbers is possible

Why my DFS+cache simultaion didn’t worked:

  • when children count > 1, we can’t flip them all simultaneously

Approach

  • attention to details: how many flips can be done, how flips happen when node has many chilren
  • can you rewrite DFS dp to return a single Long result?

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\), O(n) for dp

Code


    fun maximumValueSum(nums: IntArray, k: Int, edges: Array<IntArray>): Long {
        var sum = 0L; var xored = 0; var diff = Int.MAX_VALUE / 2
        for (x in nums) {
            sum += 1L * max(x, x xor k)
            if (x xor k > x) xored++
            diff = min(diff, abs((x xor k) - x))
        }
        return sum - diff * (xored % 2)
    }



    fun maximumValueSum(nums: IntArray, k: Int, edges: Array<IntArray>): Long {
        val g = Array(nums.size) { ArrayList<Int>() }
        for ((u, v) in edges) { g[u] += v; g[v] += u }
        val dp = HashMap<Int, Pair<Long, Long>>()
        fun dfs(u: Int, p: Int): Pair<Long, Long> = dp.getOrPut(u) {
            var sumFlip = Long.MIN_VALUE / 2
            var sumStay = 0L
            for (v in g[u]) if (v != p) {
                val (flip, stay) = dfs(v, u)
                sumFlip = max(sumStay + stay, sumFlip + flip).also {
                sumStay = max(sumStay + flip, sumFlip + stay) }
            }
            val stay = nums[u]
            val flip = stay xor k
            sumFlip = max(sumStay + stay, sumFlip + flip).also {
            sumStay = max(sumStay + flip, sumFlip + stay) }
            sumFlip to sumStay
        }
        return dfs(0, -1).first
    }



    fun maximumValueSum(nums: IntArray, k: Int, edges: Array<IntArray>): Long {
        val g = Array(nums.size) { ArrayList<Int>() }
        for ((u, v) in edges) { g[u] += v; g[v] += u }
        val dp = HashMap<Pair<Int, Int>, Long>()
        fun dfs(u: Int, p: Int, f: Int): Long = dp.getOrPut(u to f) {
            val flip = (nums[u] xor k xor f).toLong()
            val stay = (nums[u] xor f).toLong() 
            var sum = max(flip, stay)
            var flips = if (flip > stay) 1 else 0
            var diff = abs(flip - stay)
            for (v in g[u]) if (v != p) {
                val flip = dfs(v, u, k)
                val stay = dfs(v, u, 0)
                if (flip > stay) flips = flips xor 1
                diff = min(diff, abs(flip - stay))
                sum += max(flip, stay)
            }
            sum - diff * flips
        }
        return dfs(0, -1, 0)
    }



    pub fn maximum_value_sum(n: Vec<i32>, k: i32, edges: Vec<Vec<i32>>) -> i64 {
        let (mut s, mut c, mut d) = (0, 0, i32::MAX);
        for x in n {
            s += x.max(x ^ k) as i64;
            if x ^ k > x { c ^= 1 }
            d = d.min(((x ^ k) - x).abs())
        } s - d as i64 * c
    }



    long long maximumValueSum(vector<int>& n, int k, vector<vector<int>>& edges) {
        long long s = 0, c = 0, d = 1e9;
        for (int& x: n) {
            s += max(x, x ^ k);
            if ((x ^ k) > x) c ^= 1;
            d = min(d, 1LL * abs((x ^ k) - x));
        } return s - d * c;
    }


22.05.2025

3362. Zero Array Transformation III medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/996

Problem TLDR

Max removed queries still zero-fy an array #medium #heap

Intuition

Didn’t solved.

Irrelevant chain-of-thougths for history:


    // [1,1,1,1]
    // [[1,3],[0,2],[1,3],[1,2]]
    // 0,2 1,2 1,3 1,3
    // 0  1  2  3  
    // 0, 3, 3, 1, -2
    //    i  j           0,2 take
    //                   1,2 drop, 3,3 -> 2,2 min=2
    //    i     j        1,3 drop, 2,2,1 -> 2,2,0, min=0
    // *running interval minimum* increasing queue?
    // looks like too hard for medium, maybe wrong algo?
    // use hints
    // sort: already done
    // pick max end: already do ?
    // 
    // [1,1,1,1]
    //        i    1..3
    //  i          max = 1
    //             1..3
    //   2 0 2
    //   1   1    0..2
    //                  
    //   2   2    0..2
    //     1      1..1 move and compute running sum
    // ok, i fail

The working solution:

  • sort queries by start
  • iterate the nums
  • maintain the current accepted queries sum
  • put accepted queries (start, end) into a line sweep diff array
  • hard part: put candidate queries (same start) ends into a sorted heap, poll lazily when needed

Approach

  • it looks like I’ve solved it previously in contest, but havn’t absorbed the solution, or, even possible degraded in the solution search
  • I’ve solved the wrong problem on the start and spent some mind power

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(n)\)

Code


    fun maxRemoval(nums: IntArray, queries: Array<IntArray>): Int {
        val h = PriorityQueue<Int>(); val d = IntArray(nums.size + 1)
        queries.sortBy { it[0] }; var qsum = 0; var j = 0
        for ((i, x) in nums.withIndex()) {
            while (j < queries.size && queries[j][0] == i) h += -queries[j++][1]
            qsum += d[i]
            while (x > qsum && h.size > 0 && -h.peek() >= i) {
                d[-h.poll() + 1]--; qsum++
            }
            if (x > qsum) return -1
        }
        return h.size
    }


    pub fn max_removal(n: Vec<i32>, mut q: Vec<Vec<i32>>) -> i32 {
        let (mut h, mut d) = (BinaryHeap::new(), vec![0; n.len() + 1]);
        q.sort_unstable(); let (mut lvl, mut j) = (0, 0);
        for i in 0..n.len() {
            while j < q.len() && q[j][0] == i as i32 { h.push(q[j][1] as usize); j += 1 }
            lvl += d[i];
            while n[i] > lvl && h.len() > 0 && *h.peek().unwrap() >= i {
                d[h.pop().unwrap() + 1] -= 1; lvl += 1
            }
            if n[i] > lvl { return -1 }
        } h.len() as _
    }



    int maxRemoval(vector<int>& n, vector<vector<int>>& q) {
        priority_queue<int> h; int l = 0, j = 0;
        vector<int> d(n.size() + 1); sort(q.begin(), q.end());
        for (int i = 0, N = n.size(); i < N; ++i) {
            while (j < q.size() && q[j][0] == i)
                h.push(q[j++][1]);
            l += d[i];
            while (l < n[i] && !h.empty() && h.top() >= i)
                l++, d[h.top() + 1]--, h.pop();
            if (l < n[i]) return -1;
        }
        return h.size(); 
    }


21.05.2025

73. Set Matrix Zeroes medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/995

Problem TLDR

Zero-fy rows and columns #medium

Intuition

Do what is asked. In-place: use first row and column

Approach

  • don’t fall into trap of overriding the good rows
  • minimize iterations by checking m[0][x] || m[y][0]
  • check separately if you need to zero-fy the first row and column

Complexity

  • Time complexity: \(O(mn)\)

  • Space complexity: \(O(n)\) or O(1)

Code


// 16ms
    fun setZeroes(m: Array<IntArray>): Unit {
        val zc = m[0].indices.filter { x -> m.any { it[x] == 0 }}
        for (r in m) if (0 in r) r.fill(0)
        for (x in zc) for (r in m) r[x] = 0
    }



// 1ms
    fun setZeroes(m: Array<IntArray>): Unit {
        var fr = false; var fc = false; val c = m[0]
        for ((y, r) in m.withIndex()) for (x in r.indices) if (r[x] == 0) 
            { if (y == 0) fr = true; if (x == 0) fc = true; c[x] = 0; r[0] = 0 }
        for (y in 1..<m.size) for (x in 1..<c.size) 
            if (c[x] == 0 || m[y][0] == 0) m[y][x] = 0
        if (fc) for (r in m) r[0] = 0; if (fr) for (x in c.indices) c[x] = 0
    }


// 0ms
    pub fn set_zeroes(m: &mut Vec<Vec<i32>>) {
        let (mut fr, mut fc) = (false, false);
        for y in 0..m.len() { for x in 0..m[0].len() { if m[y][x] == 0 { 
            fr |= y == 0; fc |= x == 0; m[0][x] = 0; m[y][0] = 0 
        }}}
        for y in 1..m.len() { for x in 1..m[0].len() {
            if m[0][x] == 0 || m[y][0] == 0 { m[y][x] = 0 }
        }}
        if fc { for y in 0..m.len() { m[y][0] = 0 } }
        if fr { m[0][..].fill(0) }
    }



// 0ms
    void setZeroes(vector<vector<int>>& m) {
        int fr = 0, fc = 0; vector<int>& c = m[0];
        for (int y = 0; y < size(m); ++y) for (int x = 0; x < size(c); ++x) if (!m[y][x])
            fr |= y == 0, fc |= x == 0, c[x] = 0, m[y][0] = 0;
        for (int y = 1; y < size(m); ++y) for (int x = 1; x < size(c); ++x) if (!c[x] || !m[y][0]) m[y][x] = 0;
        if (fc) for (int y = 0; y < size(m); ++y) m[y][0] = 0;
        if (fr) for (int x = 0; x < size(c); ++x) c[x] = 0;
    }


20.05.2025

3355. Zero Array Transformation I medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/994

Problem TLDR

Can intersecting intervals decrease an array #medium #line_sweep

Intuition

Line sweep trick: store starts and ends of the intervals, then do the line sweep by increasing and decreasing prefix sum.

Approach

  • decreasing should be after the end

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 22ms
    fun isZeroArray(nums: IntArray, queries: Array<IntArray>): Boolean {
        val d = IntArray(nums.size + 1); var s = 0
        for ((s, e) in queries) { d[s]++; d[e + 1]-- }
        return nums.zip(d).all { (n, d) -> s += d; s >= n }
    }


// 3ms
    fun isZeroArray(nums: IntArray, queries: Array<IntArray>): Boolean {
        val d = IntArray(nums.size + 1); var s = 0
        for ((s, e) in queries) { d[s]++; d[e + 1]-- }
        for ((i, x) in nums.withIndex()) {
            s += d[i]
            if (s < x) return false
        }
        return true
    }



// 5ms
    pub fn is_zero_array(nums: Vec<i32>, queries: Vec<Vec<i32>>) -> bool {
        let (mut d, mut s) = (vec![0; nums.len() + 1], 0);
        for q in queries { d[q[0] as usize] += 1; d[q[1] as usize + 1] -= 1 }
        nums.iter().zip(d.iter()).all(|(x, d)| { s += d; s >= *x })
    }



// 0ms https://leetcode.com/problems/zero-array-transformation-i/submissions/1638961889
    bool isZeroArray(vector<int>& nums, vector<vector<int>>& queries) {
        vector<int> d(size(nums) + 1); int s = 0;
        for (auto& q: queries) ++d[q[0]], --d[q[1] + 1];
        for (int i = 0; int x: nums) { s += d[i++]; if (s < x) return 0; }
        return 1;
    }


19.05.2025

3024. Type of Triangle easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/993

Problem TLDR

Triangle type by lengths #easy

Intuition

Was surprisingly hard to work all the corner cases.

Approach

  • a = max(), b = min(), c = sum() - a - b

Complexity

  • Time complexity: \(O(brain)\)

  • Space complexity: \(O(1)\)

Code



    fun triangleType(n: IntArray) = 
        listOf("none", "equilateral", "isosceles", "scalene")[
        if (2 * n.max() >= n.sum()) 0 else n.toSet().size]




    pub fn triangle_type(mut n: Vec<i32>) -> String {
        n.sort();
        (if n[2] >= n[0] + n[1] { "none" } else
        if n[0] == n[2] { "equilateral" } else
        if n[0] == n[1] || n[1] == n[2] { "isosceles" } else { "scalene" }).into()
    }



    string triangleType(vector<int>& nums) {
        int f[101]={}, m = 0, mf = 0, s = 0;
        for (int x: nums) mf = max(mf, ++f[x]), m = max(m, x), s += x;
        return array{"none", "scalene", "isosceles", "equilateral"}[2 * m >= s ? 0 : mf];
    }


18.05.2025

1931. Painting a Grid With Three Different Colors hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/992

Problem TLDR

Ways to 3-color m*n grid, no adjucents #hard #dp #matrix

Intuition

The naive DP works:

  • walk all possible ways to color the current column with DFS
  • pre-compute all possible columns (at max 5 length)
  • make a bitmask to compare with the previous
  • cache by the bitmask and the current column

    // masks
    // 00000
    // 12121
    // 12131     3^5 9*9*3 = 81*3 x 1000 = 100.000 ok

Then we can rewrite DFS into iterative, and we only have to keep the previous result. For each mask we can use its indice.

Then the matrix trick:

  • notice we do n operations of the same trasformation op(X) = Y
  • the operation can be described as a transition matrix: Y = X * M
  • doing it n times can be written as Y = X * M^n

The transition matrix is as follows:


mask1\mask2    a b c d ... 
a              1 x               x = 1 if a & b == 0
b
c                  1 x           x = 1 if c & d == 0
d
.
.
.

The starting X matrix is an identity matrix i == j ? 1 : 0.

The exponentiation trick is derived from the arithmetics: x^n = x^(2 * n/2 + n%2) = x^2 * x^(n/2) * x^(n%2)

Approach

  • use 3 bits in the mask to quick check m & mask == 0 later

Complexity

  • Time complexity: \(O(n)\), consider m small as constant

  • Space complexity: \(O(1)\)

Code


// 188ms
    fun colorTheGrid(m: Int, n: Int): Int {
        val M = 1000000007; val masks = ArrayList<Int>()
        fun msk(i: Int, curr: Int, prev: Int) {
            if (i > m) masks += curr else
            for (j in 1..3) if (j != prev) msk(i + 1, (curr shl 3) or (1 shl j), j)
        }
        val dp = HashMap<Pair<Int, Int>, Int>()
        fun dfs(i: Int, mask: Int): Int = if (i == n) 1 else 
            dp.getOrPut(i to mask) {
                masks.fold(0) { c, m -> if ((m and mask) == 0) (c + dfs(i + 1, m)) % M else c }
            }
        msk(1, 0, 0); return dfs(0, 0)
    }



// 98ms
    fun colorTheGrid(m: Int, n: Int): Int {
        val M = 1000000007; val ms = ArrayList<Int>()
        fun msk(i: Int, curr: Int, p: Int) {
            if (i > m) ms += curr else for (j in 1..3) if (j != p) 
                msk(i + 1, (curr shl 3) or (1 shl j), j)
        }
        msk(1, 0, 0); val s = ms.size; var n = n - 1; var res = 0
        var m = Array(s) { a -> IntArray(s) { if ((ms[a] and ms[it]) == 0) 1 else 0 }}
        fun mmul(b: Array<IntArray>) = Array(s) { IntArray(s) }.also { r ->
            for (i in 0..<s) for (j in 0..<s) for (k in 0..<s) 
                r[i][j] = (r[i][j] + ((1L * b[i][k] * m[k][j]) % M).toInt()) % M
        }
        var mn = Array(s) { y -> IntArray(s) { if (y == it) 1 else 0 }}
        while (n > 0) { if (n % 2 > 0) mn = mmul(mn); m = mmul(m); n /= 2 }
        for (i in 0..<s) for (j in 0..<s) res = (res + mn[i][j]) % M
        return res
    }



// 28ms https://leetcode.com/problems/painting-a-grid-with-three-different-colors/submissions/1637068717
    fun colorTheGrid(m: Int, n: Int): Int {
        val M = 1000000007; val masks = ArrayList<Int>()
        fun msk(i: Int, curr: Int, prev: Int) {
            if (i > m) masks += curr else
            for (j in 1..3) if (j != prev) msk(i + 1, (curr shl 3) or (1 shl j), j)
        }
        msk(1, 0, 0); var dp = IntArray(masks.size) { 1 }; var dp2 = IntArray(masks.size)
        for (i in 1..<n) {
            for (mask in masks.indices) {
                var c = 0
                for (m in masks.indices)
                    if ((masks[m] and masks[mask]) == 0) c = (c + dp[m]) % M
                dp2[mask] = c
            }
            dp = dp2.also { dp2 = dp }
        }
        return dp.fold(0) { r, t -> (r + t) % M }
    }



// 11ms
    pub fn color_the_grid(m: i32, n: i32) -> i32 {
        let M = 1000000007; let mut ms = vec![];
        fn msk(i: i32, c: i32, p: i32, ms: &mut Vec<i32>) {
            if i < 1 { ms.push(c); return }
            for j in 1..4 { if j != p { msk(i - 1, (c << 3) | (1 << j), j, ms) }}
        }; msk(m, 0, 0, &mut ms); let s = ms.len();
        let (mut dp, mut dp2) = (vec![1; s], vec![0; s]);
        for _ in 1..n { for mask in 0..s { let mut c = 0; for m in 0..s {
            if (ms[m] & ms[mask]) == 0 { c = (c + dp[m]) % M }}; dp2[mask] = c
            }; (dp, dp2) = (dp2, dp) }
        dp.into_iter().fold(0, |r, t| (r + t) % M)
    }



// 19ms
    int colorTheGrid(int m, int n) {
        vector<int> ms; 
        auto msk = [&](this const auto& msk, int i, int c, int p) -> void {
            if (!i) ms.push_back(c); else for (int j = 1; j < 4; ++j) 
            if (j != p) msk(i - 1, (c << 3) | (1 << j), j);
        }; 
        msk(m, 0, 0);
        int M = 1e9+7, s = size(ms), r = 0; vector<int> dp(s, 1), dp2(s);
        for (int i = 1; i < n; ++i) {
            for (int mask = 0; mask < s; ++mask) {
                int c = 0; for (int m = 0; m < s; ++m) 
                    if (!(ms[m] & ms[mask])) c = (c + dp[m]) % M;
                dp2[mask] = c;
            }
            dp.swap(dp2);
        }
        for (int x: dp) r = (r + x) % M; return r;
    }


17.05.2025

75. Sort Colors medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/991

Problem TLDR

Sort 0,1,2 array #medium #two_pointers

Intuition

The two-pass solution is trivial: count, then write. Was very close to implement the single-pass solution:

    // 2,0,2,1,1,0
    // z         t
    // i
    // 0       t 2
    //   i
    //   z
    //     i
    //     1 t 2
    //        
    // 0 0 1 1 2 2

    // 2 0 1
    // z   t
    // i
    //   t
    // 1 0 2

What was missing: the final check i == t to check if nums[t] is zero.

Approach

Single pass:

  • fill prefix with 0 and suffix with 2
  • skip 1
  • the corner case is 10: swap nums[t] with prefix if it is 0
  • or, we can make the final check i == t, then it is handled by the nums[i] == 0 condition

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


    fun sortColors(nums: IntArray): Unit {
        val c = IntArray(3); var i = 0
        for (x in nums) ++c[x]
        for (x in 0..2) while (c[x]-- > 0) nums[i++] = x
    }


    fun sortColors(n: IntArray): Unit {
        var z = 0; var t = n.size - 1; var i = 0
        while (i <= t)
            if (n[i] == 2) { n[i] = n[t]; n[t--] = 2 } 
            else if (n[i] == 0) { n[i++] = n[z]; n[z++] = 0 } 
            else i++
    }



    pub fn sort_colors(n: &mut Vec<i32>) {
        let (mut z, mut t, mut i) = (0, n.len() - 1, 0);
        while i <= t && t < n.len() { match n[i] {
            0 => { n.swap(i, z); i += 1; z += 1 }
            2 => { n.swap(i, t); t -= 1 }
            _ => { i += 1 }
        }}
    }



    void sortColors(vector<int>& n) {
        for (int i = 0, z = 0, t = size(n) - 1; i <= t;)
            if (n[i] == 0) n[i++] = n[z], n[z++] = 0;
            else if (n[i] == 2) n[i] = n[t], n[t--] = 2;
            else i++;
    }


16.05.2025

2901. Longest Unequal Adjacent Groups Subsequence II medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/990

Problem TLDR

Longest subsequence humming distance 1, alterating groups #medium #dp

Intuition

The naive DP works: consider each position, take or not. Cache by the current and the previous taken position.

Approach

Optimizations:

  • only the previous position matters for the cache; search for the tail after it
  • rewrite DFS into iterative backwards for
  • then reverse the iterations: for each i consider 0..i-1 prefixes, choose the longest
  • use the parents array to save only the lengths into dp array

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(n)\)

Code


// 166ms
    fun getWordsInLongestSubsequence(w: Array<String>, g: IntArray): List<String> {
        val dp = Array(w.size + 1) { listOf<String>() }
        for (i in 0..w.size) for (j in 0..<i)
            if (i == w.size || g[i] != g[j] && w[i].length == w[j].length &&
                w[i].indices.count { w[i][it] != w[j][it] } < 2)
                if (dp[j].size + 1 > dp[i].size) dp[i] = dp[j] + w[j]
        return dp[w.size]
    }



// 44ms https://leetcode.com/problems/longest-unequal-adjacent-groups-subsequence-ii/submissions/1635364675
    fun getWordsInLongestSubsequence(w: Array<String>, g: IntArray): List<String> {
        val dp = Array(w.size) { listOf<String>() }
        for (i in w.indices) {
            val wi = w[i]; val gi = g[i]
            for (j in 0..<i) if (g[i] != g[j] && wi.length == w[j].length) {
                val wj = w[j]; var c = 0
                for (k in wi.indices) {
                    if (wi[k] != wj[k]) c++
                    if (c > 1) break
                }
                if (c < 2 && dp[j].size + 1 > dp[i].size) dp[i] = dp[j] + wj
            }
        }
        var res = listOf<String>()
        for (j in w.indices) if (dp[j].size + 1 > res.size) res = dp[j] + w[j]
        return res
    }



// 31ms https://leetcode.com/problems/longest-unequal-adjacent-groups-subsequence-ii/submissions/1635402651
    fun getWordsInLongestSubsequence(w: Array<String>, g: IntArray): Array<String?> {
        val dp = IntArray(w.size + 1); val p = IntArray(dp.size)
        for (i in w.indices) {
            val wi = w[i]; val gi = g[i]
            for (j in 0..<i) if (g[i] != g[j] && wi.length == w[j].length) {
                val wj = w[j]; var c = 0
                for (k in wi.indices) {
                    if (wi[k] != wj[k]) c++
                    if (c > 1) break
                }
                if (c < 2 && dp[j] + 1 > dp[i]) { dp[i] = dp[j] + 1; p[i] = j + 1 }
            }
        }
        for (j in w.indices) if (dp[j] + 1 > dp[w.size]) { dp[w.size] = dp[j] + 1; p[w.size] = j + 1 }
        val res = Array<String?>(dp[w.size]) { null }; var x = w.size; var k = res.size - 1
        while (p[x] > 0) { res[k--] = w[p[x] - 1]; x = p[x] - 1 }
        return res
    }



// 304ms
    pub fn get_words_in_longest_subsequence(w: Vec<String>, g: Vec<i32>) -> Vec<String> {
        let mut dp = vec![Vec::<String>::new(); w.len() + 1];
        for i in 0..dp.len() { for j in 0..i { if 
            i == w.len() || g[i] != g[j] && w[i].len() == w[j].len() &&
            w[i].bytes().zip(w[j].bytes()).filter(|(a, b)| a != b).count() < 2 {
            if dp[j].len() + 1 > dp[i].len() { let mut s = dp[j].clone(); s.push(w[j].clone()); dp[i] = s }}}}
        dp[w.len()].clone()
    }



// 7ms https://leetcode.com/problems/longest-unequal-adjacent-groups-subsequence-ii/submissions/1635396131
    pub fn get_words_in_longest_subsequence(w: Vec<String>, g: Vec<i32>) -> Vec<String> {
        let mut dp = vec![0; w.len() + 1]; let mut p = vec![None; dp.len()];
        for i in 1..=w.len() { for j in 0..i {
            if (i == w.len() || (g[i] != g[j] && w[i].len() == w[j].len()
                && w[i].bytes().zip(w[j].bytes()).filter(|(a, b)| a != b).count() < 2))
            && dp[j] + 1 > dp[i] { dp[i] = dp[j] + 1; p[i] = Some(j); }
        }}
        let (mut res, mut i) = (Vec::with_capacity(dp[w.len()]), w.len());
        while let Some(j) = p[i] { res.push(w[j].clone()); i = j; }
        res.reverse(); res
    }



// 59ms
    vector<string> getWordsInLongestSubsequence(vector<string>& w, vector<int>& g) {
        int n = w.size(); vector<int> dp(n+1), p(n+1, -1); vector<string> r;
        for (int i = 1; i <= n; ++i) for (int j = 0; j < i; ++j) {
                bool ok = i == n
                    || (g[i] != g[j] && size(w[i]) == size(w[j])
                        && [&]{ int c=0;
                            for (int k=0; k<size(w[i]); ++k)
                                if (w[i][k]!=w[j][k] && ++c>=2) return false;
                            return true;
                        }());
                if (ok && dp[j] + 1 > dp[i]) dp[i] = dp[j] + 1, p[i] = j;
            }
        for (int i = n; p[i] != -1; i = p[i]) r.push_back(w[p[i]]);
        reverse(r.begin(), r.end()); return r;
    }


15.05.2025

2900. Longest Unequal Adjacent Groups Subsequence I easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/989

Problem TLDR

Longest subsequence alterating g #easy #gready

Intuition

Taking the first is always the optimal greedy strategy:

    // 101
    // 010

Approach

  • we actually don’t have to remember the last g[i], compare with the previous
  • O(n^2), O(1) memory solution: remove from words (c++)

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


// 22ms
    fun getLongestSubsequence(w: Array<String>, g: IntArray) = 
        g.indices.filter { it < 1 || g[it - 1] != g[it] }.map(w::get)




// 15ms
    fun getLongestSubsequence(w: Array<String>, g: IntArray) = buildList {
        for (i in g.indices) if (i < 1 || g[i] != g[i - 1]) this += w[i]
    }




// 1ms
    fun getLongestSubsequence(w: Array<String>, g: IntArray): List<String> {
        val res = ArrayList<String>()
        for (i in g.indices) if (i < 1 || g[i] != g[i - 1]) res += w[i]
        return res
    }




// 0ms
    pub fn get_longest_subsequence(mut w: Vec<String>, g: Vec<i32>) -> Vec<String> {
        for i in (1..g.len()).rev() { if g[i] == g[i - 1] { w.remove(i); }} w
    }




// 0ms
    pub fn get_longest_subsequence(w: Vec<String>, g: Vec<i32>) -> Vec<String> {
       w.into_iter().enumerate().filter(|&(i, _)| i < 1 || g[i - 1] != g[i]).map(|(_, w)| w).collect()
    }




// 0ms
    vector<string> getLongestSubsequence(vector<string>& w, vector<int>& g) {
        for(int i = w.size(); i-- > 1; ) if (g[i] == g[i-1]) w.erase(begin(w) + i);
        return w;
    }



14.05.2025

3337. Total Characters in String After Transformations II hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/988

Problem TLDR

t steps to convert char into next nums[c] chars #hard #dp #math

Intuition

Didn’t solve. Irrelevant chain of thoughts:


    // a -> bc                                        t = 1
    //      b -> cd
    //      c -> de    1c 2d 1e                       t = 2
    //           c -> de
    //          2d -> ef ef
    //           e -> fg       1d 3e 3f 1g            t = 3
    //                d -> ef
    //               3e -> fg fg fg
    //               3f -> gh gh gh
    //                g -> hi         1e 4f 6g 4h 1i   t = 4
    //                                                 ...
    //                                                 t = 26
    //   
    // exponentiation...
    // t = 492153482    /26 = 18 928 980.0769

    // 1hr hint "Model the problem as a matrix multiplication problem." lol"

How growth law described by matrix:


from\to
       a b c d e f g .. z
a        1 1                  nums[a] = 2
b          1 1 1 1            nums[b] = 4
c            1                nums[c] = 1
d              1 1 1          nums[d] = 3
e
..
z

Now, by applying the matrix into initial frequency we will make a single step: f = f x M. To make t steps: f_t = f x M^t.

The exponentiation trick is from math: a^t = a^(2 * t/2) + a^(2 * t%2)

Approach

  • what’s missing: matrix trick for dp

Complexity

  • Time complexity: \(O(s + log(t))\)

  • Space complexity: \(O(1)\)

Code


// 701ms
    fun lengthAfterTransformations(s: String, t: Int, nums: List<Int>): Int {
        var f = LongArray(26); for (c in s) ++f[c - 'a']; val M = 1000000007L
        var m = Array(26) { c -> LongArray(26) }; var t = t; var res = 0L
        for (i in 0..25) for (j in i + 1..<i + nums[i] + 1) m[i][j % 26] = 1
        fun matMul(m1: Array<LongArray>): Array<LongArray> {
            val res = Array(26) { LongArray(26)}
            for (i in 0..25) for (j in 0..25) for (k in 0..25)
                res[i][j] = (res[i][j] + (m1[i][k] * m[k][j]) % M + M) % M
            return res
        }
        var mt = Array(26) { y -> LongArray(26) { x -> if (x == y) 1 else 0 }}
        while (t > 0) { if (t % 2 > 0) mt = matMul(mt); m = matMul(m); t /= 2 }
        for (j in 0..25) for (k in 0..25) res = (res + (f[k] * mt[k][j]) % M) % M
        return res.toInt()
    }



// 24ms
    pub fn length_after_transformations(s: String, mut t: i32, n: Vec<i32>) -> i32 {
        const M: u64 = 1_000_000_007; let (mut f, mut m) = ([0u64; 26], [[0u64; 26]; 26]); 
        for b in s.bytes() { f[(b - b'a') as usize] += 1 }
        for i in 0..26 { for j in 1..=n[i] as usize { m[i][(i + j) % 26] = 1 }}
        let mut e = [[0u64; 26]; 26]; for i in 0..26 { e[i][i] = 1 }
        let mul = |a: &[[u64; 26]; 26], b: &[[u64; 26]; 26]| {
            let mut c = [[0u64; 26]; 26];
            for i in 0..26 { for k in 0..26 { let v = a[i][k]; 
                if v != 0 { for j in 0..26 { c[i][j] = (c[i][j] + v * b[k][j]) % M; }}
            }}; c
        };
        while t > 0 { if t & 1 == 1 { e = mul(&e, &m) }; m = mul(&m, &m); t >>= 1 }
        let mut r = 0u64; for i in 0..26 { for j in 0..26 { r = (r + f[i] * e[i][j]) % M }}
        r as _
    }



// 111ms
    int lengthAfterTransformations(string s, int t, vector<int>& n) {
        long long f[26] = {}, m[26][26] = {}, e[26][26] = {}, c[26][26], r = 0;
        const long long M = 1000000007; for (auto b : s) f[b - 'a']++;
        for (int i = 0; i < 26; i++) for (int j = 1; j <= n[i]; j++) m[i][(i + j) % 26] = 1;
        for (int i = 0; i < 26; i++) e[i][i] = 1;
        auto mul = [&](long long A[26][26], long long B[26][26]) {
            memset(c, 0, sizeof c);
            for (int i = 0; i < 26; i++) for (int k = 0; k < 26; k++) if (A[i][k])
                for (int j = 0; j < 26; j++) c[i][j] = (c[i][j] + A[i][k] * B[k][j]) % M;
            memcpy(A, c, sizeof c);
        };
        while (t) { if (t & 1) mul(e, m); mul(m, m); t >>= 1; }
        for (int i = 0; i < 26; i++) for (int j = 0; j < 26; j++) r = (r + f[i] * e[i][j]) % M;
        return r;
    }


13.05.2025

3335. Total Characters in String After Transformations I medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/987

Problem TLDR

String length after t shifts c=c+1,z=ab #medium #dp

Intuition

My chain-of-thougths:


    // a + 25 = z    len = 1
    // a + 26 = z + 1 = a + b    len = 2
    // b + 24 = z
    // b + 25 = z + 1 = a + b    len = 2

    // ab + 25 = abz
    // ab + 26 = bcab

    // each char grows at its own rate
    // naive dp - TLE

Each char has it’s own growth law that can be cached by remaining time.

Another intuition is from the hint: just simulate the process for chars frequencies.

Approach

  • speed up by quick-jumping to z
  • for simultaion we can jump to z too, full 0..26 circle would produce a new char for each existing char

Complexity

  • Time complexity: \(O(t + s)\)

  • Space complexity: \(O(t)\) for dp, O(1) for the simulation

Code


// 420ms https://leetcode.com/problems/total-characters-in-string-after-transformations-i/submissions/1632533567
    fun lengthAfterTransformations(s: String, t: Int): Int {
        val M = 1000000007; val dp = HashMap<Pair<Char, Int>, Int>()
        fun dfs(c: Char, t: Int): Int = if (t == 0) 1 else dp.getOrPut(c to t) {
            if (c == 'z') (dfs('a', t - 1) + dfs('b', t - 1)) % M
            else if (t >= 'z' - c) dfs('z', t - ('z' - c)) else dfs(c + 1, t - 1)
        }
        var res = 0; for (c in s) res = (res + dfs(c, t)) % M
        return res
    }


// 57ms
    fun lengthAfterTransformations(s: String, t: Int): Int {
        val M = 1000000007; val dp = Array(26) { IntArray(t + 1) { -1 }}
        fun dfs(c: Int, t: Int): Int = if (t == 0) 1 else 
            if (dp[c][t] >= 0) dp[c][t] else
            (if (c == 25) (dfs(0, t - 1) + dfs(1, t - 1)) % M
            else if (t >= 25 - c) dfs(25, t - (25 - c)) else dfs(c + 1, t - 1))
            .also { dp[c][t] = it }
        var res = 0; for (c in s) res = (res + dfs(c - 'a', t)) % M
        return res
    }



// 28ms 
    fun lengthAfterTransformations(s: String, t: Int): Int {
        var f = IntArray(26); for (c in s) ++f[c - 'a']
        var f2 = IntArray(26); val M = 1000000007; var res = 0
        for (i in 1..t) {
            f2[0] = f[25]; for (c in 0..24) f2[c + 1] = f[c]
            f2[1] = (f2[1] + f[25]) % M
            f = f2.also { f2 = f }
        }
        for (c in f) res = (res + c) % M
        return res
    }



// 11ms https://leetcode.com/problems/total-characters-in-string-after-transformations-i/submissions/1632555700
    fun lengthAfterTransformations(s: String, t: Int): Int {
        var f = IntArray(26); for (c in s) ++f[c - 'a']
        val M = 1000000007; var res = 0
        for (i in 1..t / 26) for (c in 0..25) {
            val a = (26 - c) % 26; f[a] = (f[a] + f[25 - c]) % M
        }
        for (c in 0..<t % 26) {
            val a = (26 - c) % 26; f[a] = (f[a] + f[25 - c]) % M
        }
        for (c in f) res = (res + c) % M
        return res
    }



// 0ms https://leetcode.com/problems/total-characters-in-string-after-transformations-i/submissions/1632553112
    pub fn length_after_transformations(s: String, t: i32) -> i32 {
        let (mut f, M) = ([0; 26], 1000000007);
        for b in s.bytes() { f[(b - b'a') as usize] += 1 }
        for i in 0..t / 26 { for c in 0..26 {
                let a = (26 - c) % 26; f[a] = (f[a] + f[25 - c]) % M
        }}
        for c in 0..t as usize % 26 {
            let a = (26 - c) % 26; f[a] = (f[a] + f[25 - c]) % M
        }
        f.iter().fold(0, |r, c| (r + c) % M)
    }



// 6ms https://leetcode.com/problems/total-characters-in-string-after-transformations-i/submissions/1632563226
    int lengthAfterTransformations(string s, int t) {
        int f[26]={}, r = 0, M = 1e9+7; for (char c: s) ++f[c - 'a'];
        for (int i = 0; i < t / 26; ++i) for (int c = 0; c < 26; ++c) {
            int a = (26 - c) % 26; f[a] = (f[a] + f[25 - c]) % M;
        }
        for (int c = 0; c < t % 26; ++c) {
            int a = (26 - c) % 26; f[a] = (f[a] + f[25 - c]) % M;
        }
        for (int c: f) r = (r + c) % M; return r;
    }


12.05.2025

2094. Finding 3-Digit Even Numbers easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/986

Problem TLDR

Triple digit even numbers from digits #easy #backtrack

Intuition

This problem is not easy if you didn’t spot the problem size of 1000 possible number total.

The backtracking works and is the fastest: pick a digit one-by-one, increase counter, compare with frequency, decrease back after.

Approach

  • 3-loop solution is also possible (but 2ms vs 1ms of backtracking in Kotlin, which is unexplainable to me rn)

Complexity

  • Time complexity: \(O(range)\) or O(9^3) for backtracking DFS: depth is 3, 9 digits each

  • Space complexity: \(O(answer)\)

Code


// 41ms
    fun findEvenNumbers(digits: IntArray) =
        (100..999 step 2).filter { n ->
            "$n".groupBy { it }.all { (k, v) -> v.size <= digits.count { it == k - '0' }}
        }



// 2ms 
    fun findEvenNumbers(digits: IntArray): IntArray {
        val f = IntArray(10); for (d in digits) ++f[d]
        val r = IntArray(450); var i = 0
        for (a in 1..9) if (f[a] > 0) {
            f[a]--
            for (b in 0..9) if (f[b] > 0) {
                f[b]--
                for (c in 0..9 step 2) if (f[c] > 0) r[i++] = a * 100 + b * 10 + c
                f[b]++
            }
            f[a]++
        }
        return r.copyOf(i)
    }



// 1ms https://leetcode.com/problems/finding-3-digit-even-numbers/submissions/1631643083
    fun findEvenNumbers(digits: IntArray): List<Int> {
        val f = IntArray(10); for (d in digits) ++f[d]
        val res = ArrayList<Int>(); val taken = IntArray(10)
        fun dfs(soFar: Int, start: Int) {
            if (soFar > 99) {
                if (soFar % 2 == 0) res += soFar
            } else for (d in start..9) if (taken[d] < f[d]) {
                taken[d]++; dfs(soFar * 10 + d, 0); taken[d]--
            }
        }
        dfs(0, 1)
        return res
    }



// 0ms
    pub fn find_even_numbers(digits: Vec<i32>) -> Vec<i32> {
        let (mut f, mut r) = ([0; 10], vec![]);
        for d in digits { f[d as usize] +=  1}
        for a in 1..10 { if f[a] > 0 { f[a] -= 1;
            for b in 0..10 { if f[b] > 0 { f[b] -= 1;
                for c in (0..10).step_by(2) { if f[c] > 0 { 
                    r.push((a * 100 + b * 10 + c) as i32 )}}
             f[b] += 1 }}
        f[a] += 1 }}; r
    }



// 0ms
    vector<int> findEvenNumbers(vector<int>& digits) {
        int f[10]={}; vector<int> r; for (int& d: digits) ++f[d];
        for (int x = 100; x < 1000; x += 2) {
            int c[10]={}, g = 1, d = x; while (d) g &= ++c[d % 10] <= f[d % 10], d /= 10;
            if (g) r.push_back(x);
        }; return r;
    }


11.05.2025

1550. Three Consecutive Odds easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/985

Problem TLDR

3 odds #easy #bitmask

Intuition

Count odds.

Approach

  • use bit & 1 to check for odds
  • use bitmask 0b111 = 7 to check for 3 odds

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

```kotlin []

// 22ms fun threeConsecutiveOdds(a: IntArray) = “1, 1, 1” in “” + a.map { it % 2 }

```kotlin 

// 21ms
    fun threeConsecutiveOdds(a: IntArray) =
        a.asList().windowed(3).any { it.all { it % 2 > 0 }}



// 23ms
    fun threeConsecutiveOdds(a: IntArray) =
        a.asList().windowed(3).any { it.reduce(Int::and) % 2 > 0 }



// 4ms
    fun threeConsecutiveOdds(a: IntArray) = (1..<a.size - 1)
        .any { a[it - 1] and a[it] and a[it + 1] % 2 > 0 }



// 0ms https://leetcode.com/problems/three-consecutive-odds/submissions/1630809266
    fun threeConsecutiveOdds(a: IntArray): Boolean {
        var c = 0
        return a.any { c = (it % 2) * (c + 1); c > 2 }
    }



// 0ms
    fun threeConsecutiveOdds(a: IntArray): Boolean {
        var c = 0
        return a.any { c = it and 1 or (c shl 1) and 7; c > 6 }
    }



// 0ms https://leetcode.com/problems/three-consecutive-odds/submissions/1630796680
    pub fn three_consecutive_odds(a: Vec<i32>) -> bool {
        a[..].windows(3).any(|w| 0 < 1 & w[0] & w[1] & w[2])
    }



// 0ms
    bool threeConsecutiveOdds(vector<int>& a) {
        for(int c = 0; int &x: a) if ((c = x & 1 | (c << 1) & 7) > 6)
        return 1; return 0;
    }


10.05.2025

2918. Minimum Equal Sum of Two Arrays After Replacing Zeros medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/984

Problem TLDR

Min equal array sum, fill zeros #medium

Intuition

Any zero place can act as any number. Compare minimum sums by filling zeros with ones, then equalize.

Approach

  • the interesting golf is how to make it CPU-branchless: if (x == 0) 1 else 0 can be written as ((x | -x) >> 31) + 1 where x | -x would will everything but a sign bit, transforming into -1 for any non-zero value

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

Kotlin Rust C++
image.png image.png image.png

// 523ms
    fun minSum(n1: IntArray, n2: IntArray): Long {
        val s1 = n1.sumOf { 1L * max(1, it) }; val s2 = n2.sumOf { 1L * max(1, it) }
        return if (s1 < s2 && 0 !in n1 || s1 > s2 && 0 !in n2) -1 else max(s1, s2)
    }



// 411ms https://leetcode.com/problems/minimum-equal-sum-of-two-arrays-after-replacing-zeros/submissions/1630261946
    fun minSum(nums1: IntArray, nums2: IntArray): Long {
        var s1 = 0L; var s2 = 0L; var z1 = 0; var z2 = 0
        for (x in nums1) { s1 += x + ((x or -x).ushr(31) xor 1); z1 = z1 or ((x or -x).ushr(31) xor 1) }
        for (x in nums2) { s2 += x + ((x or -x).ushr(31) xor 1); z2 = z2 or ((x or -x).ushr(31) xor 1) }
        return if (s1 < s2 && z1 < 1 || s1 > s2 && z2 < 1) -1 else max(s1, s2)
    }


// 8ms https://leetcode.com/problems/minimum-equal-sum-of-two-arrays-after-replacing-zeros/submissions/1630002606
    pub fn min_sum(n1: Vec<i32>, n2: Vec<i32>) -> i64 {
        let s1: i64 = n1.iter().map(|&n| n.max(1) as i64).sum();
        let s2: i64 = n2.iter().map(|&n| n.max(1) as i64).sum();
        let z1 = n1.contains(&0); let z2 = n2.contains(&0);
        if (s1 < s2 && !z1) || (s1 > s2 && !z2) { -1 } else { s1.max(s2) }
    }



// 43ms https://leetcode.com/problems/minimum-equal-sum-of-two-arrays-after-replacing-zeros/submissions/1630272912
    long long minSum(vector<int>& n1, vector<int>& n2) {
        long long s1 = size(n1), s2 = size(n2); int z1 = s1, z2 = s2;
        for (int& n: n1) s1 += n + ((n|-n)>>31), z1 += (n|-n)>>31;
        for (int& n: n2) s2 += n + ((n|-n)>>31), z2 += (n|-n)>>31;
        return s1 < s2 && !z1 || s1 > s2 && !z2 ? -1 : max(s1, s2);
    }


09.05.2025

3343. Count Number of Balanced Permutations hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/983

Problem TLDR

Permutations of even-odd position sums equal #hard #dp #math

Intuition

Didn’t solved. Chain-of-thoughts (mostly irrelevant):

    // 80^80 (will TLE)
    // digits are uniq
    // partition into 2 buckets size/2
    // 123     12       3
    // 12342   132      42
    // i.i.i
    // let's brute force first
    // permutation: can take next any
    // we only have 10 digits: 0,1,2,3,4,5,6,7,8,9
    // we can count them first
    // every even frequency is good to split -- count must be equal
    // every odd frequency should be brute-forced
    // 18 minutes
    // we can calc a sum, then search for a bag of digits to match sum / 2
    // 28 minutes
    // 44 minutes, idea of bugs is not working for 112, a = 2, b = 11
    // the problem with duplicates "11" - not considered a permutation
    // 55 minutes, idea to keep both halves in bags
    // 60 minutes: wrong answer for 53374    4 instead of 6
    // looking for hints:
    // freq (known)
    // dp (somewhat known)
    // useless?
    // 1:15 look for solution

Working solution:

  • for every digit i = 9..0
  • take up to j = frequency[i] numbers on the one half
  • another half would contain frequency[i] - j automatically
  • sum would change by i * j digit times how many we take
  • search for the final condition

Now the interesting part - combinatorics. How many permutations we have?

  • we take x digits and place it at odd positions - that is Combinations(x, o)
  • and another half Combinations(frequency[i] - x, e)

How to count combinations C(a, b)?

  • precompute C[A][B] like this: i in 0..a, j in 1..i, c[i][j] = c[i - 1][j] + c[i - 1][j - 1] (just remember, but better to gain an intuition why it is: permutation is c[i] += c[i - 1], Pascal triangle is computing over previos row, and why it is relevant https://www.perplexity.ai/search/why-combinations-c-i-j-c-i-j-1-5fkL_k8BRXmllKs_FieusA)

Approach

  • gave up after 1hr
  • whats missing: combinatorics intuition

Complexity

  • Time complexity: \(O(n^3)\)

  • Space complexity: \(O(n^3)\)

Code


    fun countBalancedPermutations(s: String): Int {
        var sum = 0; val f = IntArray(10); for (x in s) { ++f[x - '0']; sum += x - '0' }
        val c = Array(81) { LongArray(81)}; val M = 1000000007L
        for (i in s.indices) { c[i][0] = 1; for (j in 1..i) c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % M }
        data class K(val i: Int, val odd: Int, val balance: Int); val dp = HashMap<K, Long>()
        fun dfs(i: Int, o: Int, e: Int, b: Int): Long =  if (o == 0 && e == 0 && b == 0) 1L
            else if (i < 0 || o < 0 || e < 0 || b < 0) 0L else dp.getOrPut(K(i, o, b)) {
                var res = 0L; for (j in 0..f[i]) res += 
                    (((c[o][j] * c[e][f[i] - j]) % M) * dfs(i - 1, o - j, e - f[i] + j, b - i * j)) % M
                res % M
            }
        return if (sum % 2 > 0) 0 else dfs(9, (1 + s.length) / 2, s.length / 2, sum / 2).toInt()
    }




    pub fn count_balanced_permutations(s: String) -> i32 {
        let (mut sum, mut f, mut c, M) = (0, [0; 10], [[0; 81]; 81], 1000000007); 
        for b in s.bytes() { f[(b - b'0') as usize] += 1; sum += (b - b'0') as i64 }
        if sum & 1 > 0 { return 0 }; let mut dp = [[[-1; 81]; 81]; 361];
        for i in 0..81 { c[i][0] = 1; for j in 1..=i { c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % M }}
        fn dfs(i: i64, o: i64, e: i64, b: i64, c: &[[i64; 81]; 81], dp: &mut [[[i64; 81]; 81]; 361], f: &[i64; 10]) -> i64 {
            if o == 0 && e == 0 && b == 0 { return 1 } else if i.min(o).min(e).min(b) < 0 { return 0 }
            if dp[b as usize][i as usize][o as usize] >= 0 { return dp[b as usize][i as usize][o as usize] }; 
            let (mut r, M) = (0, 1000000007);
            for j in 0..=f[i as usize] { 
                let k = f[i as usize] - j; let comb = (c[o as usize][j as usize] * c[e as usize][k as usize]) % M;
                let next = dfs(i - 1, o - j, e - k, b - i * j, c, dp, f);
                r = (r + (comb * next) % M) % M
            } 
            dp[b as usize][i as usize][o as usize] = r; r
        } dfs(9, (1 + s.len() as i64) / 2, s.len() as i64 / 2, sum / 2, &c, &mut dp, &f) as _
    }



    int countBalancedPermutations(string s) {
        int sum = 0, f[10]={}, c[81][81]={}, dp[81][81][361]={}, M = 1e9+7; 
        for(auto c: s) { ++f[c - '0']; sum += c - '0'; }; if (sum & 1 > 0) return 0;
        for (int i = 0; i < 81; ++i) 
            { c[i][0] = 1; for (int j = 1; j <= i; ++j) c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % M; }
        auto d = [&](this const auto& d, int i, int o, int e, int b) -> int {
            if (o == 0 && e == 0 && b == 0) return 1; if (i < 0 || o < 0 || e < 0 || b < 0) return 0;
            if (dp[i][o][b]) return dp[i][o][b] - 1;
            int r = 0;
            for (int j = 0; j <= f[i]; ++j) {
                int k = f[i] - j; int comb = (1LL * c[o][j] * c[e][k]) % M;
                int next = d(i - 1, o - j, e - k, b - i * j);
                r = (1LL * r + (1LL * comb * next) % M) % M;
            }
            dp[i][o][b] = r + 1; return r;
        };
        return d(9, (1 + size(s)) / 2, size(s) / 2, sum / 2);
    }


08.05.2025

3342. Find Minimum Time to Reach Last Room II medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/982

Problem TLDR

Fastest travel in graph, alternating dt=1,2 #medium #bfs

Intuition

The naive Dijkstra without heap would give TLE. With heap it is accepted.

Approach

Some optimizations implementation details

  • return result as fast as possible
  • no need to store the best time and compare it if heap is already picks the best
  • mark visited by mutating the graph (not production code, time golf)

Complexity

  • Time complexity: \(O(V + ElogV)\)

  • Space complexity: \(O(V)\)

Code


// 47ms https://leetcode.com/problems/find-minimum-time-to-reach-last-room-ii/submissions/1628359473
    fun minTimeToReach(g: Array<IntArray>): Int {
        val w = g[0].size - 1; val h = g.size - 1
        val q = PriorityQueue<IntArray>(compareBy { it[0] })
        val d = intArrayOf(0, 1, 0, -1, 0); q += intArrayOf(0, 0, 0, 1)
        while (q.size > 0) {
            val (t, x, y, dt) = q.poll()
            for (i in 0..3) {
                val y = y + d[i]; val x = x + d[i + 1]
                if (x !in 0..w || y !in 0..h || g[y][x] < 0) continue
                val t = dt + max(t, g[y][x]); if (x == w && y == h) return t
                g[y][x] = -1; q += intArrayOf(t, x, y, 3 - dt)
            }
        }
        return 0
    }


// 11ms https://leetcode.com/problems/find-minimum-time-to-reach-last-room-ii/submissions/1628358131
    pub fn min_time_to_reach(mut g: Vec<Vec<i32>>) -> i32 {
        let (mut w, mut h) = (g[0].len() - 1, g.len() - 1);
        let (mut d, mut q) = ([0, 1, 0, -1, 0], BinaryHeap::from([(0, 0, 0, 1)]));
        while let Some((t, x, y, dt)) = q.pop() {
            for i in 0..4 {
                let y = (y as i32 + d[i]) as usize; let x = (x as i32 + d[i + 1]) as usize;
                if x > w || y > h || g[y][x] < 0 { continue }
                let t = dt + (-t).max(g[y][x]); if x == w && y == h { return t }
                g[y][x] = -1; q.push((-t, x, y, 3 - dt))
            }
        } 0
    }



// 0ms https://leetcode.com/problems/find-minimum-time-to-reach-last-room-ii/submissions/1628349530
    int minTimeToReach(vector<vector<int>>& g) {
        priority_queue<tuple<int, int, int, int>, vector<tuple<int, int, int, int>>, greater<>> q;
        q.emplace(0, 0, 0, 1); int h = size(g) - 1, w = size(g[0]) - 1, d[] = {0, 1, 0, -1, 0};
        while (size(q)) {
            auto [t1, x1, y1, dt] = q.top(); q.pop();
            for (int i = 0; i < 4; ++i) {
                int x = x1 + d[i]; int y = y1 + d[i + 1];
                if (min(x, y) < 0 || x > w || y > h || g[y][x] < 0) continue;
                int t = dt + max(t1, g[y][x]); if (x == w && y == h) return t;
                g[y][x] = -1; q.emplace(t, x, y, 3 - dt);
            }
        } return 0;
    }


07.05.2025

3341. Find Minimum Time to Reach Last Room I medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/981

Problem TLDR

Fastest path in graph #medium #bfs

Intuition

Use BFS, track time.

Approach

  • use time-improvement condition, or a Heap (heap is faster)

Complexity

  • Time complexity: \(O(V^2)\), or (E + V)logV for heap

  • Space complexity: \(O(V)\)

Code


// 184ms
    fun minTimeToReach(moveTime: Array<IntArray>): Int {
        val w = moveTime[0].size; val time = IntArray(moveTime.size * w) { Int.MAX_VALUE }
        val q = ArrayDeque<Int>(); q += 0; time[0] = 0; val dxy = intArrayOf(-1, 1, -w, w)
        while (q.size > 0) {
            val xy = q.removeFirst(); val x1 = xy % w; val y1 = xy / w; val t = time[xy]
            for (d in dxy) {
                val xy2 = xy + d; val y2 = xy2 / w; val x2 = xy2 % w
                if (xy2 in 0..<time.size && (y1 == y2 || x1 == x2)) {
                    val t2 = 1 + max(t, moveTime[y2][x2])
                    if (t2 < time[xy2]) { time[xy2] = t2; q += xy2 }
                }
            }
        }
        return time.last()
    }



// 163ms https://leetcode.com/problems/find-minimum-time-to-reach-last-room-i/submissions/1627622531
    fun minTimeToReach(moveTime: Array<IntArray>): Int {
        val w = moveTime[0].size; val n = w * moveTime.size - 1
        val q = PriorityQueue<IntArray>(compareBy { it[1] })
        q += intArrayOf(0, 0); val dxy = intArrayOf(-1, 1, -w, w)
        while (q.size > 0) {
            val (xy, t) = q.poll(); val x1 = xy % w; val y1 = xy / w
            if (xy == n) return t
            for (d in dxy) {
                val xy2 = xy + d; val y2 = xy2 / w; val x2 = xy2 % w
                if (xy2 in 0..n && (y1 == y2 || x1 == x2) && moveTime[y2][x2] >= 0) {
                    q += intArrayOf(xy2, (1 + max(t, moveTime[y2][x2])))
                    moveTime[y2][x2] = -1
                }
            }
        }
        return -1
    }



// 0ms https://leetcode.com/problems/find-minimum-time-to-reach-last-room-i/submissions/1627635883
    pub fn min_time_to_reach(mut move_time: Vec<Vec<i32>>) -> i32 {
        let mut w = move_time[0].len(); let n = w * move_time.len() - 1;
        let mut q = BinaryHeap::from([(0, 0)]);
        let dxy = [-1, 1, -(w as i32), w as i32];
        while let Some((t, xy)) = q.pop() {
            let (x1, y1) = (xy % w, xy / w);
            if xy == n { return -t }
            for d in dxy {
                let xy2 = (xy as i32 + d) as usize; let (y2, x2) = (xy2 / w, xy2 % w);
                if xy2 <= n && (y1 == y2 || x1 == x2) && move_time[y2][x2] >= 0 {
                    q.push((-1 + t.min(-move_time[y2][x2]), xy2));
                    move_time[y2][x2] = -1
                }
            }
        } 0
    }


// 0ms https://leetcode.com/problems/find-minimum-time-to-reach-last-room-i/submissions/1627644831
    int minTimeToReach(vector<vector<int>>& g) {
        int h = size(g), w = size(g[0]), n = h * w - 1;
        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> q;
        int dir[4] = {-1, 1, -w, w}; q.push({0, 0});
        while (size(q)) {
            auto [t, u] = q.top(); q.pop(); if (u == n) return t;
            for (int i = 0; i < 4; ++i) {
                int v = u + dir[i];
                if (v >= 0 && v <= n && (u / w == v / w || u % w == v % w) && g[v / w][v % w] >= 0) 
                    q.push({max(t, g[v / w][v % w]) + 1, v}), g[v / w][v % w] = -1;
            }
        } return 0;
    }


06.05.2025

1920. Build Array from Permutation easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/980

Problem TLDR

n[n[i]] #easy

Intuition

The follow up is more tricky: we have to store the result and preserver the initial values somehow, shift bits or do * and % operations.

Approach

  • do golf
  • do follow-up

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\) or O(1)

Code


// 3ms
    fun buildArray(n: IntArray) = n.map { n[it] }



// 2ms
    fun buildArray(n: IntArray): IntArray {
        for (i in n.indices) n[i] += (n[n[i]] and 0xFFFF) shl 16
        for (i in n.indices) n[i] = n[i] shr 16
        return n;
    }



// 1ms
    fun buildArray(n: IntArray) = IntArray(n.size) { n[n[i]] }



// 0ms
    pub fn build_array(mut n: Vec<i32>) -> Vec<i32> {
        for i in 0..n.len() { n[i] |= (n[n[i] as usize] & 0xFFFF) << 16 }
        for i in 0..n.len() { n[i] >>= 16 } n
    }



// 0ms
    pub fn build_array(n: Vec<i32>) -> Vec<i32> {
        n.iter().map(|&x| n[x as usize]).collect()
    }



// 0ms
    vector<int> buildArray(vector<int>& n) {
        vector<int> r(size(n));
        for (int i = 0; auto& x: n) r[i++] = n[x];
        return r;
    }


05.05.2025

790. Domino and Tromino Tiling meidum blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/979

Problem TLDR

Ways to fill 2xn board with I,L shapes #medium #dp

Intuition

Let’s full-search by trying every possible way of placing every domino shape at current position i with Depth-First Search. If the final column is filled, count this way as 1. Result only depends on the current position i and the column filled condition of 00 as empty, 01 as bottom filled and 10 as top filled. Can be cached.

Another fun way to optimize the solution is to look at the pattern of the results:

1
1
2
5
11     5 * 2 + 1
24    11 * 2 + 2
53    24 * 2 + 5
117   53 * 2 + 11
258
569
1255
2768

Approach

  • for dp we can either go i+2 or introduce another filled state 11
  • there is also an O(log(n)) solution by doing matrix^n
    // [ a_n   ]   [ 2 0 1 ] [ a_{n-1} ]
    // [a_{n-1}] = [ 1 0 0 ] [ a_{n-2} ]
    // [a_{n-2}]   [ 0 1 0 ] [ a_{n-3} ]

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\), or O(1) for the arithmetic solution

Code


// 6ms
    fun numTilings(n: Int): Int {
        val M = 1_000_000_007; val dp = HashMap<Pair<Int, Int>, Int>()
        fun dfs(i: Int, tb: Int): Int =  if (i > n) 0 else if (i == n) 
        { if (tb == 0) 1 else 0 } else dp.getOrPut(i to tb) {
            val vertical = if (tb > 0) 0 else dfs(i + 1, 0b00)
            val horizontal = dfs(i + 2, 0b00)
            val trtop = if (tb == 0b10) 0 else dfs(i + 1, 0b10)
            val trbot = if (tb == 0b01) 0 else dfs(i + 1, 0b01)
            (((vertical + horizontal) % M + trtop) % M + trbot) % M
        }
        return dfs(0, 0)
    }


// 0ms
    fun numTilings(n: Int): Int {
        var a = 1; var b = 1; var c = 2; val m = 1000000007
        for (i in 3..n) { val t = a; a = b; b = c; c = ((2 * b) % m + t) % m }
        return if (n < 2) 1 else if (n < 3) 2 else c
    }



// 0ms
    pub fn num_tilings(n: i32) -> i32 {
        let (mut a, mut b, mut c, m) = (1, 1, 2, 1000000007);
        for i in 3..=n { (a, b, c) = (b, c, ((2 * c) % m + a) % m) }
        if n < 2 { 1 } else if n < 3 { 2 } else { c }
    }



// 0ms
    int numTilings(int n) {
        int c = 2; 
        for (int i = 3, t, a = 1, b = 1, m = 1e9+7; i <= n; ++i) 
            t = a, a = b, b = c, c = ((2 * b) % m + t) % m;
        return n < 2 ? 1 : n < 3 ? 2 : c;
    }


04.05.2025

1128. Number of Equivalent Domino Pairs easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/978

Problem TLDR

Dominoes pairs #easy #hash

Intuition

The brute-force O(n^2) is accepted. More optimal O(n) is the counting pattern: count visited pairs, each new will pair with previous count.

Approach

  • we can try to CPU-branching optimize by using a symmetric cache key a * b + 10 * (a + b)
  • otherwise, space-optimizations are possible too: we have a symmetric matrix of 9x9 and a total of 45 uniq keys

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 4ms
    fun numEquivDominoPairs(ds: Array<IntArray>): Int {
        val m = Array(10) { IntArray(10) }
        return ds.sumOf { (a, b) -> m[min(a, b)][max(a, b)]++ }
    }



// 2ms https://leetcode.com/problems/number-of-equivalent-domino-pairs/submissions/1625039917
fun numEquivDominoPairs(ds: Array<IntArray>): Int {
    val m = IntArray(262); var c = 0
    for ((a, b) in ds) c += m[a * b + 10 * (a + b)]++
    return c
}



// 0ms
    pub fn num_equiv_domino_pairs(ds: Vec<Vec<i32>>) -> i32 {
        let mut m = [0; 100];
        ds.iter().map(|d| { 
            let k = (d[0].min(d[1]) * 10 + d[0].max(d[1])) as usize; 
            let c = m[k]; m[k] += 1; c
        }).sum()
    }



// 0ms
    int numEquivDominoPairs(vector<vector<int>>& ds) {
        int m[100], c = 0;
        for (auto& d: ds) c += m[min(d[0], d[1]) * 10 + max(d[0], d[1])]++;
        return c;
    }


03.05.2025

1007. Minimum Domino Rotations For Equal Row medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/977

Problem TLDR

Min swaps to make a top or bottom row #medium

Intuition

It’s all about the implementation and edge cases. Consider counting the frequencies for the top and for the bottom row. Then detect a dominant value. Then check it can fill the row.

Approach

  • first domino contains a dominant value
  • consider both values as possible dominant
  • we can use a recursion, or a single iteration with four counters (can be less?)
  • in jvm test machine two passes are faster than a single pass, possible beacuse of the instructions prediction or cache can’t handle too many variables at once

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 19ms
    fun minDominoRotations(tops: IntArray, bottoms: IntArray, d: Int = 0): Int =
    if (d < 1) {
        val a = minDominoRotations(tops, bottoms, tops[0])
        if (a < 0) minDominoRotations(tops, bottoms, bottoms[0]) else a
    } else if (tops.indices.any { tops[it] != d && bottoms[it] != d }) -1
    else tops.size - max(tops.count { it == d }, bottoms.count { it == d })



// 6ms
    fun minDominoRotations(top: IntArray, bottom: IntArray): Int {
        var d1 = top[0]; var d2 = bottom[0]
        var a = top.size; var b = a; var c = a; var d = a
        for (i in 0..<a) {
            val tp = top[i]; val bt = bottom[i]
            if (tp != d1 && bt != d1) if (d2 == 0) return -1 else d1 = 0
            if (tp != d2 && bt != d2) if (d1 == 0) return -1 else d2 = 0
            if (tp == d1) --a else if (tp == d2) --b
            if (bt == d1) --c else if (bt == d2) --d
        }
        return min(min(a, b), min(c, d))
    }



// 4ms
    fun minDominoRotations(top: IntArray, bottom: IntArray): Int {
        var d = top[0]; var a = 0; var b = 0
        for (i in top.indices) {
            if (top[i] != d && bottom[i] != d) { a  = -1; b = -1; break }
            if (top[i] == d) ++a; if (bottom[i] == d) ++b
        }
        var r = max(a, b); if (r >= 0) return top.size - r
        d = bottom[0]; a = 0; b = 0
        for (i in top.indices) {
            if (top[i] != d && bottom[i] != d) { a  = -1; b = -1; break }
            if (top[i] == d) ++a; if (bottom[i] == d) ++b
        }
        r = max(a, b)
        return if (r < 0) -1 else top.size - r
    }



// 0ms
    pub fn min_domino_rotations(tops: Vec<i32>, bottoms: Vec<i32>) -> i32 {
        let (mut d1, mut d2, mut a) = (tops[0], bottoms[0], tops.len());
        let (mut b, mut c, mut d) = (a, a, a);
        for i in 0..a {
            let (tp, bt) = (tops[i], bottoms[i]);
            if tp != d1 && bt != d1 { if d2 < 1 { return -1 }; d1 = 0 }
            if tp != d2 && bt != d2 { if d1 < 1 { return -1 }; d2 = 0 }
            if tp == d1 { a -= 1 } else if tp == d2 { b -= 1 }
            if bt == d1 { c -= 1 } else if bt == d2 { d -= 1 }
        } a.min(b).min(c).min(d) as _
    }



// 0ms
    int minDominoRotations(vector<int>& tops, vector<int>& bottoms) {
        int d1 = tops[0], d2 = bottoms[0], j = 0, a = size(tops);
        int b = a, c = a, d = a;
        for (int tp: tops) {
            int bt = bottoms[j++];
            if (tp != d1 && bt != d1) if (!d2) return -1; else d1 = 0;
            if (tp != d2 && bt != d2) if (!d1) return -1; else d2 = 0;
            a -= tp == d1; b -= tp == d2; c -= bt == d1; d -= bt == d2;
        } return min(min(a, b), min(c, d));
    }


02.05.2025

838. Push Dominoes medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/976

Problem TLDR

Dominoes simulation #medium

Intuition

My first idea was to use force balance, but I didn’t find the working algorigthm for that (it is possible to make it work, but force should be decreasing from n)

    // 0123456789
    // .L.R...LR..L..
    // 00012340123000 to the right
    // 21004321032100 to the left
    //    1?02 1?
    // LL.RR.LLRR
    // 21  20?1 1

The more simple approach is to notice how ..L, R.., L..R and R..L ranges are behaving. Then it is all about the implementation details.

Approach

  • the golfed code here is completely obfuscates the logic: consider only L and backtrack to the half of R range or full otherwise.

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\) or O(1)

Code


// 30ms
    fun pushDominoes(d: String) = buildString {
        var r = false; var l = 1
        for ((i, c) in d.withIndex()) 
            if (c == '.') { append(if (r) 'R' else c); ++l } else { append(c)
                if (c == 'L') for (j in (if (r) i - l / 2 else i - l + 1)..<i) set(j, c)
                if (c == 'L' && r && l % 2 < 1) set(i - l / 2, '.')
                r = c == 'R'; l = 1
            }
    }



// 10ms
    fun pushDominoes(dominoes: String): String {
        val r = dominoes.toCharArray(); var isR = false; var l = 1
        for ((i, c) in r.withIndex()) 
            if (c == '.') { if (isR) r[i] = 'R'; ++l } else {
                if (c == 'L') for (j in (if (isR) i - l / 2 else i - l + 1)..<i) r[j] = 'L'
                if (c == 'L' && isR && l % 2 < 1) r[i - l / 2] = '.'
                isR = c == 'R'; l = 1
            }
        return String(r)
    }



// 1ms
    pub fn push_dominoes(mut d: String) -> String {
        unsafe { let (mut r, mut l, mut b) = (false, 1, d.as_bytes_mut());
        for i in 0..b.len() {
            if b[i] == b'.' { if r { b[i] = b'R'}; l += 1 } else {
                if b[i] == b'L' { b[if r { i - l / 2 } else { i - l + 1 }..i].fill(b'L') }
                if b[i] == b'L' && r && l % 2 < 1 { b[i - l / 2] = b'.' }
                r = b[i] == b'R'; l = 1
            }}} d
    }



// 0ms
    string pushDominoes(string d) {
        for (int i = 0, n = size(d), l = 1, r = 0; i < n; ++i)
            if (d[i] == '.') { if (r) d[i] = 'R'; ++l; } else {
                if (d[i] == 'L') fill(begin(d) + (r ? i - l/2 : i - l + 1), begin(d) + i, 'L');
                if (d[i] == 'L' && r && l % 2 < 1) d[i - l/2] = '.';
                r = d[i] == 'R'; l = 1;
            }
        return d;
    }


01.05.2025

2071. Maximum Number of Tasks You Can Assign hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/975

Problem TLDR

Tasks can be done by workers with pills #hard #binary_search

Intuition

Didn’t solve myself.

Thought process:


    // 5 9 8 5 9      5 5 8 9 9       p=1 s=5
    // 1 6 4 2 6      1 2 4 6 6

    // 5 5 8 9 9
    // *         1+5 p=0 not optimal
    //   *       6
    //           -
    //               maybe start with whats already fits?
    //               or just DP by (i,j,pills) - n^3
    //               
    // idea: real pointer + heap of skipped enchanced values (optimal?)-not optimal
    // idea: all in heap, real + enchanced, use greedy (not optimal)

    // hint: first smallest k to the workers
    // use binary search
    // but how to assign k smallest to all workers?
    // 5 5 8 9 9 - tasks              1 2 4 6 6  - workers     p=1 s=5
    // . . k, all must fit - key idea         
    //        still, how to optimally give the pills?


    // 5 5 8            1 2 3 4 5 6  p=1 s=5    can assign all tasks to workers?
    //                                          start with biggest
    //                      8                   assign it to smallest+pill

The hint: the is a greedy way to check if x workers can or can not do x tasks.

Now, after the hint I was able to discover the working greedy algorithm:

  • start with the biggest task and worker
  • if it works - it works
  • if it not, don’t give the pill to that worker, instead, find the weakest worker that will do that with pill

Another weak point of mine was: how to actually implement this search for the weakest worker? Do we have to track the used workers somehow? Is the solution becomes O(workers^2)

Thats where I gave up and looked for the answer:

  • put all the workers in a queue by their pill potential
  • if task is doable - take from the front of the queue (meaning the strongest worker)
  • if its not - consume the pill and the weakest worker (back of the pill potential queue)

Approach

  • some greedy ideas are not working, we have to try different examples
  • the implementation can be the hardest part even if you know the algorithm
  • 1 hr - brain can’t give its full power after this line (for me)

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(n)\)

Code


// 180ms
    fun maxTaskAssign(t: IntArray, ws: IntArray, pills: Int, s: Int): Int {
        t.sort(); ws.sort(); var lo = 0; var hi = t.lastIndex; var res = -1
        while (lo <= hi) {
            val m = (lo + hi) / 2
            var j = ws.lastIndex; var p = pills; var good = true; val q = ArrayDeque<Int>()
            for (i in m downTo 0) {
                while (j >= 0 && j >= ws.lastIndex - m && ws[j] + s >= t[i]) q += ws[j--]
                if (q.size < 1) { good = false; break }
                if (q.first() >= t[i]) q.removeFirst() else if (--p < 0) { good = false; break } else q.removeLast()
            }
            if (good) { res = max(res, m); lo = m + 1 } else hi = m - 1
        }
        return res + 1
    }



// 15ms
    pub fn max_task_assign(mut t: Vec<i32>, mut ws: Vec<i32>, pills: i32, s: i32) -> i32 {
        t.sort_unstable(); ws.sort_unstable(); let (mut lo, mut hi, mut r) = (0, t.len() as i32 - 1, -1);
        while lo <= hi {
            let m = (lo + hi) as usize / 2;
            let (mut j, mut p, mut good, mut q) = (ws.len() - 1, pills, true, VecDeque::new());
            for i in (0..=m).rev() {
                while j < ws.len() && j >= ws.len() - m - 1 && ws[j] + s >= t[i] { q.push_back(ws[j]); j -= 1 }
                if q.len() < 1 { good = false; break }
                if *q.front().unwrap() >= t[i] { q.pop_front(); } else if p < 1 { good = false; break }
                else { q.pop_back(); p -= 1 }
            }
            if good { r = r.max(m as i32); lo = m as i32 + 1 } else { hi = m as i32 - 1 }
        }
        r + 1
    }



// 66ms
    int maxTaskAssign(vector<int>& t, vector<int>& ws, int pills, int s) {
        int l = 0, r = min(size(t), size(ws)); sort(begin(t), end(t)); sort(begin(ws), end(ws));
        while (l < r) {
            int m = (l + r + 1) / 2, p = pills, j = size(ws) - 1, g = 1; deque<int> q;
            for (int i = m - 1; i >= 0 && g; --i) {
                while (j >= 0 && j >= size(ws) - m && ws[j] + s >= t[i]) q.push_back(ws[j--]);
                if (!size(q)) g = 0; else
                if (q.front() >= t[i]) q.pop_front(); else if (--p < 0) g = 0; else q.pop_back();
            }
            if (g) l = m; else r = m - 1;
        } return l;
    }


30.04.2025

1295. Find Numbers with Even Number of Digits easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/974

Problem TLDR

Even length numbers #easy

Intuition

Do what is asked

Approach

  • some golf and counter acrobatics possible
  • how the input range can be used?

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 3ms
    fun findNumbers(n: IntArray) = 
    n.count { "$it".length % 2 < 1 }



// 1ms
    fun findNumbers(n: IntArray) = n
    .count { it in 10..99 || it in 1000..9999 || it == 100000 }



// 0ms
    pub fn find_numbers(n: Vec<i32>) -> i32 {
        n.iter().map(|&x| { let (mut x, mut c) = (x, 1);
            while x > 0 { x /= 10; c = 1 - c }; c
        }).sum()
    }



// 0ms
    int findNumbers(vector<int>& n) {
        int r = 0;
        for (int c = 0; int x: n)
            for (c = 1, r++; x > 0; x /= 10 ) r +=  2 * (++c & 1) - 1;
        return r;
    }


29.04.2025

2962. Count Subarrays Where Max Element Appears at Least K Times medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/973

Problem TLDR

Subarrays at least k maxes #medium #two_pointers

Intuition

Two pointers pattern:

  • always move the right
  • move the left until condition
  • count how many valid subarray starting positions are
    // 1,3,2,3,3
    //   j   i i

Approach

  • we can compute max as we go
  • we can use a queue instead of the second pointer (slower runtime though)

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\), or O(n) or O(k) for the queue solution

Code


// 43ms
    fun countSubarrays(n: IntArray, k: Int): Long {
        var m = n.max(); val q = ArrayList<Int>()
        return n.withIndex().sumOf { (i, x) ->
            if (x == m) q += i
            if (q.size >= k) 1L + q[q.size - k] else 0L
        }
    }



// 20ms
    fun countSubarrays(n: IntArray, k: Int): Long {
        var j = 0; var m = n.max(); var c = 0
        return n.sumOf { x ->
            if (x == m) ++c
            while (c >= k) if (n[j++] == m) --c
            1L * j
        }
    }



// 13ms
    fun countSubarrays(n: IntArray, k: Int): Long {
        var r = 0L; var m = 0; val q = ArrayList<Int>()
        for (i in n.indices) {
            if (n[i] > m) { r = 0; m = n[i]; q.clear(); q += i } 
            else if (n[i] == m) q += i
            if (q.size >= k) r += q[q.size - k] + 1
        }
        return r
    }



// 8ms
    fun countSubarrays(n: IntArray, k: Int): Long {
        var j = 0; var r = 0L; var m = 0; var c = 0
        for (x in n) {
            if (x > m) { r = 0; c = 1; j = 0; m = x } else if (x == m) ++c
            while (c >= k) if (n[j++] == m) --c
            r += j
        }
        return r
    }



// 6ms
    fun countSubarrays(n: IntArray, k: Int): Long {
        var j = 0; var r = 0L; var m = 0; var c = 0
        for ((i, x) in n.withIndex()) {
            if (x > m) { r = 0; c = 1; j = i; m = x } else if (x == m) ++c
            while (c > k || n[j] != m) if (n[j++] == m) --c
            if (c == k) r += j + 1
        }
        return r
    }



// 0ms
    pub fn count_subarrays(n: Vec<i32>, k: i32) -> i64 {
        let (mut j, mut r, mut m, mut c) = (0, 0, 0, 0);
        for &x in &n {
            if x > m { r = 0; c = 1; j = 0; m = x } else if x == m { c += 1 }
            while c >= k { if n[j] == m { c -= 1 }; j += 1 }
            r += j as i64
        } r
    }



// 0ms
    long long countSubarrays(vector<int>& n, int k) {
        int j = 0, m = 0, c = 0; long long r = 0;
        for (int x: n) {
            if (x > m) r = 0, c = 1, j = 0, m = x; else if (x == m) ++c;
            while (c >= k) if (n[j++] == m) --c;
            r += j;
        } return r;
    }


28.04.2025

2302. Count Subarrays With Score Less Than K hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/972

Problem TLDR

Subarrays sum * cnt <= k #hard #two_pointers

Intuition

This is a standart two-pointers pattern task: always move the right pointer, move the left util condition, count how many good subarray starting point are.

Approach

  • you can use i - j + 1 or a separate count variable
  • careful with int overflow

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 28ms
    fun countSubarrays(n: IntArray, k: Long): Long {
        var s = 0L; var j = 0
        return n.withIndex().sumOf { (i, x) ->
            s += x; while (s * (i - j + 1) >= k) s -= n[j++]
            1L + i - j
        }
    }



// 3ms
    fun countSubarrays(n: IntArray, k: Long): Long {
        var s = 0L; var r = 0L; var j = 0
        for ((i, x) in n.withIndex()) {
            s += x
            while (s * (i - j + 1) >= k) s -= n[j++]
            r += i - j + 1
        }
        return r
    }



// 0ms
    pub fn count_subarrays(n: Vec<i32>, k: i64) -> i64 {
        let (mut s, mut j) = (0, 0);
        n.iter().enumerate().map(|(i, &x)| {
            s += x as i64; 
            while s * (i - j + 1) as i64 >= k { s -= n[j] as i64; j += 1 }
            i - j + 1
        }).sum::<usize>() as _
    }



// 0ms
    long long countSubarrays(vector<int>& n, long long k) {
        long long s = 0, r = 0; int j = 0, c = 0;
        for (int x: n) {
            s += x; ++c;
            while (c * s >= k) s -= n[j++], --c;
            r += c;
        } return r;
    }


27.04.2025

3392. Count Subarrays of Length Three With a Condition easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/971

Problem TLDR

3-subarrays 2a + 2c == b #easy

Intuition

Constrains are small, even the brute-force solution is O(n)

Approach

  • let’s golf it
  • some CPU-cache friendliness possible

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


// 31ms
    fun countSubarrays(n: IntArray) = n.asList()
    .windowed(3).count { 2 * it.sum() == 3 * it[1] }



// 2ms
    fun countSubarrays(n: IntArray): Int {
        var c = 0; var l = 0; var m = -300
        for (r in n) {
            if (l + l + r + r == m) c++
            l = m; m = r
        }
        return c
    }



// 0ms
    pub fn count_subarrays(n: Vec<i32>) -> i32 {
        n[..].windows(3).filter(|w| 2 * w[0] + 2 * w[2] == w[1]).count() as _
    }



// 0ms
    int countSubarrays(vector<int>& n) {
        int c = 0, l = 0, m = 300;
        for (int r: n) c += l + l + r + r == m, l = m, m = r;
        return c;
    }


26.04.2025

2444. Count Subarrays With Fixed Bounds hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/970

Problem TLDR

Subarrays with min=minK, max=maxK #hard #two_pointers

Intuition

I’ve encounter this problem for a 3rd time (last https://leetcode.com/problems/count-subarrays-with-fixed-bounds/solutions/4951301/kotlin-rust/).

This time I felt pretty fluent with subarrays logic: two pointers maintain the minimum valid window, and a third pointer s is a start position of the valid starting positions of possible subarrays s..j.


    // 2 2 2 1 3 5 2 2 7 1 3 5    1..5 
    //       j   j   i

    // 1 3 5 2 7 5      1..5
    // *minj
    //     *maxj
    // j     i
    //                  not in *range* but *equal*

Approach

  • attention: subarray should have exact min=minK and max=maxK
  • there is some pointer acrobatics trick: instead of a start position, track count, increase it by pointers diff

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

// 38ms
    fun countSubarrays(n: IntArray, minK: Int, maxK: Int): Long {
        var a = -1; var b = -1; var s = -1
        return n.withIndex().sumOf { (i, x) ->
            if (x == minK) a = i; if (x == maxK) b = i
            if (x < minK || x > maxK) { s = i; a = i; b = i }
            1L * min(a, b) - s
        }
    }


// 6ms
    fun countSubarrays(n: IntArray, minK: Int, maxK: Int): Long {
        var a = -1; var b = -1; var c = 0; var r = 0L
        for ((i, x) in n.withIndex())
            if (x < minK || x > maxK) { a = i; b = i; c = 0 }
            else {
                if (x == minK) { if (a < b) c += b - a; a = i }
                if (x == maxK) { if (b < a) c += a - b; b = i }
                r += c
            }
        return r
    }


// 0ms
    pub fn count_subarrays(n: Vec<i32>, min_k: i32, max_k: i32) -> i64 {
        let (mut a, mut b, mut c) = (-1, -1, 0);
        n.into_iter().enumerate().map(|(i, x)| {
            if x < min_k || x > max_k { a = i as i32; b = i as i32; c = 0 }
            if x == min_k { if a < b { c += b - a }; a = i as i32 }
            if x == max_k { if b < a { c += a - b }; b = i as i32 }
            c as i64
        }).sum()
    }


// 0ms
    long long countSubarrays(vector<int>& n, int minK, int maxK) {
        int a = -1, b = -1, c = 0; long long r = 0;
        for (int i = 0; i < size(n); ++i) {
            if (n[i] < minK || n[i] > maxK) a = i, b = i, c = 0;
            if (n[i] == minK) c += max(0, b - a), a = i;
            if (n[i] == maxK) c += max(0, a - b), b = i;
            r += c;
        } return r;
    }


25.04.2025

2845. Count of Interesting Subarrays medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/969

Problem TLDR

Subarrays, count a[i]%m=k is c%m=k #medium #hash_map

Intuition

Failed to solve.

Wrong two-pointers reasoning:


    // 0 1 2 3
    // 3 1 9 6       m=3 k=0
    //               0,3,6,9... cnt indices
    // *   * *       the interesting indices are known
    // what possible patterns are
    // ...***..., ....*....*....*..., .***.***, .***.***.***
    //                                  i..j 
    //                                 i.....j
    // window of 0, window of 3, window of 6,...
    // what if k=1, m=3
    // ..*..*..*.
    // window of 1, window of 4, window of x*m+1
    // how many windows possible?
    // m = 1, k = 0, windows_count = n, so it is n^2 algo
    // 012345678
    // .***.***.***.***..
    // .i j. j .j j. j ..
    //   i .j j. j .j j..
    //    i. j .j j.j j..  every j is a valid end
    //                     it is (i+m-1)%m (* only)
    // .***.***.***.***..
    //  i     .   .        s=0 js=0
    //  j i   .   .        s=0 js=1
    //   j  i .   .        s=0 js=2
    //  * j  i.   .        s=1 js=3 
    //   *  j i   .        s=1 js=4
    //  * *  j  i .        s=2 js=5
    //   *  * j  i.        s=2 js=6
    //  * * * * j i        the number of prefix stars=4, number of js=7
    //                     s=(js+1)/3 ?
    //     .
    //      \how to count this dot?

I’ve almost come to the conclusion of counting prefix good j’s. But do not understood how can I also count non-divisible dots.

Then I used the hints:

  • if we are at i and have good count[i]
  • then how many good starting js are? j is good if (count[i] - count[j]) % m == k. Number of good starting js is freq[count[j]].
  • I have to be fluid with modulo arithmetics: (a - b) % m == k, a%m - b%m == k, b%m == a%m - k, b%m == (a%m + m - k)%m (+m to make positive)

Approach

  • zero case is map[0] = 1
  • non-divisible positions are counted because we increase r by previous running sum cnt

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


    fun countInterestingSubarrays(nums: List<Int>, m: Int, k: Int): Long {
        var r = 0L; var cnt = 0; var map = HashMap<Int, Int>(); map[0] = 1
        for (x in nums) {
            cnt = (cnt + (if (x % m == k) 1 else 0)) % m
            r += map[(cnt + m - k) % m] ?: 0
            map[cnt] = 1 + (map[cnt] ?: 0)
        }
        return r
    }


    pub fn count_interesting_subarrays(n: Vec<i32>, m: i32, k: i32) -> i64 {
        let (mut cnt, mut r, mut map) = (0, 0, HashMap::new()); map.insert(0, 1);
        for x in n {
            if x % m == k { cnt += 1}
            r += map.get(&((cnt + m - k) % m)).unwrap_or(&0);
            *map.entry(cnt % m).or_insert(0) += 1
        } r
    }



    long long countInterestingSubarrays(vector<int>& n, int m, int k) {
        unordered_map<int, int> map; long long r = 0; int cnt = 0; map[0] = 1;
        for (int x: n) {
            cnt = (cnt + (x % m == k)) % m;
            r += map[(cnt + m - k) % m];
            ++map[cnt];
        } return r;
    }


24.04.2025

2799. Count Complete Subarrays in an Array medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/968

Problem TLDR

Subarrays having all uniqs #medium #two_pointers

Intuition

This is a standard two-pointers problem: count frequencies, always move right, move left until condition. All prefixes are valid starts of the subarrays.


    // 0 1 2 3 4
    // 1,3,1,2,2
    //     j   i

  • subarrays are valid for all indexes 0..j

Approach

  • try to dry-run solution before pressing “submit”

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


    fun countCompleteSubarrays(nums: IntArray): Int {
        val f = IntArray(2001); var u = nums.toSet().size
        return nums.sumOf { x ->
            if (f[x]++ < 1) u--
            while (u < 1) if (--f[nums[f[0]++]] < 1) u++
            f[0]
        }
    }



    fun countCompleteSubarrays(nums: IntArray): Int {
        val f = IntArray(2001); var j = 0; var u = 0
        for (x in nums) if (f[x] < 1) { u++; ++f[x] }
        return nums.sumOf { x ->
            if (f[x]++ < 2) u--
            while (u < 1) if (--f[nums[j++]] < 2) u++
            j
        }
    }



    fun countCompleteSubarrays(nums: IntArray): Int {
        val f = IntArray(2001); var j = 0; var r = 0
        for (x in nums) {
            if (f[x]++ < 1) r = 0
            while (f[nums[j]] > 1) --f[nums[j++]]
            r += j + 1
        }
        return r
    }



    pub fn count_complete_subarrays(nums: Vec<i32>) -> i32 {
        let (mut f, mut j, mut u) = ([0; 2001], 0, 0);
        for &x in &nums { if f[x as usize] < 1 { u += 1; f[x as usize] = 1}}
        (0..nums.len()).map(|i| { let x = nums[i] as usize;
            if f[x] < 2 { u -= 1 }; f[x] += 1; 
            while u < 1 { let x = nums[j] as usize; j += 1;
                f[x] -= 1; if f[x] < 2 { u += 1 }}
            j
        }).sum::<usize>() as _
    }



    int countCompleteSubarrays(vector<int>& nums) {
        int f[2001] = {}, u = 0, r = 0, j = 0;
        for (int x: nums) if (!f[x]) ++u, ++f[x];
        for (int x: nums) {
            if (f[x]++ < 2) --u;
            while (u < 1) if (--f[nums[j++]] < 2) ++u;
            r += j;
        } return r;
    }


23.04.2025

1399. Count Largest Group easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/967

Problem TLDR

Count of max groups by digits sum 1..n #easy

Intuition

The brute-force is accepted.

Approach

  • max digits sum is 9+9+9+9 = 36

Complexity

  • Time complexity: \(O(nlg(n))\)

  • Space complexity: \(O(n)\)

Code


    fun countLargestGroup(n: Int): Int =
        (1..n).groupBy { "$it".sumOf { it - '0' }}.values
        .run { count { it.size == maxOf { it.size }}}



    fun countLargestGroup(n: Int): Int {
        val f = IntArray(37); var cnt = 0; var gmax = 0
        for (x in 1..n) {
            var s = 0; var y = x
            while (y > 0) { s += y % 10; y /= 10 }
            val g = ++f[s]
            if (g > gmax) { gmax = g; cnt = 1 } 
            else if (g == gmax) cnt++
        }
        return cnt
    }



    pub fn count_largest_group(n: i32) -> i32 {
        let (mut f, mut gmax, mut cnt) = ([0; 37], 0, 0);
        for x in 1..=n {
            let (mut s, mut y) = (0, x);
            while y > 0 { s += y as usize % 10; y /= 10 }
            f[s] += 1; let g = f[s];
            if g > gmax { gmax = g; cnt = 1 }
            else if g == gmax { cnt += 1 }
        } cnt
    }



    int countLargestGroup(int n) {
        int f[37], gmax = 0, cnt = 0;
        for (;n;n--) {
            int x = n, s = 0; 
            while (x) s += x % 10, x /= 10;
            int g = ++f[s];
            if (g > gmax) gmax = g, cnt = 1;
            else if (g == gmax) cnt++;
        } return cnt;
    }


22.04.2025

2338. Count the Number of Ideal Arrays hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/966

Problem TLDR

Arrays a[i] % a[i - 1] == 0, i..n, a[i]..max #hard #combinatorics

Intuition

Didn’t solve. And didn’t understand the solution. To make it work you have to be fluent with combinatorics. You have to be fluent with Stars and bars https://cp-algorithms.com/combinatorics/stars_and_bars.html.

My thoughts rundown is irrelevant here, so I will not post it.

Some thoughts about the solution:

  • arrays are aaa | bbb | ccc, where | is the bars. 1 | 2 | 4 4 or 1 1| 2 |4 or 1 | 2 2 | 4.
  • the max uniq sequence length is for 2: 1,2,4,8,2^4,2^5,...2^i,..10000, max i is 2^13=8192 < 10000
  • res += n choose k, n in 1..maxValue, k in 0..13. We considering placing 1..maxValue numbers into a length of 0..13 places

Approach

  • maybe I should try more combinatorics problems to better understand them; right now they are not picturing in my brain canvas

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(nlog(n))\)

Code


    fun idealArrays(n: Int, maxValue: Int): Int {
        val comb = Array(10001) { IntArray(14) }; val cnt = Array(10001) { IntArray(14) }
        val M = 1_000_000_007; comb[0][0] = 1; var res = 0L
        for (s in 1..10000) { comb[s][0] = 1
            for (r in 1..13) comb[s][r] = (comb[s - 1][r - 1] + comb[s - 1][r]) % M }
        for (div in 1..10000) {
            ++cnt[div][0]
            for (i in 2 * div..10000 step div)
                for (bars in 0..12) cnt[i][bars + 1] += cnt[div][bars]
        }
        for (i in 1..maxValue) for (bars in 0..min(13, n)) 
            res = (1L * cnt[i][bars] * comb[n - 1][bars] + res) % M
        return res.toInt()
    }

21.04.2025

2145. Count the Hidden Sequences medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/965

Problem TLDR

Possible arrays from diff array and lo..hi #medium

Intuition

Let’s observe the numbers, x is some starting point:


    // 3,-4,5,1,-2       -4..5   len1 = 5-(-4) = 9
    // x           x
    // x+3         x+3
    // x+3-4       x-1   -1
    // x+3-4+5     x+4
    // x+3-4+5+1   x+5    5
    // x+3-4+5+1-2 x+3
    // -1..5    in -4..5 = (-4..2, -3..3, -2..4, -1..5)
    // len2 = 5-(-1) = 6
    // len1 - len2 + 1

    // 1 -3 4        1..6, len1=6-1=5
    // x       x
    // x+1     x+1
    // x+1-3   x-2
    // x+1-3+4 x+2
    // -2..2, len2 = 2-(-2)=4
    // len1 - len2 + 1 = 5-4+1=2

    // -40            -46..53, len1=99
    // x
    // x-40
    // len2=0-(-40)=40
    // 99-40+1 = 60

  • compute the x_max and x_min
  • find how many ranges of x_min..x_max in the range lo..hi

Approach

  • beware of the int overflow
  • early exit is possible

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code

```kotlin [Kotlin(5ms]

fun numberOfArrays(diff: IntArray, lo: Int, up: Int): Int {
    var x = 0L; var a = 0L; var b = 0L
    for (d in diff) { x += d; a = max(a, x); b = min(b, x) }
    return max(0, 1L * up - lo - a + b + 1).toInt()
}
```kotlin [2ms)]

    fun numberOfArrays(diff: IntArray, lo: Int, up: Int): Int {
        var x = 0; var a = 0; var b = 0; val r = up - lo
        for (d in diff) { 
            x += d
            if (x > a) { a = x; if (a - b > r) return 0 }
            else if (x < b) { b = x; if (a - b > r) return 0 }
        }
        return r - a + b + 1
    }


```rust [Rust(0ms]

pub fn number_of_arrays(diff: Vec<i32>, lo: i32, up: i32) -> i32 {
    let (mut x, mut a, mut b) = (0, 0, 0);
    for d in diff { x += d as i64; a = a.max(x); b = b.min(x) }
    0.max(up - lo + 1 - (a - b) as i32)
}
```rust [0ms)]

    pub fn number_of_arrays(diff: Vec<i32>, lo: i32, up: i32) -> i32 {
        let (mut x, mut a, mut b) = (0, 0, 0);
        for d in diff { x += d; a = a.max(x); b = b.min(x); 
            if a - b > up - lo { return 0 } }
        up - lo + 1 - a + b
    }


```c++ [C++(0ms)]

int numberOfArrays(vector<int>& diff, int lo, int up) {
    long long x = 0, a = 0, b = 0;
    for (int d: diff) a = max(a, x += d), b = min(b, x);
    return (int) max(0LL, b - a + up - lo + 1);
}

# 20.04.2025
[781. Rabbits in Forest](https://leetcode.com/problems/rabbits-in-forest/description) medium
[blog post](https://leetcode.com/problems/rabbits-in-forest/solutions/6669530/kotlin-rust-by-samoylenkodmitry-epo4/)
[substack](https://open.substack.com/pub/dmitriisamoilenko/p/20042025-781-rabbits-in-forest?r=2bam17&utm_campaign=post&utm_medium=web&showWelcomeOnShare=true)
[youtube](https://youtu.be/a2Bwo9E0RDo)
![1.webp](/assets/leetcode_daily_images/d26a1610.webp)

#### Join me on Telegram

https://t.me/leetcode_daily_unstoppable/964

#### Problem TLDR

Count total rabbits from other numbers #medium #math #brainteaser

#### Intuition

* the rabbit tells how many *other* rabbits are

Thoughts process:

```j

    // 10,10,10     11   how?

    // brain teaser
    // 10 red
    // 10 red
    // 10 red   it is 3 that answered, 
    //          10 - 3 = 7 not answered

    // 2 2 2 2 2
    // 5 + 
    // I do not understand the problem
    // "have the same color as you"
    // is it including or excluding?
    // suppose excluding
    // 1 1 2
    // *     one other - mark red
    //   *   one other -  mark red
    //     * two others - no other with two
    // 3 + 2 of no-matches

    // 10 10 10
    // *         ten others - mark red (total 1 + 10)
    //    *      ten others - red
    //       *   ten others - red
    // total = 11

    // 2 2 2
    // *     2 others (total 1 + 2 = 3)
    //   *   2 others
    //     * 2 others
    // 3 of red

    // 1 1 = 2
    // 1 1 1 = 1 1 | 1 = 2 + 2
    // 1 1 1 1 = 1 1 | 1 1 = 2 + 2
    // 1 1 1 1 1 = 1 1 | 1 1 | 1  = 2 + 2 + 2 = 6

    // 2 2 2 2
    // so we have 4 rabbits
    // only 3 can be same color (2 + 1)
    // x = 2
    // group = 3 = (2 + 1) = g = x + 1
    // buckets = f(2) / (2 + 1) = f / g + f % g
    //         = 4 / 3 + 4 % 3 = 2 
    // count = buckets * g = 2 * 3 = 6

    // 2 = 3
    // 2 2 = 3
    // 2 2 2 = 3
    // 2 2 2 2 = 2 2 2 | 2 = 3 + 3 = 6

  • each group defined by the others answer, group count is others + 1
  • total answered rabbits should be split into the buckes of group count

Approach

  • from u/votrubac/ & u/lee215/: we can increment a new group on the go

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


    fun numRabbits(answers: IntArray) = answers.groupBy { it }
    .entries.sumOf { (x, f) -> (f.size + x) / (x + 1) * (x + 1) }



    fun numRabbits(answers: IntArray): Int {
        val f = IntArray(1001); for (x in answers) ++f[x]
        for (x in 0..999) if (f[x] > 0)
            f[1000] += (f[x] + x) / (x + 1) * (x + 1)
        return f[1000]
    }



    fun numRabbits(answers: IntArray): Int {
        val f = IntArray(1000); var r = 0; 
        for (x in answers) if (f[x]++ % (x + 1) < 1) r += x + 1
        return r
    }



    pub fn num_rabbits(answers: Vec<i32>) -> i32 {
        let (mut f, mut r) = ([0; 1000], 0);
        for x in answers {
            if f[x as usize] % (x + 1) < 1 { r += x + 1 }
            f[x as usize] += 1
        } r
    }



    int numRabbits(vector<int>& a) {
       int r = 0, f[1000];
       for (int x: a) if (f[x]++ % (x + 1) < 1) r += x + 1;
       return r;
    }


19.04.2025

2563. Count the Number of Fair Pairs medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/963

Problem TLDR

Pairs a + b in lower..upper #medium #two_pointers

Intuition

This time I was able to solve it with hints. Previous time was a fail (5 month ago https://leetcode.com/problems/count-the-number-of-fair-pairs/solutions/6040302/kotlin-rust/).

The hints that helped the most:

  • both boundaries move only in a single direction (you have to know how to use them though)

Here is my thougths rundown:

    // 0,1,7,4,4,5 3..6
    //     i
    //     how many visited numbers are in range
    //     3 <= x + a[i] <= 6
    //     3 - a[i] <= x <= 6 - a[i]
    // i
    // expect numbers in range
    // 3 <= a[i] + x <= 6
    // 3 - a[i]..6 - a[i] segment tree?
    //                    sort and binary search
    //
    // 0,1, 7,4,4,5         3..6
    // 3 2 -4
    // 4 3 -3
    // 5 4 -2
    // 6 5 -1

    // total n^2 pairs possible, i < j is irrelevant
    // 0 1 4 4 5 7   two-sum
    // l->          (increase left to make sum bigger)
    //         r->  (increase right to make sum bigger)
    // count of pairs > upper
    // count of pairs < lower

    // -2 -1 0 1 2       0..1
    //       * *
    //     *   *
    //     *     *
    //  *        *

    // 0 1 4 4 5 7   3..6
    // *             3..6       just move l and r, they always go to the left
    //   *           2..5  -1
    //     *        -1..2  -3
    //       *        
    //         *    -2..1  -1
    //           *  -4..-1 -2

    // 1 2 5 7 9      11..11

My observations:

  • i and j positions are irrelevant, we can safely sort
  • we can do a binary search (I have failed to implement this in Kotlin)
  • we can move both borders left as we go right
  • for count lower..upper we may apply count(upper) - count(lower) rule

Approach

  • let’s implement everything and see what’s the best

Complexity

  • Time complexity: \(O(nlog(n))\)

  • Space complexity: \(O(1)\)

Code


    fun countFairPairs(n: IntArray, lower: Int, upper: Int): Long {
        n.sort(); val n = n.asList()
        return n.withIndex().sumOf { (i, x) -> 1L *
            max(i + 1, -n.binarySearch { if (it <= upper - x) -1 else 1 } - 1) - 
            max(i + 1, -n.binarySearch { if (it < lower - x) -1 else 1 } - 1)
        }
    }



    fun countFairPairs(n: IntArray, lower: Int, upper: Int): Long {
        n.sort(); var r = 0L; val n = Array(n.size) { n[it] }
        val cmp = Comparator<Int> { a, b -> if (a < b) -1 else 1 }
        for (i in 0..<n.size) r -= 
            Arrays.binarySearch(n, i + 1, n.size, upper - n[i] + 1, cmp) -
            Arrays.binarySearch(n, i + 1, n.size, lower - n[i], cmp)
        return r
    }



    fun countFairPairs(n: IntArray, lower: Int, upper: Int): Long {
        n.sort(); var l = n.size - 1; var r = l
        return (0..r).sumOf { i ->
            while (l > i && n[l] + n[i] >= lower) l--
            while (r > l && n[r] + n[i] > upper) r--
            1L * max(i, r) - max(i, l)
        }
    }



    fun countFairPairs(n: IntArray, lower: Int, upper: Int): Long {
        n.sort(); var res = 0L; var l = n.size - 1; var r = l
        for (i in 0..r) {
            while (l > i && n[l] + n[i] >= lower) l--
            while (r > l && n[r] + n[i] > upper) r--
            if (r <= i) break; res += r - max(i, l)
        }
        return res
    }



    fun countFairPairs(n: IntArray, lower: Int, upper: Int): Long {
        fun cnt(max: Int): Long {
            var res = 0L; var l = 0; var r = n.size - 1
            while (l < r) if (n[l] + n[r] > max) r-- else res += r - l++
            return res
        }
        n.sort(); return cnt(upper) - cnt(lower - 1)
    }



    pub fn count_fair_pairs(mut nums: Vec<i32>, lower: i32, upper: i32) -> i64 {
        nums.sort(); 
        (0..nums.len()).map(|i|
            nums[..i].partition_point(|&n| n <= upper - nums[i]) -
            nums[..i].partition_point(|&n| n < lower - nums[i])
        ).sum::<usize>() as _
    }



    pub fn count_fair_pairs(mut nums: Vec<i32>, lower: i32, upper: i32) -> i64 {
        fn cnt(nums: &Vec<i32>, max: i32) -> i64 {
            let (mut res, mut l, mut r) = (0, 0, nums.len() - 1);
            while l < r { 
                if nums[l] + nums[r] > max { r -= 1 } 
                else { res += (r - l) as i64; l += 1 }
            } res
        }
        nums.sort(); cnt(&nums, upper) - cnt(&nums, lower - 1)
    }



    pub fn count_fair_pairs(mut n: Vec<i32>, lower: i32, upper: i32) -> i64 {
        n.sort(); let (mut l, mut r, mut res) = (n.len() - 1, n.len() - 1, 0);
        for i in 0..=r {
            while l > i && n[i] + n[l] >= lower { l -= 1 }
            while r > l && n[i] + n[r] > upper { r -= 1 }
            if r <= i { break }; res += (r - i.max(l)) as i64
        } res
    }



    pub fn count_fair_pairs(mut n: Vec<i32>, lower: i32, upper: i32) -> i64 {
        n.sort(); let (mut l, mut r) = (n.len() - 1, n.len() - 1);
        (0..=r).map(|i| {
            while l > i && n[i] + n[l] >= lower { l -= 1 }
            while r > l && n[i] + n[r] > upper { r -= 1 }
            (i.max(r) - i.max(l)) as i64 }).sum()
    }



    long long countFairPairs(vector<int>& a, int l, int u) {
        sort(begin(a), end(a)); long long r = 0; 
        for(int m: array{u, l - 1}) for (int i = 0, j = a.size() - 1; i < j;) 
            if (a[i] + a[j] > m) --j;
            else r += (m == u ? 1 : -1) * (j - i++);
        return r;
    }


18.04.2025

38. Count and Say medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/962

Problem TLDR

nth run-length encoded string #medium

Intuition

Just simulate, the n is small.

Approach

  • it is interesting to optimize this solution
  • it is well-known sequence A005150 named “Look-and-say” https://en.wikipedia.org/wiki/Look-and-say_sequence https://oeis.org/A005150
  • the only numbers are 1, 2 and 3

Complexity

  • Time complexity: \(O(n^2)\), according to wiki, it grows 30% per generation

  • Space complexity: \(O(n^2)\)

Code


    fun countAndSay(n: Int): String = if (n < 2) "1" else buildString {
        val s = countAndSay(n - 1); var i = 0; var j = 0
        while (i < s.length) {
            while (j < s.length && s[i] == s[j]) j++
            append(j - i).append(s[i]); i = j
        }
    }



    fun countAndSay(n: Int): String {
        var a = CharArray((49 * n * n + 20 * n) / 10); var b = CharArray(a.size)
        a[0] = '1'; var sz = 1
        for (r in 2..n) {
            var i = 0; var j = 0; var k = 0
            while (i < sz) {
                val x = a[i]
                while (j < sz && a[j] == x) j++
                b[k++] = '0' + j - i
                b[k++] = x
                i = j
            }
            a = b.also { b = a }; sz = k
        }
        return String(a, 0, sz)
    }



val answers = {
    var a = CharArray(3410); var b = CharArray(4463)
    a[0] = '1'; var sz = 1; val res = Array(31) { "1" }
    for (r in 2..30) {
        var i = 0; var j = 0; var k = 0
        while (i < sz) {
            val x = a[i]
            while (j < sz && a[j] == x) j++
            b[k++] = '0' + j - i
            b[k++] = x
            i = j
        }
        a = b.also { b = a }; sz = k
        res[r] = String(a, 0, sz)
    }
    res
}()
class Solution { fun countAndSay(n: Int) = answers[n] }



    pub fn count_and_say(n: i32) -> String {
        if n < 2 { return "1".into() }
        let s = Self::count_and_say(n - 1); let s = s.as_bytes();
        let (mut i, mut j, mut v) = (0, 0, vec![]);
        while i < s.len() {
            while j < s.len() && s[i] == s[j] { j += 1 }
            v.push(b'0' + (j - i) as u8); v.push(s[i]); i = j
        } String::from_utf8(v).unwrap()
    }



    string countAndSay(int n) {
        if (n < 2) return "1";
        string s = countAndSay(n - 1), r;
        for (int i = 0, j = 0; i < size(s); i = j) {
            while (j < size(s) && s[i] == s[j]) ++j;
            r += '0' + j - i; r += s[i];
        } return r;
    }


17.04.2025

2176. Count Equal and Divisible Pairs in an Array easy blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/961

Problem TLDR

Pairs a[i] == b[j], i * j % k == 0 #easy

Intuition

The brute force is accepted.

Approach

  • the problem has also more optimal solution by using gcd(i, k) * gcd(j, k) % k == 0 equality

Complexity

  • Time complexity: \(O(n^2)\)

  • Space complexity: \(O(1)\)

Code


    fun countPairs(nums: IntArray, k: Int) =
        nums.indices.sumOf { i -> 
            (i + 1..<nums.size).count { j ->
                (i * j) % k == 0 && nums[i] == nums[j] }}



    pub fn count_pairs(n: Vec<i32>, k: i32) -> i32 {
        (0..n.len()).map(|i| (i + 1..n.len()).filter(|&j| 
        (i * j) as i32 % k < 1 && n[i] == n[j]).count() as i32).sum()
    }



    int countPairs(vector<int>& n, int k) {
        int r = 0;
        for (int i = 0; i < size(n); ++i)
            for (int j = i + 1; j < size(n); ++j)
                r += i * j % k < 1 && n[i] == n[j];
        return r;
    }


16.04.2025

2537. Count the Number of Good Subarrays medium blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/960

Problem TLDR

Subarrays with at least k equal pairs #medium #sliding_window #math

Intuition

Let’s observe sliding window:


    // [3,1,4,3,2,2,4], k = 2
    //                  freq
    //  i     j         3->2
    //  i         j     3->2 + 2->2          2
    //  i           j   3->2 + 2->2 + 4->2   3
    //    i         j   2->2 + 4->2          2
    //      i       j   2->2 + 4->2          2
    // when to move second pointer to shrink?
    // ****************
    //    i     j->     expand until good, + all before i count
    //     i->  j       shrink while good

Expand window until we get k equal pairs.

The hardest part is to reason about when to shrink the window. The count & shrink technique is: we always freeze the right border and shrink left while we can. The prefix is all valid subarrays, so count all of them.

Now, how to increase and decrease the frequency?


    // freq = 4, (n - 1) * (n - 2) / 2
    // freq = 5, n * (n - 1) / 2 - (n - 1) * (n - 2) / 2
    //           (n - n + 2) * (n - 1) / 2
    //                    2 * (n - 1) / 2
    //                    n - 1

By looking at 1 1 1 1 1 example, the pairs count is p = f * (f - 1) / 2. So, the diff is p(n) - p(n - 1) = n - 1.

Approach

  • we can shrink window up to the invalid state and not check if it is valid to add j, as j = 0 initially

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


    fun countGood(n: IntArray, k: Int): Long {
        val f = HashMap<Int, Int>(); var j = 0; var p = 0
        return n.indices.sumOf { i ->
            p += f[n[i]] ?: 0
            f[n[i]] = 1 + (f[n[i]] ?: 0)
            while (p >= k) { f[n[j]] = f[n[j]]!! - 1; p -= f[n[j++]]!! }
            1L * j
        }
    }



    pub fn count_good(n: Vec<i32>, mut k: i32) -> i64 {
        let (mut f, mut j) = (HashMap::new(), 0);
        (0..n.len()).map(|i| {
            k -= f.get(&n[i]).unwrap_or(&0); *f.entry(n[i]).or_default() += 1;
            while k <= 0 { *f.entry(n[j]).or_default() -= 1; k += f[&n[j]]; j += 1 }
            j as i64
        }).sum::<i64>()
    }



    long long countGood(vector<int>& n, int k) {
        long long r = 0LL; unordered_map<int, int> f;
        for (int i = 0, j = 0; i < size(n); ++i, r += j) {
            k -= f[n[i]]++; while (k <= 0) k += --f[n[j++]];
        } return r;
    }


15.04.2025

2179. Count Good Triplets in an Array hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/959

Problem TLDR

Triplets in same order in both (0..n)-arrays #hard #bit

Intuition

Didn’t solve, as I am not familiar with Fenwick Tree or Binary Indexed Tree.

Some of my thought process and observations:


    // 4,0,1,3,2
    // 4,1,0,2,3
    //*4          (0 1 3 2) and (1 0 2 3)
    //   0        (1 3 2) and (2 3) -> 2,3
    //     1      (3 2) and (0 2 3) -> 2,3
    //  
    //  *0         (1 3 2) and (2 3)
    //     1-      can't take, pos2(-1) < pos2(0)
    //       3     (2) and ()
    // this is an n^2 algo

    // numbers are exactly 0..n-1

    // 0 1 2 3 4    can we sort both and preserve the relations?
    // 0   1   2   
    // 0 3   4

    // 0 1 2 3 4
    // 4,0,1,3,2  -> 0 1 2 3 4  
    // 4,1,0,2,3  -> 0 2 1 4 3    now the problem is to count increasing sequencies
    // 0 2 1 4 3       .   .      number of increasing triplets? or subsequences?
    //               0 2   4
    //               0 2   . 3
    //               0 . 1 4
    //               0 . 1 . 3
    //                 .   .      monotonic stack    count smaller than current
    //               0 .   .      0                  0
    //                 2   .      02                 1
    //                   1 .      01                 1
    //                     4      014                2 (lost '2')
    // use the hint - totally different algo
    // the useful hint - triplets are better observed by middle: count smaller * count bigger
    //               0            count less = 0, count bigger = n - 1
    //                 2          count less = 1, count bigger = n - 1 - 1



The most helpful observation was that problem can be narrowed down to a single array with increased triplets.

The most helpful hint is for triplets: consider the middle, then the problem became how much to the left and how much to the right.

However, to answer how many numbers are less than current in a less than O(n^2) you have to know BIT.

BIT:



    //          
    // 2 0 1 3 -> 0 1 2 3
    // 0 1 2 3 -> 1 2 0 3
    //          
    // didn't quite get how to use BIT here
    // count values smaller/bigger than x
    // add x, remove x

    //                                     16
    //               8                     16
    //       4       8         12          16
    //   2   4   6   8   10    12    14    16
    // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
    //              
    // add 6: 7 -> 8 -> 16
    // add 4: 5 -> 6 -> 8 -> 16
    // count less than 8:  9_1001(0) -> 8_1000(2) -> 0
    // count less than 7:  8_1000(2) -> 0
    // count less than 6:  7_111(0) -> 6_110(1) -> 4_100 -> 0
    // count less than 5:  6_110(1) -> 4_100 -> 0
    // count less than 4:  5_101(0) -> 4_100 -> 0

This is not the first time I see the BIT, but it is so rare, I forgot how it works. The idea is the bits: each rightmost bit is a parent of all the left bits. The core implementation tricks:

  • use idx + 1
  • use i & (-i), and + makes it go to the parent, - iterates all the children

Approac