Block sequence in Java

3 min read 765 words

Table of Contents

The challenge

Consider the following array:

[1, 12, 123, 1234, 12345, 123456, 1234567, 12345678, 123456789, 12345678910, 1234567891011...]

If we join these blocks of numbers, we come up with an infinite sequence which starts with 112123123412345123456.... The list is infinite.

You will be given an number (n) and your task will be to return the element at that index in the sequence, where 1 ≤ n ≤ 10^18. Assume the indexes start with 1, not ``. For example:

solve(1) = 1, because the first character in the sequence is 1. There is no index 0. 
solve(2) = 1, because the second character is also 1.
solve(3) = 2, because the third character is 2.

The solution in Java code

Option 1:

class Solution{
    private static long bSearch(long n) {    
        long res = 0, i = 1, k = 9, j = 9;
        for (; j < n; ++i, k *= 10, j += k){
            res += i * k * (k + 1) / 2;
            res += i * k * (n - j);
        }
        k = n - j / 10;
        res += i * k * (k + 1) / 2;
        return res;
    }
      
    public static int solve(long n) {
        n--;
        long lb = 0, rb = (long)1e9;
        while (lb < rb){
            long mb = (lb + rb + 1) / 2;
            if (bSearch(mb) > n) rb = mb - 1;   
            else lb = mb;   
        }
        n -= bSearch(lb);
        long cnt = 9, len = 1;
        while (n >= cnt * len){
            n -= cnt * len;
            cnt *= 10;
            ++len;
        }
        String x = String.valueOf(cnt / 9 + n / len);
        int y = (int)(n % len);
        return x.charAt(y) - '0';
    }
}

Option 2:

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;

public class Solution {

    public static int solve(long n) {
        return getPoz(getShorterNumber(n));
    }

    private static long getShorterNumber(long n) {
        long shortN = n;
        long add = 1;
        int digits = 1;
        Numbers[] SAFE_TO_REMOVE = {
                new Numbers(45L, 11L),
                new Numbers(9045L, 192L),
                new Numbers(1395495L, 2893L),
                new Numbers(189414495L, 38894L),
                new Numbers(23939649495L, 488895L),
                new Numbers(2893942449495L, 5888896L),
                new Numbers(339393974949495L, 68888897L),
                new Numbers(38939394344949495L, 788888898L),
                new Numbers(4393939398494949495L, 8888888899L)
        };

        for (int i = 0; i < SAFE_TO_REMOVE.length; i++) {
            if (SAFE_TO_REMOVE[i].start >= n) {
                if (i > 0) {
                    shortN = n - SAFE_TO_REMOVE[i - 1].start;
                    add = SAFE_TO_REMOVE[i - 1].add;
                    digits = i + 1;
                }
                break;
            }
        }

        return getEvenShorterNumber(digits, add, shortN - 1);
    }

    public static long getEvenShorterNumber(long digit, long start, long n) {
        BigDecimal b = BigDecimal.valueOf((start - 0.5 * digit));
        double X = b.multiply(b)
                .add(BigDecimal.valueOf(2).multiply(BigDecimal.valueOf(digit)).multiply(BigDecimal.valueOf(n)))
                .sqrt(MathContext.DECIMAL64)
                .subtract(b)
                .divide(BigDecimal.valueOf(digit), 8, RoundingMode.HALF_UP)
                .doubleValue();
        long longX = (long) X;
        long shorterNumber = (2L * start + (longX - 1L) * digit) * longX / 2L;
        return (n - shorterNumber + 1);
    }

    private static int getPoz(long n) {
        long n0 = n - 1;
        long prevN;
        int i = 0;
        do {
            prevN = n0;
            n0 -= 9 * Math.pow(10.0, i) * (i + 1);
            i++;
        } while (n0 >= 0);
        long number = (long) Math.pow(10.0, i - 1) + prevN / i;
        int digitPoz = (int) (prevN % i);
        String digit = String.valueOf(number).substring(digitPoz, digitPoz + 1);
        return Integer.decode(digit);
    }

    private static class Numbers {
        final long start;
        final long add;

        Numbers(long start, long add) {
            this.start = start;
            this.add = add;
        }
    }
}

Option 3:

class Solution{
    public static long bSearch(long n){    
        long res = 0, i = 1, k = 9, j = 9;
        for (; j < n; ++i, k *= 10, j += k){
          res += i * k * (k + 1) / 2;
          res += i * k * (n - j);
        }
        k = n - j / 10;
        res += i * k * (k + 1) / 2;
        return res;
      }    
      public static int solve(long n){
          n--;
          long lb = 0, rb = (long)1e9;
          while (lb < rb){
              long mb = (lb + rb + 1) / 2;
              if (bSearch(mb) > n) rb = mb - 1;   
              else lb = mb;   
          }
          n -= bSearch(lb);
          long cnt = 9, len = 1;
          while (n >= cnt * len){
              n -= cnt * len;
              cnt *= 10;
              ++len;
          }
          String x = String.valueOf(cnt / 9 + n / len);
          int y = (int)(n % len);
          return x.charAt(y) - '0';
      }
}

Test cases to validate our solution

import org.junit.Test;
import static org.junit.Assert.assertEquals;
import org.junit.runners.JUnit4;

public class SolutionTest{    
    @Test
    public void basicTests(){     
        assertEquals(1, Solution.solve(1L));
        assertEquals(1, Solution.solve(2L));
        assertEquals(2, Solution.solve(3L));
        assertEquals(1, Solution.solve(100L));  
        assertEquals(2, Solution.solve(2100L));
        assertEquals(2, Solution.solve(3100L));
        assertEquals(1, Solution.solve(55L));
        assertEquals(6, Solution.solve(123456L));
        assertEquals(3, Solution.solve(123456789L));  
        assertEquals(4, Solution.solve(999999999999999999L));
        assertEquals(1, Solution.solve(1000000000000000000L));
        assertEquals(7, Solution.solve(999999999999999993L));   
    }
}
Tags:
Andrew
Andrew

Andrew is a visionary software engineer and DevOps expert with a proven track record of delivering cutting-edge solutions that drive innovation at Ataiva.com. As a leader on numerous high-profile projects, Andrew brings his exceptional technical expertise and collaborative leadership skills to the table, fostering a culture of agility and excellence within the team. With a passion for architecting scalable systems, automating workflows, and empowering teams, Andrew is a sought-after authority in the field of software development and DevOps.

Tags

Recent Posts