stevensonmt
I’m trying to do a very basic union-find (not doing any path compression by rank or size).
def find(dsu, x) do
case Map.get(dsu, x) do
nil ->
{Map.put(dsu, x, x), x}
^x -> {dsu, x}
y ->
{dsu2, p} = find(dsu, y)
{Map.put(dsu2, x, p), p}
end
end
def union(%{} = dsu, x, y) do
{dsu, a} = find(dsu, x)
{dsu, b} = find(dsu, y)
if a == b do
dsu
else
[a,b] = Enum.sort([a,b])
{dsu, c} = find(dsu, a)
Map.put(dsu, b, c)
end
end
The issue I’m having is that after iterating over a set of nodes I have to iterate over all the “parents” a second time because the find function isn’t recursing on those.
@spec num_islands(grid :: [[char]]) :: integer
def num_islands(grid) do
map = LandMap.new(grid)
m = grid |> length() |> Kernel.-(1)
n = hd(grid) |> length() |> Kernel.-(1)
intermediate =
0..m
|> Enum.reduce(%{}, fn x, acc ->
0..n
|> Enum.filter(fn y -> MapSet.member?(map, {x,y}) end)
|> Enum.reduce(acc, fn y, acc2 ->
acc3 = DSU.union(acc2, {x,y}, {x,y})
LandMap.neighbors({x,y}, m, n)
|> Enum.filter(fn coord -> MapSet.member?(map, coord) end)
|> Enum.reduce(acc3, fn neighbor, acc4 -> DSU.union(acc4, neighbor, {x,y}) end)
end)
end)
intermediate
|> Map.values()
|> Enum.reduce(intermediate, fn x, islands ->
case DSU.find(islands, x) do
{^islands, ^x} -> islands
{islands, y} ->
islands
|> Enum.map(fn {k, v} = curr ->
if v == x do
{k, y}
else
curr
end
end)
|> Map.new()
true -> islands
end
end)
|> Map.values()
|> Enum.uniq()
|> Enum.count()
end
If I don’t do the second pass a node that was initially it’s own parent but later linked to others will get updated, but any nodes pointing to it as parent would not be updated. Do I need to track a “parents” map and a “children” map so that I can update any children when a “parent” is updated?
Trending in Questions
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
Hi everyone,
I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding.
I sta...
New
Hello,
I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
Documentation
While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
So my question is quite simple and i have found no conclusive answer on forum, google or AI.
Should we use :erlang.float for Integer to ...
New
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
I’m new to elixir and just tried to install the elixirLS extension for VScode(ium) and it is throwing some errors that I would like help ...
New
Other Trending Topics
Edit: 2026 May 15 - This post is archived.
Mob is alive!!
Main docs: mob v0.7.11 — Documentation
A bit of explanation for the slightly c...
New
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hi there! We created Gust: A task orchestrator inspired by Airflow.
For those who have never heard about Aiflow, it’s a Python-based wor...
New
Hi everyone!
The first release candidate for the Expert language server project is now available!
We’ve published a press release detai...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #ai
- #elixirconf-us
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #elixirconf-eu
- #metaprogramming
- #hex











Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
hst337
Could you please describe original task and what “union find algorithm” is for?
stevensonmt
Leetcode Number of Islands problem: https://leetcode.com/problems/number-of-islands/
Also in case you meant what “union find” means, a lot of places refer to it as “disjoint set” I think.
hst337
Generally speaking, you need traverse all the map point by point and do BFS for every new piece of land you encounter. This will be
O(N)in time and memory solution whereNis the size of the map. I don’t know anything about Union Find algorithm you’re referring tostevensonmt
Thanks. I’m not really trying to solve the problem so much as use this problem to learn about implementing disjoint set and union find concepts. Disjoint-set data structure - Wikipedia
code-shoily
I will look into it after work. It’s surprising how hard on memory disjoint set is despite being a simple algorithm.
I looked into number of island and I think using :digraph and connected component could help?
Back to your DS algorithm I’m interested to trace it but if it helps let me send you an implementation I did: ex_algo/lib/ex_algo/set/disjoint_set.ex at main · code-shoily/ex_algo · GitHub
Thank you for motivating me to look into that again, I’ll be back soon
stevensonmt
haha, I’ve had your code in an open tab the whole time I’ve been working on this and the Most Stones Removed problem. I had no chance getting it right until I read your code.
code-shoily
Do you have any “intuitive” feel towards disjoint set? I seem to lose my understanding of it after some time of not using it. I looked at my own code and was like, wtf was I thinking?
code-shoily
So I spun up a livebook and tried your code, see if I do these:
Then I end up with
%{1 => 1, 2 => 1, 4 => 2}- which is not wrong,4has the parent2which has the parent1. So1,2and4belong to the same club. However, you’d need to flatten it up with an extra run which would collapse the4 -> 2 -> 1path. I guess that’s why compressions optimize, since when you have a clash and you use the size/rank etc to be the determinant of who becomes the parent, so in that case, when1met2,2already had a follower (that being4), so it deserved to be1-s parent, so there is no ambiguity.Now, with union by rank compression enabled, look into the sequence below:
If you now look into the parent/rank:
I tried creating two heavily connected group and then join them, so that there are two sets of parents.
See
findpath is shorter, it will be? -> 8 -> 2in the worst case, however, we could introduce more techniques to make it even better. So ideally, the island counting algorithm should really be runningfindon each points, making it a(O(LandVertex * PathCompressionDS)). Also this assumes some kungfu to optimize parent length and updating of data structure perfindrun.So, to find the number of islands, I think a way would be to find each point in the processed disjoint set and adding the parent to a set. So the more optimized
)
findis, the more optimized the collection would be. (But I’d still prefer connected components approach to solving the island problem, and I get nervous around 2D grid type problems with Elixircode-shoily
I should revisit my implementation, it might improve with some optimization and might help me learn a few things, especially around some intuitive understanding of how the compressions, splitting, halving etc work on the parent data and friends.
hst337
I wrote this simple rank-based disjoint set implementation. I chose verbosity and ease of reading over performance