Decompose a number into triangles

15

Given an integer n, decompose it into a sum of maximal triangular numbers (where Tm represents the mth triangular number, or the sum of the integers from 1 to m) as follows:

  • while n > 0,

    • find the largest possible triangular number Tm such that Tm ≤ n.

    • append m to the triangular-decomposition representation of n.

    • subtract Tm from n.

For example, an input of 44 would yield an output of 8311, because:

  • 1+2+3+4+5+6+7+8 = 36 < 44, but 1+2+3+4+5+6+7+8+9 = 45 > 44.

    • the first digit is 8; subtract 36 from 44 to get 8 left over.
  • 1+2+3 = 6 < 8, but 1+2+3+4 = 10 > 8.

    • the second digit is 3; subtract 6 from 8 to get 2 left over.
  • 1 < 2, but 1+2 = 3 > 2.

    • the third and fourth digits must be 1 and 1.

Use the digits 1 through 9 to represent the first 9 triangular numbers, then use the letters a through z (can be capitalized or lowercase) to represent the 10th through 35th triangular number. You will never be given an input that will necessitate the use of a larger "digit".

The bounds on the input are 1 ≤ n < 666, and it will always be an integer.

All possible inputs and outputs, and some selected test cases (listed as input, then output):

1 1
2 11
3 2
4 21
5 211
6 3
100 d32
230 k5211
435 t
665 z731

An output of for an input of -1/12 is not required. :)

Doorknob

Posted 2017-05-02T00:14:58.907

Reputation: 68 138

But does an input of need to have an output of ∞?

– user75200 – 2017-10-26T09:22:15.577

Answers

8

JavaScript (ES6), 52 bytes

f=(n,t=0)=>t<n?f(n-++t,t):t.toString(36)+(n?f(n):'')

How?

Rather than explicitly computing Ti = 1 + 2 + 3 + … + i, we start with t = 0 and iteratively subtract t + 1 from n while t < n, incrementing t at each iteration. When the condition is not fulfilled anymore, a total of Tt has been subtracted from n and the output is updated accordingly. We repeat the process until n = 0.

Below is a summary of all operations for n = 100.

 n  |  t | t < n | output
----+----+-------+--------
100 |  0 | yes   | ""
 99 |  1 | yes   | ""
 97 |  2 | yes   | ""
 94 |  3 | yes   | ""
 90 |  4 | yes   | ""
 85 |  5 | yes   | ""
 79 |  6 | yes   | ""
 72 |  7 | yes   | ""
 64 |  8 | yes   | ""
 55 |  9 | yes   | ""
 45 | 10 | yes   | ""
 34 | 11 | yes   | ""
 22 | 12 | yes   | ""
  9 | 13 | no    | "d"
----+----+-------+--------
  9 |  0 | yes   | "d"
  8 |  1 | yes   | "d"
  6 |  2 | yes   | "d"
  3 |  3 | no    | "d3"
----+----+-------+--------
  3 |  0 | yes   | "d3"
  2 |  1 | yes   | "d3"
  0 |  2 | no    | "d32"

Test cases

f=(n,t=0)=>t<n?f(n-++t,t):t.toString(36)+(n?f(n):'')

console.log(f(1))   // 1
console.log(f(2))   // 11
console.log(f(3))   // 2
console.log(f(4))   // 21
console.log(f(5))   // 211
console.log(f(6))   // 3
console.log(f(100)) // d32
console.log(f(230)) // k5211
console.log(f(435)) // t
console.log(f(665)) // z731

Arnauld

Posted 2017-05-02T00:14:58.907

Reputation: 111 334

5

Jelly, 18 17 bytes

Ḥ‘½+.Ḟ©ịØB2®cạµ¹¿

This is a monadic link that prints to STDOUT. It's return value is 0 and should be ignored.

Try it online!

Dennis

Posted 2017-05-02T00:14:58.907

Reputation: 196 637

4

dc, 74 bytes

?sa[2k_1K/1 4/la2*+v+0k1/dlardd*+2/-sadd10<t9>ula0<s]ss[87+P]st[48+P]sulsx

This is awful.

?sa             stores the input
[2k             sets precision to 2 so dc doesn't truncate 1/4
_1K/1 4/la2*+v+ uses the quadratic formula to find k, the next value to print
0k1/d           truncates k to an integer
lardd*+2/-sa    subtracts kth triangular number from the input 
dd10<t9>u       determines whether to print k as a letter or a digit         
la0<s]ss        loops when a is greater than 0
[87+P]st        prints k as a letter
[48+P]su        prints k as a digit (not p, as that leaves a trailing newline)
lsx             starts the main loop

poi830

Posted 2017-05-02T00:14:58.907

Reputation: 1 265

3

JavaScript (ES6), 61 57 bytes

Saved 4 bytes thanks to @Arnauld

f=(n,p=q=0)=>n?p-~q>n?q.toString(36)+f(n-p):f(n,++q+p):''

ETHproductions

Posted 2017-05-02T00:14:58.907

Reputation: 47 880

1I had f=(n,t=0)=>n?t+1>n?t.toString(36)+f(n):f(n-++t,t):1 – Arnauld – 2017-05-02T00:37:55.047

@Arnauld Oh wow, that's way better. You should post it yourself... – ETHproductions – 2017-05-02T00:39:17.100

1Alright. In your version, would it be safe to do f=(n,p=q=0) and f(n,++q+p)? – Arnauld – 2017-05-02T00:58:31.170

@Arnauld Yes, thanks! – ETHproductions – 2017-05-02T01:25:04.500

2

Retina, 115 108 38 34 bytes

.+
$*¶
(\G¶|¶\1)+
0$1
+T`_w¶`w_`.¶

[Try it online!] (Includes test suite) Uses uppercase letters. Edit: Saved 70 74 bytes by shamelessly adapting @MartinEnder's answer to Is this number triangular? Explanation: The number is converted into unary, then the largest possible triangular number is repeatedly matched until the number is exhausted. Each match is then converted into base 36.

Neil

Posted 2017-05-02T00:14:58.907

Reputation: 95 035

2

Java 7, 81 bytes

int i=0;String c(int n){return i<n?c(n-++i):Long.toString(i,36)+(n>(i=0)?c(n):"");}

Port from @Arnauld's amazing JavaScript (ES6) answer.
My own approach was almost 2x as long..

Try it here.

Explanation:

int i=0;                  // Temp integer `i` (on class level)
String c(int n){          // Method with integer parameter and String return-type
  return i<n?             //  If `i` is smaller than the input integer
    c(n-++i)              //   Return a recursive call with input minus `i+1` (and raise `i` by 1 in the process)
   :                      //  Else:
    Long.toString(i,36)+  //   Return `i` as Base-36 +
     (n>(i=0)?            //   (If the input integer is larger than 0 (and reset `i` to 0 in the process)
      c(n)                //    Recursive call with the input integer
     :                    //   Else:
      "");                //    an empty String)
}                         // End of method

Kevin Cruijssen

Posted 2017-05-02T00:14:58.907

Reputation: 67 575

1

PHP, 74 Bytes

for(;$n=&$argn;$t.=$i>10?chr($i+86):$i-1)for($i=0;$n>=++$i;)$n-=$i;echo$t;

Online Version

Jörg Hülsermann

Posted 2017-05-02T00:14:58.907

Reputation: 13 026

0

R, 87 bytes

Originally, I tried to preset the possible Triangular numbers. This led to this code with 105 bytes:

pryr::f(n,{l=cumsum(1:35)
k=''
while(n){y=tail(which(l<=n),1)
n=n-l[y]
k=paste0(k,c(1:9,letters)[y])}
k})

This required more indexing so I tried the methodology from @Arnauld to reduce the bytes down to 87.

pryr::f(n,{k='';while(n){t=0;while(t<n){t=t+1;n=n-t};k=paste0(k,c(1:9,letters)[t])};k})

Both codes made use of the preset letters, since their I couldn't find a short way to convert to base 36.

Shayne03

Posted 2017-05-02T00:14:58.907

Reputation: 347