stevensonmt

stevensonmt

LeetCode Convert BST to Greater Tree: how to do without GenServer?

I simply could not figure out a way to solve this problem without using a GenServer to keep the state of the running sum. My solution with GenServer is below, but I’m wondering if anyone could suggest a way to do it without a GenServer, which felt like overkill.

  use GenServer 
  
  def init(tally), do: {:ok, tally}

  def handle_cast({:add, n}, tally), do: {:noreply, n + tally}

  def handle_call(:tally, _from, tally), do: {:reply, tally, tally}


  @spec convert_bst(root :: TreeNode.t | nil) :: TreeNode.t | nil
  def convert_bst(root) do
    {:ok, pid} = GenServer.start(__MODULE__, 0)
    do_convert(root, pid)
  end
 
  def do_convert(nil, tally), do: nil
  def do_convert(node, tally) do
    right = do_convert(node.right, tally)
    GenServer.cast(tally, {:add, node.val})
    new_val = GenServer.call(tally, :tally)
    left = do_convert(node.left, tally)
    %TreeNode{ val: new_val, left: left, right: right}
  end

Marked As Solved

al2o3cr

al2o3cr

The GenServer lets do_convert do two things:

  • return a new tree node
  • as a side-effect, update the running total

To remove it, you’ll need to transform that side-effect into a part of the return value.

Consider Map.pop for inspiration; it returns a {popped_value, updated_map} tuple. You can combine it with rebinding to get code that looks almost like mutability:

things = %{a: 1, b: 2, c: 3}

{c_value, things} = Map.pop(things, :c)

A similar transformation on do_convert would make it return a tuple of {tree_node, updated_tally}.

Also Liked

stevensonmt

stevensonmt

Many thanks. I knew there must be some way to keep that “state” without using a GenServer. My first issue had actually been figuring out how to use the left node value as the tally for the grandparent node calculation. I only figured that out after changing to GenServer which made the steps in the process clearer to me. Changing to returning tuples was trivial. Thanks again.

  def convert_bst(root) do
    do_convert(root, 0) |> elem(0)
  end
 
  def do_convert(nil, tally), do: {nil, tally}
  def do_convert(node, tally) do
    {right, interim_tally} = do_convert(node.right, tally)
    new_val = interim_tally + node.val
    {left, final_tally} = do_convert(node.left, new_val)
    {%TreeNode{ val: new_val, left: left, right: right}, final_tally}
  end
Aetherus

Aetherus

I came up with a similar solution, and it passed the tests:

defmodule Solution do
  @spec convert_bst(root :: TreeNode.t | nil) :: TreeNode.t | nil  
  def convert_bst(root) do
    {converted, _} = do_convert_bst(root, 0)
    converted
  end
    
  defp do_convert_bst(nil, _carry), do: {nil, 0}
  defp do_convert_bst(node, carry) do
    {right, sum_r} = do_convert_bst(node.right, carry)
    carry = carry + node.val + sum_r
    {left, sum_l} = do_convert_bst(node.left, carry)
    {%TreeNode{left: left, right: right, val: carry}, node.val + sum_l + sum_r}
  end
end

carry is the sum of the values of all the nodes that have already been visited that have values greater than the next node to visit.

joaoevangelista

joaoevangelista

I have no ideia how to implement such algorithm, but!
Genservers are an abstraction over a looping receiver, so you can try to implement it with recursion, keeping the state as a parameter and keep passing it. Start with the base cases that returns a value instead of recusing. I bet it will look closely to your current implementation,but without the genserver specifics

stackcats

stackcats

There are many problems in Leetcode with the topic Design that you can’t do without using GenServer :joy:

Where Next?

Popular in Questions Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
logicmason
Hi there, I'm working through my first release with elixir/phoenix. I've built a release with distillery and found that it crashes when I...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
Fl4m3Ph03n1x
Background Let’s assume I have a typical GenServer that receives messages as requests, does some operation in a DB and returns responses....
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
Mooodi
Given a string, how can I get access to its character by index? Enum.at("my_string", 2) doesn't work. Or rather, not char, but a substr...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 27727 240
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New

We're in Beta

About us Mission Statement