Coding Challenge #9: Recamán's sequence

Coding Challenge #9

Hello! Welcome back to another challenge. I am still looking for people to help me out and make challenges as well! So if you’re interested, help me out!

As usual, same requirements:

  • Has to be written in Lua 5.1 (the version roblox uses)
  • The program has to be compatible with Roblox Studio, meaning you can’t use features vanilla Lua has but rbxlua disabled
  • You can’t use httpservice to cheat the challenge

Recamán’s sequence is a sequence where the first term is 0 (meaning R(0) = 0), and each next term in the sequence is either the previous term minus the current index, if the result is negative, then the next term is the previous term plus the current index.

The first few terms of the sequence are: 0, 1, 3, 6, 2, 7, 13, 20, 12…

Write a function R(n), that returns the n-th term in the sequence.

R(0) -- 0
R(1) -- 1
R(2) -- 3
R(3) -- 6

R(12) -- 18
R(20) -- 22
R(100) -- 152

Goodluck! You can find a list of all the challenges here or a github version here.

Answer!

More formally,
image

If you ever made an algorithm for a fabonacci sequence for example, making an algorithm for another sequence would become a piece of cake! What’s the answer? Recursion.
Technically, in order to calculate the value each time we would need to do this

local previous = R(n-1)
if previous - i > 0 then
    return previous - i
else
   return previous + i
end

and with ternary magic we can do

local previous = R(n-1)
return previous - n > 0 and previous - n or previous + n

Now, let’s say we called R(3), the function will need to get the previous term, which is the 2nd term first in order to perform the calculations later. The 2nd term will need the 1st term, because any term requires the previous one. The 1st would require the starting term, the 0-th if you’d call it that, which is 0. We know the starting term so we can simply return it straight away (if n == 0 then return 0). Now we go up the ladder again, we hand off the 1st term 0, it finishes its calculation, we hand off the result of that to the 2nd term, and we hand off the result of that to the 3rd term, and we get out final result (which is 6). The poor computer has to go through this whole process! Imagine if we wanted to get the 100th term. This our function, very simple.

local function R(n)
	if n == 0 then return 0 end
    local r = R(n-1)
	return r - n > 0 and r - n or r + n
end

You can even do this with iteration, but in cases like these, recursion seems to be superior, because it’s easier to understand and read. But performance wise, iteration is better.

local function R(n)
	if n == 0 then return 0 end
  local r = R(n-1)
	return r - n > 0 and r - n or r + n
end

local function R2(n)
  local previous = 0
  for i = 1, n do
    previous = previous-i>0 and previous-i or previous+i
  end
  return previous
end

local start = tick()
for i = 1, 10000 do
  R(i)
end
print(tick()-start) --8.298012

local start = tick()
for i = 1, 10000 do
  R2(i)
end
print(tick()-start) --3.761421

The Slightly Spooky Recamán Sequence - Numberphile - YouTube

6 Likes
local index = 0 

function R(n)
	index += 1
	
	if n == 0 then print("0") end
	
	if n > 0 then
		print(n)
		R( (n-1) - index )
	else
		R( (n-1) + index )	
	end
end

R(0)
1 Like

Here’s my solution:

code
local function recaman(ind)
	if ind == 0 then return 0 end

	local prev = recaman(ind - 1)
	if prev - ind <= 0 then
		return prev + ind
	else
		return prev - ind
	end
end

Alternatively:

code
local cache = {0, 1, 3, 6, 2, 7, 1, 8, 16, 7, 17, 6, 18, 5, 19, 4, 20, 3, 21, 2, 22, 1, 23, 46, 22, 47, 21, 48, 20, 49, 19, 50, 18, 51, 17, 52, 16, 53, 15, 54, 14, 55, 13, 56, 12, 57, 11, 58, 10, 59, 9, 60, 8, 61, 7, 62, 6, 63, 5, 64, 4, 65, 3, 66, 2, 67, 1, 68, 136, 67, 137, 66, 138, 65, 139, 64, 140, 63, 141, 62, 142, 61, 143, 60, 144, 59, 145, 58, 146, 57, 147, 56, 148, 55, 149, 54, 150, 53, 151, 52, 152, 51, 153, 50, 154, 49, 155, 48, 156, 47, 157, 46, 158, 45, 159, 44, 160, 43, 161, 42, 162, 41, 163, 40, 164, 39, 165, 38, 166, 37, 167, 36, 168, 35, 169, 34, 170, 33, 171, 32, 172, 31, 173, 30, 174, 29, 175, 28, 176, 27, 177, 26, 178, 25, 179, 24, 180, 23, 181, 22, 182, 21, 183, 20, 184, 19, 185, 18, 186, 17, 187, 16, 188, 15, 189, 14, 190, 13, 191, 12, 192, 11, 193, 10, 194, 9, 195, 8, 196, 7, 197, 6, 198, 5, 199, 4, 200, 3, 201, 2, 202, 1, 203, 406, 202, 407, 201, 408, 200, 409, 199, 410, 198, 411, 197, 412, 196, 413, 195, 414, 194, 415, 193, 416, 192, 417, 191, 418, 190, 419, 189, 420, 188, 421, 187, 422, 186, 423, 185, 424, 184, 425, 183, 426, 182, 427, 181, 428, 180, 429, 179, 430, 178, 431, 177, 432, 176, 433, 175, 434, 174, 435, 173, 436, 172, 437, 171, 438, 170, 439, 169, 440, 168, 441, 167, 442, 166, 443, 165, 444, 164, 445, 163, 446, 162, 447, 161, 448, 160, 449, 159, 450, 158, 451, 157, 452, 156, 453, 155, 454, 154, 455, 153, 456, 152, 457, 151, 458, 150, 459, 149, 460, 148, 461, 147, 462, 146, 463, 145, 464, 144, 465, 143, 466, 142, 467, 141, 468, 140, 469, 139, 470, 138, 471, 137, 472, 136, 473, 135, 474, 134, 475, 133, 476, 132, 477, 131, 478, 130, 479, 129, 480, 128, 481, 127, 482, 126, 483, 125, 484, 124, 485, 123, 486, 122, 487, 121, 488, 120, 489, 119, 490, 118, 491, 117, 492, 116, 493, 115, 494, 114, 495, 113, 496, 112, 497, 111, 498, 110, 499, 109, 500, 108, 501, 107, 502, 106, 503, 105, 504, 104, 505, 103, 506, 102, 507, 101, 508, 100, 509, 99, 510, 98, 511, 97, 512, 96, 513, 95, 514, 94, 515, 93, 516, 92, 517, 91, 518, 90, 519, 89, 520, 88, 521, 87, 522, 86, 523, 85, 524, 84, 525, 83, 526, 82, 527, 81, 528, 80, 529, 79, 530, 78, 531, 77, 532, 76, 533, 75, 534, 74, 535, 73, 536, 72, 537, 71, 538, 70, 539, 69, 540, 68, 541, 67, 542, 66, 543, 65, 544, 64, 545, 63, 546, 62, 547, 61, 548, 60, 549, 59, 550, 58, 551, 57, 552, 56, 553, 55, 554, 54, 555, 53, 556, 52, 557, 51, 558, 50, 559, 49, 560, 48, 561, 47, 562, 46, 563, 45, 564, 44, 565, 43, 566, 42, 567, 41, 568, 40, 569, 39, 570, 38, 571, 37, 572, 36, 573, 35, 574, 34, 575, 33, 576, 32, 577, 31, 578, 30, 579, 29, 580, 28, 581, 27, 582, 26, 583, 25, 584, 24, 585, 23, 586, 22, 587, 21, 588, 20, 589, 19, 590, 18, 591, 17, 592, 16, 593, 15, 594, 14, 595, 13, 596, 12, 597, 11, 598, 10, 599, 9, 600, 8, 601, 7, 602, 6, 603, 5, 604, 4, 605, 3, 606, 2, 607, 1, 608, 1216, 607, 1217, 606, 1218, 605, 1219, 604, 1220, 603, 1221, 602, 1222, 601, 1223, 600, 1224, 599, 1225, 598, 1226, 597, 1227, 596, 1228, 595, 1229, 594, 1230, 593, 1231, 592, 1232, 591, 1233, 590, 1234, 589, 1235, 588, 1236, 587, 1237, 586, 1238, 585, 1239, 584, 1240, 583, 1241, 582, 1242, 581, 1243, 580, 1244, 579, 1245, 578, 1246, 577, 1247, 576, 1248, 575, 1249, 574, 1250, 573, 1251, 572, 1252, 571, 1253, 570, 1254, 569, 1255, 568, 1256, 567, 1257, 566, 1258, 565, 1259, 564, 1260, 563, 1261, 562, 1262, 561, 1263, 560, 1264, 559, 1265, 558, 1266, 557, 1267, 556, 1268, 555, 1269, 554, 1270, 553, 1271, 552, 1272, 551, 1273, 550, 1274, 549, 1275, 548, 1276, 547, 1277, 546, 1278, 545, 1279, 544, 1280, 543, 1281, 542, 1282, 541, 1283, 540, 1284, 539, 1285, 538, 1286, 537, 1287, 536, 1288, 535, 1289, 534, 1290, 533, 1291, 532, 1292, 531, 1293, 530, 1294, 529, 1295, 528, 1296, 527, 1297, 526, 1298, 525, 1299, 524, 1300, 523, 1301, 522, 1302, 521, 1303, 520, 1304, 519, 1305, 518, 1306, 517, 1307, 516, 1308, 515, 1309, 514, 1310, 513, 1311, 512, 1312, 511, 1313, 510, 1314, 509, 1315, 508, 1316, 507, 1317, 506, 1318, 505, 1319, 504, 1320, 503, 1321, 502, 1322, 501, 1323, 500, 1324, 499, 1325, 498, 1326, 497, 1327, 496, 1328, 495, 1329, 494, 1330, 493, 1331, 492, 1332, 491, 1333, 490, 1334, 489, 1335, 488, 1336, 487, 1337, 486, 1338, 485, 1339, 484, 1340, 483, 1341, 482, 1342, 481, 1343, 480, 1344, 479, 1345, 478, 1346, 477, 1347, 476, 1348, 475, 1349, 474, 1350, 473, 1351, 472, 1352, 471, 1353, 470, 1354, 469, 1355, 468, 1356, 467, 1357, 466, 1358, 465, 1359, 464, 1360, 463, 1361, 462, 1362, 461, 1363, 460, 1364, 459, 1365, 458, 1366, 457, 1367, 456, 1368, 455, 1369, 454, 1370, 453, 1371, 452, 1372, 451, 1373, 450, 1374, 449, 1375, 448, 1376, 447, 1377, 446, 1378, 445, 1379, 444, 1380, 443, 1381, 442, 1382, 441, 1383, 440, 1384, 439, 1385, 438, 1386, 437, 1387, 436, 1388, 435, 1389, 434, 1390, 433, 1391, 432, 1392, 431, 1393, 430, 1394, 429, 1395, 428, 1396, 427, 1397, 426, 1398, 425, 1399, 424, 1400, 423, 1401, 422, 1402, 421, 1403, 420, 1404, 419, 1405, 418, 1406, 417, 1407, 416, 1408, 415, 1409, 414, 1410, 413, 1411, 412, 1412}

setmetatable(cache, {__index = function(self, ind)
	local prev = cache[ind - 1]
	if prev - ind <= 0 then
		rawset(self, ind, prev + ind)
		return prev + ind
	else
		rawset(self, ind, prev - ind)
		return prev - ind
	end
end})

local function recaman(ind)
	return cache[ind]
end

I don’t find these challenges as interesting when there’s already an algorithm given. Might not continue doing these challenges in the future.

6 Likes

First attempt:
I made some minor optimizations

RT = {}

function R(n)
	if n == 0 then
		return 0
	end
	local BeforeN = RT[n-1] or R(n-1)
	
	if BeforeN - n > 0 then
		RT[n] = RT[n] or BeforeN - n
		return BeforeN - n
	else 
		RT[n] = RT[n] or BeforeN +n
		return BeforeN + n 
	end
end

1 Like

How about a non-recursive option?

local function Recaman(n)
  local sequence = table.create(n, 0);
  for i = 1, #sequence do
    local prev = sequence[i - 1] or 0;
    if (prev - i > 0 and not table.find(sequence, prev - i)) then
      sequence[i] = prev - i;
    else
      sequence[i] = prev + i;
    end
  end
  return sequence[n] or 0;
end
2 Likes