Coding Challenge #6
Welcome back, to another coding challenge! I’ve been getting some feedbacks telling me that the challenges are becoming somewhat very easy, for an experienced individual to say the least. Which is not necessarily bad, in fact it’s good because more people can contribute that way, but I’ll try to vary the difficulty in future challenges!
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
Given an array of positive integers, write a function firstDuplicate
to find the first integer that is repeated at least once. If no duplicate is found return -1
. Examples:
{1,2,3,1} --1
{2,1,4,2,4} --2
{12,4,5,9,15,12,2} --12
{1,2,3,4,5} -- -1
Here is a function to generate random number for you
local function random()
local n = math.random(1, 20)
local t = table.create(n)
for i = 1, n do
t[i] = math.random(1, n)
end
return t
end
Note that, you can see that the integers inside of the table are between 1 and the size of the table, meaning we don’t have an integer that’s greater than the table’s size. See if you can use that for your advantage!
Goodluck! You can find a list of all the challenges here or a github version here.
Answer!
I simply make a table toLookFor
to keep track of the integers that we’ve seen, and we loop through the table and each time make an arbitrary value (true
for example) inside of toLookFor
at the index corresponding with the current integer, and as well each time we loop we check if a true
exists in toLookFor[current integer]
which means that we have already seen this integer.
local function firstDuplicate(t)
local toLookFor = {}
for i, v in pairs(t) do
if toLookFor[v] then
return v
end
toLookFor[v] = true
end
return -1
end
Another way to do it is using table.find()
, and see if after the current index there is a similar integer.
local function firstDuplicate(t)
local toLookFor = {}
for i, v in pairs(t) do
if table.find(t, v, i+1) then
return v
end
return -1
end
A golf code driven answer using the table.find
method
function f(t)for i=1,#t do if table.find(t,t[i],i+1)then return t[i]end end return-1 end
Now for the creative answer. Remember when I told you?
Note that, you can see that the integers inside of the table are between 1 and the size of the table, meaning we don’t have an integer that’s greater than the table’s size. See if you can use that for your advantage!
What you can do is using this fact for your advantage: since there is no way an integer inside of the table can be greater then the table’s size, technically any integer can describe an index inside of that table. Each time we visit an integer, we go to the index that it’s supposed to represent in that table, and we negate the value at that index, as a way of saying “we have seen an integer that leads back to this index”. Like that, each time we visit an integer, we check if the index that it leads to is already negative, if it is already negative that means a previous integer led to the same index thus they’re equal, and return that. Brilliant!
local function firstDuplicate(t)
for i, v in pairs(t) do
t[math.abs(v)] = -t[math.abs(v)] --negate it, t[v] is the index v leads to, we do math.abs because there is a chance that the value we visited has already been tagged which means it's negative, and we can't index with negative integers.
if t[v] < 0 then --we check if the value of the index that it leads to is positive, because technically if we negated it/flipped its sign and got a positive number as a result, that means it was previously negative, which means it was tagged and return the current integer
return v
end
end
return -1
end