• 一道面试题引发的思考


    概述

    最近复习算法,正好想到了之前的一道面试题,由此引发了许多思考。在此记录一下,供以后开发时参考,希望对其他人也有用。

    一道面试题

    面试题如下:

    // 要求实现一个 flatten 函数,有如下效果:
    // [1,2,[3,4,[5,6,7],8],9]  =>  [1,2,3,4,5,6,7,8,9]
    // todo
    

    一般的解法是使用递归:

    function flatten(arr) {
        return arr.reduce((accu, curr) => Array.isArray(curr) ? accu.push(...flatten(curr)) : accu.push(curr));
    }
    

    当然还有比较简便的方法:

    function flatten(arr) {
        return arr.toString().split(',').map(item => parseInt(item));
    }
    

    DFS

    DFS 的全称是 Deep First Search,也叫深度优先遍历,它是先一遍遍,从上到下,从左到右,先遍历到叶子节点,然后进行回溯遍历其它节点的遍历方法。其模板形式为:

    // 递归版
    function dfs(node, visited) {
        visited.add(node);
    
        // process corrent node here
        // ...
    
        node.children.forEach((child) => {
            if (!visited.has(child)) {
                dfs(child, visited);
            }
        });
    }
    
    // 遍历版
    function dfs(tree) {
        const visited = new Set();
        cosnt stack = [tree.root];
    
        while (stack.length) {
            const node = stack.shift();
    
            if (!visited.has(node)) {
                visited.add(node);
    
                // process corrent node here
                // ...
    
                stack.unshift(...node.children);
            }
        }
    }
    

    注意:

    1. 递归版在递归函数里面储存了状态,而遍历版使用了一个栈来储存状态。
    2. visited 是一个集合,用来检查是否已经访问过了,一般情况下我们用不到这个。

    面试题的遍历写法

    其实仔细一想,上面的面试题不就是深度优先遍历吗?而上面递归写法可以转化成遍历写法,那么我们面试题的递归写法能不能转化为递归写法呢?答案是能的,直接套用模板即可,代码如下:

    function flatten(arr) {
        const stack = [arr];
        const result = [];
    
        while (stack.length > 0) {
            const node = stack.shift();
    
            if (Array.isArray(node)) {
                stack.unshift(...node);
            } else {
                result.push(node);
            }
        }
    
        return result;
    }
    

    其中的关键点是,我们 while 循环的判断条件是栈的长度

    BFS

    BFS 的全称是 Broad First Search,也叫广度优先遍历,它是指从上到下,从左到右,一层层进行遍历,遍历完一层后再遍历下一层。它没有递归版的模板,只有遍历版的模板,形式为:

    function BFS(tree) {
        const visited = new Set();
        const queue = [tree.root];
    
        while (queue.length) {
            const node = queue.shift();
    
            if (!visited.has(node)) {
                visited.add(node);
    
                // process corrent node here
                // ...
    
                queue.push(...node.children);
            }
        }
    }
    

    注意:

    1. 它是用一个队列来储存状态的。
    2. while 循环的判断条件是这个队列的长度

    总结

    1. 各种形式的遍历,直接调用模板之后就会发现很容易写了,这些模板最好记在脑子里
    2. 递归转遍历看起来可能很难,但是模板能帮到你。
  • 相关阅读:
    golang访问数据库
    dynamic与泛型
    新的published和$M+对比
    插入窗体到别的程序里
    淺談怎么样运用Delphi 2009地泛型容器類別
    Delphi随记
    查找文件
    Delphi操作xml
    Delphi图像编程学习笔记
    Ext.net中如何上传文件
  • 原文地址:https://www.cnblogs.com/yangzhou33/p/13829111.html
Copyright © 2020-2023  润新知