What is causing the duplication of leaves when using this DFS implementation?

I created an algorithm to compare if two trees have the same leaves.

https://i.sstatic.net/lpO2C.png

Both trees display matching leaf numbers in the exact order, resulting in a true outcome.

Below is the code that I formulated:

function leafSimilar(root1: TreeNode | null, root2: TreeNode | null): boolean {

    console.log(DFS(root1))

    const leavesRoot1 = DFS(root1);
    const leavesRoot2 = DFS(root2);

    for (let i = 0; i < Math.max(leavesRoot1.length, leavesRoot2.length); i += 1) {
        if (leavesRoot1[i] !== leavesRoot2[i]) {
            return false;
        }
    }

    return true;
};

function DFS(root, leaves = [] ) {

    if(!root) return leaves; 

    if (!root.left && !root.right) {
        leaves.push(root.val);
        return leaves;
    }

    // return DFS(root.left).concat(DFS(root.right)); // this is the correct answer

    return DFS(root.left, leaves).concat(DFS(root.right, leaves)); // why doesn't this work?
}

The final line of the code was my initial assumption, but it turned out to be incorrect.

I struggled to visualize it mentally, so I logged them as shown in the second-to-last line.

This log reveals:

[
  6, 7, 4, 
  6, 7, 4, 
  6, 7, 4, 
  6, 7, 4, 9, 8,
  6, 7, 4, 9, 8
] 

After spending two hours trying to decipher this issue, I still cannot comprehend why.

My expectation would be something like this:

[6, 
 6, 7, 
 6, 7, 4, 
 6, 7, 4, 9,
 6, 7, 4, 9, 8,
]

or simply

[6,7,4,9,8]

which represents the accurate result.

Can anyone provide insights into why this discrepancy exists?

The DFS function accepts the leaves array argument from the previous call.

Therefore, it is anticipated to receive leaves from the preceding node, not the following one, preventing any repetitive pattern in the leaves array since it starts empty.

As per the code I crafted, the DFS operates in preorder manner where the left-most nodes are assessed first.

I am seeking clarification on this matter. Thank you.

Answer №1

If you were to approach it in this manner, your solution would work:

    DFS(root.left, leaves);
    DFS(root.right, leaves);
    return leaves;

The key here is to understand that each recursive call of DFS returns a reference to the same array, so when concatenating the results of both calls, you end up duplicating values unintentionally.

To avoid such issues, it is recommended to follow one of these two patterns:

  • Pass the object (array) as an argument to the function and have it mutate the original object without returning anything. This way, the caller is aware of the mutation.

  • Have the function construct a new object from scratch and return it to the caller. This ensures that each call generates a distinct object reference.

In the given algorithm, the preference is for the second pattern, which eliminates the need for the values argument:

function DFS(root) {
    if (!root) return []; 
    if (!root.left && !root.right) return [root.val];
    return DFS(root.left).concat(DFS(root.right));
}

An alternative approach is to use a generator function for a more efficient solution:

function leafSimilar(root1, root2) {
    const leavesRoot1 = [...DFS(root1)]; // consume the iterator
    const leavesRoot2 = [...DFS(root2)];

    for (let i = 0; i < Math.max(leavesRoot1.length, leavesRoot2.length); i += 1) {
        if (leavesRoot1[i] !== leavesRoot2[i]) {
            return false;
        }
    }
    return true;
};

function* DFS(root) {
    if (!root) return; 
    if (!root.left && !root.right) yield root.val;
    yield* DFS(root.left);
    yield* DFS(root.right);
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Managing State Changes with Redux

Reducers in Redux are primarily designed to be pure functions that take the previous state and an action as arguments, and return a new state object without mutating the previous state. However, it is still possible for developers to directly mutate the st ...

What could be causing the issue with the variable appearing as undefined in

My class has a property: public requestLoadPersonal: Personal[] = []; As well as a method: private filterByGender(selectedValue: any): void { console.log(this.requestLoadPersonal); this.requestLoadPersonal = this.requestLoadPersonal.filter( ...

Reorganize code in JavaScript and TypeScript files using VSCode

Is there a way to efficiently organize the code within a .js / .ts file using Vscode? Specifically, when working inside a Class, my goal is to have static variables at the top, followed by variables, then methods, and so on automatically. I did some resea ...

Is there a specific requirement for importing a React component into a particular file?

I am facing an issue with my component and two JavaScript files: index.js and App.js. When I import the component into index.js, it displays correctly on the screen. However, when I import it into App.js, nothing appears on the screen. Here is the code fr ...

Dynamically load modules within an AngularJS application

Is there a way to dynamically load module scripts? I have 2 JS files: module1.js (function() { var mod = angular.module('module1', []); .... })(); This is the second one: module2.js (function() { var mod = angular.module('m ...

Exploring (nested) data structures in JavaScript

I'm struggling to understand if my issue lies in how I am organizing my array or in how I am accessing it. The idea is simple: I want to have an array of car makes and models that I can access for display purposes. const carBrands = [ { Audi: { ...

TypeScript disregards interface method argument types

Unexpectedly, the code below compiles without any errors (using tsc 3.9.5): interface IDateHandler { handleDate: (Date) => void; } let dateHandler: IDateHandler = { handleDate: (d: Date) => {}, }; dateHandler.handleDate([1, 2, 3]); Even more s ...

It appears that Yarn is having trouble properly retrieving all the necessary files for a package

Recently, I encountered a strange issue in our project involving 3 microservices, all using the exceljs library. Two of the microservices successfully download all necessary files for this package through yarn. However, the third microservice is missing ...

Issue: Unable to assign value to 'googleUri' property of null. Resolving with Interface for two-way binding?

Can anyone help me figure out why I keep getting a 'set property of null' error while attempting 2way binding in my interface? Whenever I submit the form and trigger the onSave function, I encounter the error "Cannot set property 'googleUri ...

The leaflet.js library threw an error: LatLng object is not valid due to invalid coordinates (NaN, NaN)

Currently, I am working with a JSON file that contains coordinates in pairs. "_id" : ObjectId("59407457838b932e0677999e"), "type" : "MultiPoint", "name" : "points", "coordinates" : [ [ -73.958, 40.8003 ], ...

The functionality of the AngularJS UI-Router seems to be impaired following the minification of

Hey there, I just developed an app with Angular and implemented ui-router for routing. To reduce the file size, I minified the entire Angular app using gulp-uglify. However, after minifying the app, the child route (nested route) of ui-router is no longer ...

Utilizing JSON API data to populate Leaflet maps

I am currently working on fetching JSON data from an API call, extracting the latitude, longitude, and name variables to create a GeoJSON array, and then displaying it on a Leaflet map. Despite not encountering any errors in the console, the geojson appea ...

"Using TSOA with TypeScript to return an empty array in the response displayed in Postman

I have successfully implemented CRUD operations using TSOA in TypeScript. However, I am facing an issue where I receive an empty array when making HTTP requests, despite adding data to the 'Livraison' table in MongoDB. https://i.sstatic.net/7IWT ...

The Vue v-for directive encountered an unrecognized property during rendering

Trying to grasp the concept of v-for in Vue JS, especially since I am a newcomer to this framework. Since I am utilizing Django, custom delimiters are necessary. I have a script example that appends a list of objects to a data property: var app = new Vue( ...

How can I connect the Bootstrap-datepicker element with the ng-model in AngularJS?

Below is the html code for the date field : <div class='form-group'> <label>Check out</label> <input type='text' ng-model='checkOut' class='form-control' data-date-format="yyyy-mm-dd" plac ...

When redirecting to the same component, Vue.js hooks are not triggered

In my Vuejs project, I have two pages located at the same level with a common component. However, when I redirect from post/new to post/edit/:id, the beforeMount method is not being called. redirect() { this.$router.push({path: `home/post/edit/${this ...

How come the back button does not initiate client-side navigation in a Next.js application?

In my Next.js application utilizing GraphQL to fetch articles from a server, I encountered an issue with dynamic routing when reloading the page while on an article and attempting to navigate back. The usual scenario works as expected: Index -> [slu ...

Encountering a TypeError in Mongoose: Unable to access properties of undefined while trying to read 'find'

Encountering an issue with the error message, TypeError: Cannot read properties of undefined (reading 'find'), specifically pointing to this block of code: app.get('/Organizations', (req,res) => { Organizations.find({}).then((organiz ...

The code function appears to be malfunctioning within the Cordova platform

When working with Cordova, I encountered an issue where I needed to trigger a button event from a listener. In my app, I am loading a specific page . This page contains a button with the class name "btn", and I wanted to display an alert when that button i ...

Restrict the Angular ng-repeat directive to specific rows only

Suppose we have a JSON dataset listing all languages of books: $scope.data = [{ "title": "Alice in wonderland", "author": "Lewis Carroll", "lang": ["en"] }, { "title": "Journey to the West", "author": "Wu Cheng'en", "lang": [" ...