changeset 27:668adaf0313f

three-sum
author Lewin Bormann <lbo@spheniscida.de>
date Sat, 04 Mar 2023 12:08:16 +0100
parents 015fe10a59cd
children 743af1962848
files julia/arrays.jl
diffstat 1 files changed, 80 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/julia/arrays.jl	Sat Mar 04 11:31:42 2023 +0100
+++ b/julia/arrays.jl	Sat Mar 04 12:08:16 2023 +0100
@@ -76,6 +76,86 @@
     nothing
 end
 
+# About 11x faster than without memoization for input set of n = 11
+# MUCH MUCH faster for larger input sets
+function threesum_memoize(a::AbstractVector{<:Integer}, s, i=1, running::Tuple=(), triplets=Set{Tuple}(), badstarts=Set{Tuple}())
+    markbad(t) = if length(t) < 3 push!(badstarts, t) end
+    isbad(t) = t in badstarts
+
+    if i > length(a) && length(running) < 3
+        return 0
+    end
+    if length(running) == 3
+        if sum(running) == s
+            push!(triplets, running)
+            return 1
+        end
+        return 0
+    elseif length(running) == 2
+        current = a[i]
+        # incl/excl/new
+        possibilities = [running, (running..., current), (running[1], current), (running[2], current), ()]
+        for p = possibilities
+            if !isbad(p) && 0 == threesum_memoize(a, s, i+1, p, triplets, badstarts)
+                markbad(p)
+            end
+        end
+    elseif length(running) == 1
+        current = a[i]
+        possibilities = [(running[1], current), running, ()]
+        # incl/excl current element
+        for p = possibilities
+            if !isbad(p) && 0 == threesum_memoize(a, s, i+1, p, triplets, badstarts)
+                markbad(p)
+            end
+        end
+    elseif length(running) == 0
+        current = a[i]
+        if !isbad((current,)) && 0 == threesum_memoize(a, s, i+1, (current,), triplets, badstarts)
+            markbad((current,))
+        end
+        if !isbad(running) && 0 == threesum_memoize(a, s, i+1, running, triplets, badstarts)
+            markbad(running)
+        end
+    end
+    if i == 1
+        @show badstarts
+        return triplets
+    end
+end
+
+function threesum(a::AbstractVector{<:Integer}, s, i=1, running::Tuple=(), triplets=Set{Tuple}())
+    if i > length(a) && length(running) < 3
+        return
+    end
+    if length(running) == 3
+        if sum(running) == s
+            push!(triplets, running)
+        end
+    elseif length(running) == 2
+        current = a[i]
+        # incl/excl/new
+        threesum(a, s, i+1, running, triplets)
+        threesum(a, s, i+1, (running..., current), triplets)
+        threesum(a, s, i+1, (running[1], current), triplets)
+        threesum(a, s, i+1, (running[2], current), triplets)
+        threesum(a, s, i+1, (), triplets)
+    elseif length(running) == 1
+        current = a[i]
+        # incl/excl current element
+        threesum(a, s, i+1, (running[1], current), triplets)
+        threesum(a, s, i+1, running, triplets)
+        threesum(a, s, i+1, (), triplets)
+    elseif length(running) == 0
+        current = a[i]
+        threesum(a, s, i+1, (current,), triplets)
+        threesum(a, s, i+1, running, triplets)
+    end
+    if i == 1
+        return triplets
+    end
+end
+
 function watercontainer(a::Vector{Int})
     maxvol = 0
     best = (0,0)