How does backtracking work in going back up the stack in this example (generate parentheses)? - recursion

I've been working on learning backtracking and I know how the general template goes, but I'm struggling to fully understand how the algorithm backtracks, specifically how it knows when to pop from a current solution and how often to.
I know it should be that we have a base case, and when we hit this base case, we then return from this current iteration. But then I'm not fully sure on why we pop from a solution many times until we start exploring again.
For example, I've been working on the classic "Generate Parentheses" problem:
Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
E.g.
Input: n = 3
Output: ["((()))","(()())","(())()","()(())","()()()"]
Here's my working solution after applying my existing knowledge of how the template should be, but I just can't work out how currCombo.pop() falls into the thinking and visualising how it works.
function generateParenthesis(n) {
const result = [];
backtrack(result, n, 0, 0, []);
return result;
};
function backtrack(result, n, open, close, currCombo) {
if (currCombo.length === 2 * n) {
result.push(currCombo.join(''));
return;
}
if (open < n) {
currCombo.push('(');
backtrack(result, n, open + 1, close, currCombo);
currCombo.pop();
}
if (close < open) {
currCombo.push(')');
backtrack(result, n, open, close + 1, currCombo);
currCombo.pop();
}
}
So for example, the algorithm first outputs:
"((()))"
And the second result is then:
"(()())"
But how does the algorithm know it needs to pop off 3 close brackets and then 1 open bracket, and then to continue adding brackets from there? I debugged the code line by line and just couldn't see why it would do a certain number of pop operations and then continue.
I've tried checking out Youtube videos, articles, blogs, but I just can't visualise what the algorithm is doing and how it's making the decisions that it is when it is.
Any help much appreciated. Thanks

There's nothing for the algorithm to "know" exactly; each pop is an undo of the push that set up the call frame for the recursion. That's it. Most of the logic has to do with your if statements that protect the recursion, ensuring balance.
Think of it as a depth-first graph exploration where each node is a possible arrangement of up to n ( parentheses and n ) parentheses. The open and close variables don't encode any unique information. These variables are conveniences to avoid each frame having to count the already-chosen parentheses, and having these counts enables you to avoid exporing pointless subtrees which can never produce a result, like (((( on n=3.
Each recursive call frame begins by asking whether it's at a result point. If so, save the result and return. If not, if it'd be possible to reach a result by adding a ( to the end of the string so far, explore that subtree, then undo the move by popping, resetting to a clean state. Next, try adding ) if that might lead to a result, explore the subtree, and undo the move. After undoing any modifications made and exploring one or both subtrees, return to the caller since all possibilities have been explored rooted at this node in the graph.
Let's trace how we get to the first result "((()))" and then to "(()())".
On the first call, open < n ("the first branch") is true, so we push ( and spawn one recursive call with open = 1. This initial ( stays in the result for the duration of the algorithm; close < open ("the second branch") is false for the first call frame.
On the second call, both branches are true, so we'll eventually make two recursive calls, but for starters we try pushing ( again to give the string (( and recursing with open = 2.
On the third call, both branches are true, so we'll eventually make two recursive calls, but for starters we try pushing ( again to give the string ((( and recursing with open = 3.
On the fourth call, the first branch is false, so we only perform one recursion from the second branch close < open with the string ((() and open = 3, close = 1.
On the fifth call, the first branch is false, so we only perform one recursion from the second branch close < open with the string ((()) and open = 3, close = 2.
On the sixth call, the first branch is false, so we only perform one recursion from the second branch close < open with the string ((())) and open = 3, close = 3.
On the seventh call, currCombo.length === 2 * n is true so we add ((())) to the result and return back up one call frame.
Now the sixth call resumes executing and there's no code left to run; recall that for this frame, the first branch was false, so we skipped it, and we've already explored the second branch recursively. Pop the string to ((()) and return to the caller.
Now the fifth call resumes executing and there's no code left to run; recall that for this frame, the first branch was false, so we skipped it, and we've already explored the second branch recursively. Pop the string to ((() and return to the caller.
Now the fourth call resumes executing and there's no code left to run; recall that for this frame, the first branch was false, so we skipped it, and we've already explored the second branch recursively. Pop the string to ((( and return to the caller.
Now the third call resumes executing but we haven't explored the second branch yet, so pop ( again to give the string ((, then push ) and recurse on (() and open = 2, close = 1.
A new call, the eighth call, begins, and both branches are true, so we'll eventually make two recursive calls, but for starters we try pushing ( again to give the string (()( and recursing with open = 3, close = 1.
A new call, the ninth call, begins. The first branch is false, so we only perform one recursion from the second branch close < open with the string (()() and open = 3, close = 2.
A new call, the tenth call, begins. The first branch is false, so we only perform one recursion from the second branch close < open with the string (()()) and open = 3, close = 3.
A new call, the eleventh call, begins.
On this call, currCombo.length === 2 * n is true so we add (()()) to the result and return back up one call frame.
Now the tenth call resumes executing and there's no code left to run; recall that for this frame, the first branch was false, so we skipped it, and we've already explored the second branch recursively. Pop the string to (()() and return to the caller.
Now the ninth call resumes executing and there's no code left to run; recall that for this frame, the first branch was false, so we skipped it, and we've already explored the second branch recursively. Pop the string to (()( and return to the caller.
Now the eighth call resumes executing but we haven't explored the second branch yet, so pop ( again to give the string ((), then push ) and recurse on (()) and open = 2, close = 2.
... I'll stop here; finish tracing the execution to the next result (())() which you can see we're well on our way to building.
But how does the algorithm know it needs to pop off 3 close brackets and then 1 open bracket, and then to continue adding brackets from there?
It popped off 3 close parens because there was nothing left to explore on those call frames. The first branch was false and the second branch had already been explored.
The reason the 1 open paren was popped next is because the recursive subtree of possibilities starting with the open paren had already been explored fully, but the subtree rooted with ) hadn't been explored yet. When we left off our algorithm trace, we were just launching into exploring that subtree. When the subtree is exhausted and any results that it ultimately yielded had been stored, that paren would also pop off and the frame would be completely explored.
At that point, its caller (the second call in the above example) would still need to explore the subtree starting with (), open = 1, close = 1, since it had only tried ((, open = 2, close = 0 up to that point. In other words, it'll have explored the ( branch but not the ) branch that will ultimately lead to the last result ()()().
Here's a visualization of the recursive call tree:
function generateParenthesis(n) {
const result = [];
backtrack(result, n, 0, 0, []);
return result;
};
function backtrack(result, n, open, close, currCombo, depth=0) {
console.log(`${" ".repeat(depth * 2)}enter '${currCombo.join("")}'`);
if (currCombo.length === 2 * n) {
result.push(currCombo.join(''));
console.log(`${" ".repeat(depth * 2)}result '${currCombo.join("")}'`);
console.log(`${" ".repeat(depth * 2)}exit '${currCombo.join("")}'`);
return;
}
if (open < n) {
currCombo.push('(');
backtrack(result, n, open + 1, close, currCombo, depth + 1);
currCombo.pop();
}
if (close < open) {
currCombo.push(')');
backtrack(result, n, open, close + 1, currCombo, depth + 1);
currCombo.pop();
}
console.log(`${" ".repeat(depth * 2)}exit '${currCombo.join("")}'`);
}
generateParenthesis(3);
If that's too complex, you can dial it back to n = 2, trace that, then do n = 3.

Related

automatic gantt line numbering with elm

I am stuck with a functionality that i have already done in python long time ago.
I draw a gantt chart in a specific way that i can't reproduce with elm.
here is my code :
https://ellie-app.com/8sYLsxTZHk5a1
The problem is in the "calcTaskPosition" function where i try to set the row of the task.
calcTaskPosition : Int -> Task -> List(Task)
calcTaskPosition row task =
let
precs = List.concatMap (calcTaskPosition (row+1)) (taskPrecs task)
in
{ task | col = (Maybe.withDefault -1 <|
List.maximum <|
List.map (\t -> t.col) precs) + 1
--, row = row
}
:: precs
In my example, tasks lines are set by the initTask function.
I wish to get the same task order whithout having to set explicit line position in the initTask function.
The first clue is when you look at svg you will notice that your "task1" is actually rendered twice. This is easier to see if you uncomment the line --, row = row in the snippet you posted.
In elm (and other functional languages) your tasks will not be manipulated in-place, but instead your tasks will be copied when you mutate them. So it is not really useful to keep col and row values in the model (for now).
Also, working with task ids makes more sense than directly linking objects.
With this in mind, I would create two different task records: One for keeping it in the model (Task in my example) and one for rendering it (I called it DrawableTask).
And then you need a transformation function like
toDrawableListOfTasks : List Task -> List DrawableTask
that will be called in the view.
The transformation function essentially uses your tasksNotInTaskPrecs where you select all tasks that can be immediately drawn (because their precs list is empty). I generalized it and called it allDependenciesMet instead and use it on every iteration to select the tasks that can be drawn.
All tasks that can be drawn will be added to a temporary list (in my case a dictionary for fast look-up of already entered tasks) and then the next iteration starts with all tasks that were not yet drawn.
When no tasks are left, you can return the list and the rendering pass will traverse the list once again.
order : Temp -> List Task -> List DrawableTask
order temp todo =
case List.partition (allDependenciesMet temp) todo of
( [], [] ) ->
-- We are done and can return the list
Dict.values temp
|> List.sortBy .row
( [], _ ) ->
Debug.todo "An invalid list of tasks was passed"
( drawableTasks, nextTodo ) ->
let
nextTemp =
List.indexedMap (toDrawable temp) drawableTasks
|> List.map (\t -> ( t.id, t ))
|> Dict.fromList
|> Dict.union temp
in
order nextTemp nextTodo
I'm not sure if this is understandable, but you should be able to follow https://ellie-app.com/8tdzrgLfBfya1

Kotlin - very frequent data removal and addition to a list causes npe

I've a buffer that is actually ArrayList<Object>.
Happens async:
This buffer list changes very frequently - I mean 15-50 times in single second and the idea is that whenever there's an update, I remove first element by position buffer.removeAt(0) and add new value in the end by buffer.add(new).
At some point I call a function that goes and do calculation with buffer list. What I do is I go through the list - element by element. At some point I run into NPE as the the element has been removed async.
How to solve this NPE? I was thinking of making deep copy, but making deep copy would mean to go through the buffer list and do some data allocation, which basically means that while I do deep copy I can still run into NPE.
How problems like these are solved?
How to solve NPE?
What would be more optimized way as this is gonna consume a lot of memory?
Code:
private fun observeFrequentData() {
frequentData.observe(owner, Observer { data ->
if (accelerationData == null) return#Observer
GlobalScope.launch {
val a = data[0].toDouble()
val b = data[1].toDouble()
val c = a + b
val timestamp = System.currentTimeMillis()
val customObj = CustomObj(c, timestamp)
if (buffer.size >= 5000) {
buffer.removeAt(0)
}
buffer.add(acceleration)
}
})
}
fun getBuffer() {
val mappedData = buffer.map { it.smth } // NPE, it == null
}
If you are doing lots of removing from 0, and insert at the end. Then ArrayList is probably not the container to use.
you can consider using a LinkedList .
buffer.removeFirst();
and
buffer.add(acceleration);
also note the following comments regarding synchronization.
Note that this implementation is not synchronized. If multiple threads
access a linked list concurrently, and at least one of the threads
modifies the list structurally, it must be synchronized externally. (A
structural modification is any operation that adds or deletes one or
more elements; merely setting the value of an element is not a
structural modification.) This is typically accomplished by
synchronizing on some object that naturally encapsulates the list. If
no such object exists, the list should be "wrapped" using the
Collections.synchronizedList method. This is best done at creation
time, to prevent accidental unsynchronized access to the list:
List list = Collections.synchronizedList(new LinkedList(...));
Using the synchronized keyword on your piece of code as #patrickf suggested.
To take care of performance, instead of making the method call itself synchronized, you can just write the 3 "buffer" related lines of code (size, removeAt and add) in a synchronized block.
Something like;
.
.
.
synchronized {
if (buffer.size >= 5000) {
buffer.removeAt(0)
}
buffer.add(acceleration)
}
}
})
Hope this helps!

Trying to understand how two same method call placed one after the other in recursive method

Below is an example of quicksort. I was wondering how two recursive method call inside quicksort method works i.e in what sequence it'll execute? So to check in what sequence I placed syso after each method (check output).My doubt why this sequence?Thus it depends on any conditions? if so, what condition? It would be helpful if explained the logic in detail.
Thank you in advance :)
void quicksort(int a[], int p, int r)
{
if(p < r)
{
int q;
q = partition(a, p, r);
System.out.println("q:"+q);
quicksort(a, p, q);
System.out.println("1");
quicksort(a, q+1, r);
System.out.println("2");
}
}
int partition(int a[], int p, int r)
{
System.out.println("p:"+p+" r:"+r);
int i, j, pivot, temp;
pivot = a[p];
i = p;
j = r;
while(1)
{
while(a[i] < pivot && a[i] != pivot)
i++;
while(a[j] > pivot && a[j] != pivot)
j--;
if(i < j)
{
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
else
{
return j;
}
}
}
Output
p:0 r:7
q:4
p:0 r:4
q:0
1
p:1 r:4
q:1
1
p:2 r:4
q:3
p:2 r:3
q:2
1
2
1
2
2
2
1
p:5 r:7
q:7
p:5 r:7
q:6
p:5 r:6
q:5
1
2
1
2
1
2
2
Would like to know why the gap between method calls?i.e how println(placed after method calls) statement getting executed w/o executing method call?
Yes, it depends on conditions: specifically, the values of p and r on each call. Each instance of the sort will do the two calls in order: none of the execution branches will get to the second call until the first call of that branch is completely done.
You will get a much nicer trace if you put a println at the top of the function that displays the parameter values. You might want to place one after you compute the value of q, as well. Try that, and see whether it tells you the rest of the story.
Okay, you've done the printing ... and you don't see the reason for that gap? When you get to the output line "q:2", you've made five calls to quicksort, and the only progress through that sequence is that you've made it past the "1" print for two of them (you're in the second call). Your current stack looks like this, in terms of p and r:
2, 3
2, 4
0, 4
0, 7
This is the right half of the left half (second quarter) of the array, four levels deep. You now have to finish off those calls, which will get you to the "1" print for the "right-half" ones, the "2" print for each of them.
Looking at it another way, you work to partition the array down to single elements. While you're doing this, you stack up calls for smaller partitions. Any call with at least two elements has to finish off both of its partitions before it returns to the next print.
Once you get to a single-element array, you return right away, and get to print the next "1" or "2". If the other partition is also fully atomized, then you get to the next "1" or "2" without any more partitioning calls.
Halfway through, you get to the point where you've fully atomized the left half of the array; that's when you clear out all the outstanding processing, back up the stack, and do all of that printing. Then you recur down the right half, and get a similar effect.
I think you might have an easier time understanding if you'd give yourself a full trace. Either follow this in your debugger, or modify and add print statements so that (1) you have a unique, easily-read output for every line, rather than 8 lines each of "1" and "2" that you can't tell apart; (2) you can also trace the return from each routine. The objective here is to be able to recognize where you are in the process at each output line.
Yes, it's another programming problem to be able to print out things such as
1.L.R.R
1.1.2
(0,4) L
...
... or whatever format you find readable.

Creating Sequence of Sequences is Causing a StackOverflowException

I'm trying to take a large file and split it into many smaller files. The location where each split occurs is based on a predicate returned from examining the contents of each given line (isNextObject function).
I have attempted to read in the large file via the File.ReadLines function so that I can iterate through the file one line at a time without having to hold the entire file in memory. My approach was to group the sequence into a sequence of smaller sub-sequences (one per file to be written out).
I found a useful function that Tomas Petricek created on fssnip called groupWhen. This function worked great for my initial testing on a small subset of the file, but a StackoverflowException is thrown when using the real file. I am not sure how to adjust the groupWhen function to prevent this (I'm still an F# greenie).
Here is a simplified version of the code showing only the relevant parts that will recreate the StackoverflowExcpetion::
// This is the function created by Tomas Petricek where the StackoverflowExcpetion is occuring
module Seq =
/// Iterates over elements of the input sequence and groups adjacent elements.
/// A new group is started when the specified predicate holds about the element
/// of the sequence (and at the beginning of the iteration).
///
/// For example:
/// Seq.groupWhen isOdd [3;3;2;4;1;2] = seq [[3]; [3; 2; 4]; [1; 2]]
let groupWhen f (input:seq<_>) = seq {
use en = input.GetEnumerator()
let running = ref true
// Generate a group starting with the current element. Stops generating
// when it founds element such that 'f en.Current' is 'true'
let rec group() =
[ yield en.Current
if en.MoveNext() then
if not (f en.Current) then yield! group() // *** Exception occurs here ***
else running := false ]
if en.MoveNext() then
// While there are still elements, start a new group
while running.Value do
yield group() |> Seq.ofList }
This is the gist of the code making use Tomas' function:
module Extractor =
open System
open System.IO
open Microsoft.FSharp.Reflection
// ... elided a few functions include "isNextObject" which is
// a string -> bool (examines the line and returns true
// if the string meets the criteria to that we are at the
// start of the next inner file)
let writeFile outputDir file =
// ... write out "file" to the file system
// NOTE: file is a seq<string>
let writeFiles outputDir (files : seq<seq<_>>) =
files
|> Seq.iter (fun file -> writeFile outputDir file)
And here is the relevant code in the console application that makes use of the functions:
let lines = inputFile |> File.ReadLines
writeFiles outputDir (lines |> Seq.groupWhen isNextObject)
Any ideas on the proper way to stop groupWhen from blowing the stack? I'm not sure how I would convert the function to use an accumulator (or to use a continuation instead, which I think is the correct terminology).
The problem with this is that the group() function returns a list, which is an eagerly evaluated data structure, which means that every time you call group() it has to run to the end, collect all results in a list, and return the list. This means that the recursive call happens within that same evaluation - i.e. truly recursively, - thus creating stack pressure.
To mitigate this problem, you could just replace the list with a lazy sequence:
let rec group() = seq {
yield en.Current
if en.MoveNext() then
if not (f en.Current) then yield! group()
else running := false }
However, I would consider less drastic approaches. This example is a good illustration of why you should avoid doing recursion yourself and resort to ready-made folds instead.
For example, judging by your description, it seems that Seq.windowed may work for you.
It's easy to overuse sequences in F#, IMO. You can accidentally get stack overflows, plus they are slow.
So (not actually answering your question),
personally I would just fold over the seq of lines using something like this:
let isNextObject line =
line = "---"
type State = {
fileIndex : int
filename: string
writer: System.IO.TextWriter
}
let makeFilename index =
sprintf "File%i" index
let closeFile (state:State) =
//state.writer.Close() // would use this in real code
state.writer.WriteLine("=== Closing {0} ===",state.filename)
let createFile index =
let newFilename = makeFilename index
let newWriter = System.Console.Out // dummy
newWriter.WriteLine("=== Creating {0} ===",newFilename)
// create new state with new writer
{fileIndex=index + 1; writer = newWriter; filename=newFilename }
let writeLine (state:State) line =
if isNextObject line then
/// finish old file here
closeFile state
/// create new file here and return updated state
createFile state.fileIndex
else
//write the line to the current file
state.writer.WriteLine(line)
// return the unchanged state
state
let processLines (lines: string seq) =
//setup
let initialState = createFile 1
// process the file
let finalState = lines |> Seq.fold writeLine initialState
// tidy up
closeFile finalState
(Obviously a real version would use files rather than the console)
Yes, it is crude, but it is easy to reason about, with
no unpleasant surprises.
Here's a test:
processLines [
"a"; "b"
"---";"c"; "d"
"---";"e"; "f"
]
And here's what the output looks like:
=== Creating File1 ===
a
b
=== Closing File1 ===
=== Creating File2 ===
c
d
=== Closing File2 ===
=== Creating File3 ===
e
f
=== Closing File3 ===

How does recursion work its way back?

I'm working to understand recursion more in depth and I'm struggling with WHY it works the way it does. I know that this function returns the square of the previous return (2, 4, 16, 256, etc.), but I'm wonder how it gets the answer.
My understanding of recursion is that it iterates back down to the base case, but that leads me to believe that it would eventually always return the base case. How does it work its way back up to returning something new every time?
int p1a(int num) {
if (num == 1) { return 2; }
else {
return pow(p1a(num-1), 2);
}
}
Here's an example of my thinking
num = 3
passes through the base case and hits pow(p1a(num-1), 2)
moves back to the start
again passes through the base case and hits pow(p1a(num-1), 2)
at this point, num = 1, so it would return 2
How is it working its way back up to return 16? I understand what the function returns, but I'm stuck on the process of getting there.
You're thinking about the steps linearly, while the execution is actually nested (represented by indenting):
call p1a(3)
call p1a(2)
call p1a(1)
return 2
return pow(2, 2)
return pow(4, 2)
So the final return returns the value 16.

Resources