外包竟敢用vim,我一个正编都没敢用

文摘   2024-11-29 11:02   陕西  

前段时间看到一个网友发帖,说外包竟然敢用Vim,而他自己作为一个“正编”都不敢用Vim,结果我不禁笑了。😂

老实说,我能理解他为什么这么说。Vim对新手来说,的确难上手。它不像IDE那样直接给你所有的提示,很多时候你得靠自己去摸索,这容易让人掉进坑里。

作为一个老程序员,一开始我自己也用得不太顺手,光是记快捷键就能让我焦头烂额。有时候输入法没切好,敲几下就发现自己居然是删除了半篇代码(哭)。😅

不过,慢慢地,我也领悟了Vim的魅力。看似不那么友好,操作复杂,但一旦你掌握了,就能体验到它的速度和高效。

那外包为什么敢用vim呢?有没有可能他就是一个老程序员了,哈哈~

算法题:最小高度树

给大家带来一道挺有意思的算法题:最小高度树。这道题听起来可能有点复杂,但其实掌握了其中的思路,你会发现它非常简单,顺便还能加深对图和树的理解。大家准备好了吗?来吧,我们一块儿把它搞定!

首先,题目的核心要求是:给定一个无向图,你需要找到一个最小高度的树。这里的树其实就是一个根节点,之后所有其他节点都要通过边连接到它,且树的高度尽可能小。树的高度是指从根节点到最远叶节点的距离。

我来解释一下,这个问题从字面上看可能会有些迷惑,但其实我们可以将其理解为:如何在一个图中找到一个“最优”根节点,让树的最大深度最小。也就是说,树的高度最小,也就是从根到最远叶子的距离最短。

说到这,很多人会想:这是不是又是某种平衡二叉树的问题?其实不是。最小高度树和平衡二叉树是不同的,我们要做的不是保证左右子树的高度平衡,而是通过一些算法找到一个合适的根节点,让整个树的高度最小。

那么,怎么做呢?答案其实很简单——通过“剥洋葱”的方式逐步逼近最优解。你可以理解为从树的外围逐渐去除一层,直到剩下中心节点。简而言之,我们要从所有的节点开始,逐步剔除离根最远的节点,直到只剩下最优的中心节点。

具体来说,首先你可以想象每个节点的度数(即有多少条边连接到它)。当一个节点的度数只有1时,它就像一个叶子一样,可以剔除掉。然后,我们继续剔除其他度数为1的节点,直到只剩下中心节点为止。这个过程类似于从外围向中心收缩,最终找到的中心节点就是我们要求的最小高度树的根节点。

再回到算法的实现,我们可以利用广度优先搜索(BFS)来实现这个过程。BFS很适合解决这种逐步剔除的操作。具体步骤如下:

  1. 计算每个节点的度数。
  2. 将所有度数为1的节点加入队列,作为“叶子节点”进行处理。
  3. 不断从队列中移除叶子节点,并更新相邻节点的度数。
  4. 如果某个相邻节点的度数变为1,就将其加入队列。
  5. 重复这个过程,直到队列中只剩下一个或两个节点,这些节点即为树的中心。

接下来,我给大家看一个Java实现:

import java.util.*;

public class MinimumHeightTree {

    public List<Integer> findMinHeightTrees(int n, int[][] edges) {
        // 如果只有一个节点,直接返回
        if (n == 1) {
            return Collections.singletonList(0);
        }

        // 建立图的邻接表
        List<Set<Integer>> graph = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            graph.add(new HashSet<>());
        }

        for (int[] edge : edges) {
            graph.get(edge[0]).add(edge[1]);
            graph.get(edge[1]).add(edge[0]);
        }

        // 初始化队列,存放叶子节点
        Queue<Integer> queue = new LinkedList<>();
        // 计算每个节点的度数
        int[] degrees = new int[n];
        for (int i = 0; i < n; i++) {
            degrees[i] = graph.get(i).size();
            if (degrees[i] == 1) {
                queue.offer(i);
            }
        }

        // 剥离叶子节点
        while (n > 2) {
            int size = queue.size();
            n -= size;
            for (int i = 0; i < size; i++) {
                int leaf = queue.poll();
                for (int neighbor : graph.get(leaf)) {
                    degrees[neighbor]--;
                    if (degrees[neighbor] == 1) {
                        queue.offer(neighbor);
                    }
                }
            }
        }

        // 剩下的节点就是最小高度树的根
        List<Integer> result = new ArrayList<>();
        while (!queue.isEmpty()) {
            result.add(queue.poll());
        }
        return result;
    }

    public static void main(String[] args) {
        MinimumHeightTree solution = new MinimumHeightTree();
        int[][] edges = {{1, 0}, {1, 2}, {1, 3}, {2, 4}, {2, 5}};
        List<Integer> roots = solution.findMinHeightTrees(6, edges);
        System.out.println(roots); // 输出 [1, 2]
    }
}

这段代码实现了最小高度树的算法。首先,我们构建了一个图的邻接表,并记录了每个节点的度数。然后,我们用一个队列存放叶子节点,逐步剔除它们,并更新它们的邻居节点。如果某个邻居的度数变为1,就加入队列。最终,队列中的节点就是树的中心节点。

看起来是不是不复杂?其实在复杂度上,整个算法的时间复杂度是O(n),因为我们每个节点最多被访问两次——一次是加入队列,另一次是剔除它。空间复杂度是O(n),因为我们要存储邻接表和度数信息。

这样,我们就找到了最小高度树的根节点。你要是问我这个问题有什么坑,我只能说:没有什么坑,唯一需要注意的就是图的遍历方法,BFS挺合适的。你不信?试试用DFS,可能会发现效果差不多,但你要处理每层节点时可能会有些麻烦。

好了,今天的算法题讲解就到这。

-END-


ok,今天先说到这,老规矩,给大家分享一份不错的副业资料,感兴趣的同学找我领取。

以上,就是今天的分享了,看完文章记得右下角给何老师点赞,也欢迎在评论区写下你的留言

程序员老鬼
10年+老程序员,专注于AI知识普及,已打造多门AI课程,本号主要分享国内AI工具、AI绘画提示词、Chat教程、AI换脸、Chat中文指令、Sora教程等,帮助读者解决AI工具使用疑难问题。
 最新文章