找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1902

积分

0

好友

252

主题
发表于 2 小时前 | 查看: 4| 回复: 0

OpenClaw 最近实在太火了。

它究竟有多火?不仅体现在仅用不到三个月时间,就在 GitHub 上力压 React,成为软件类项目 Star 历史第一(要知道,React 的这个地位是靠长达13年的积累才获得的)。更直观的体现是,上周腾讯宣布提供现场安装 OpenClaw 服务时,那堪称“疯狂”的场面。

OpenClaw安装活动现场人群聚集图

现场聚集了数千人,涵盖各行各业和各个年龄段。这还是个工作日!更离谱的是,腾讯事前并没有做太多预热宣传。即便派出了大量工程师协助,依然供不应求,连马化腾都在朋友圈感叹“没想到这么火”。

马化腾对OpenClaw火爆表示惊讶的朋友圈截图

活动当天,有些声音质疑腾讯,认为所谓的安装服务只是个幌子,最终目的是推销自家的云服务器。但我相信,真正去过现场、了解规则的人不会有这种想法。

首先,不止腾讯,阿里、字节都在其云服务官网提供了“一键安装 OpenClaw”的服务。目的当然是降低使用门槛,但过程中消耗的计算资源(Token)自然会绑定在自家的云服务上。这属于典型的“醉翁之意不在酒”,是商业上的捆绑销售。不过,这种行为属于纯商业选择,没有强迫使用,也不好做过多的评价。

而腾讯那天的活动,是支持协助大家进行本地安装的,并没有强制要求必须购买腾讯云服务。单就这一点而言,其实没什么可指责的。

反观某些没有自家云产品的大厂,为了接住 OpenClaw 这波“泼天的流量”,居然真的官方推出了收费安装服务,而且价格不菲。

某平台OpenClaw远程部署服务收费截图

就在腾讯活动的第二天,某平台联合服务商上线了 OpenClaw 远程部署服务:不含聊天应用配置的安装服务要价 395 元,包含聊天应用的则要 695 元。怎么说呢,你可以理解为这是在为“有使用需求且不差钱的用户”提供一种省事的渠道。但在我看来,这多少有点“啥钱都想挣”的意思。如果真心想帮用户解决问题,定价不会如此“高端”。

那么,你怎么看?你会为了用上 OpenClaw,花几百块钱请人上门或远程安装吗?欢迎大家在 云栈社区 交流看法。

聊完了行业见闻,按照惯例,来一道和“范围”、“边界”相关的算法题放松一下。这道题关于如何用最短的绳子围起所有的树,本质上是一个求解 二维凸包 的经典问题,非常考验对 计算机科学基础 中几何与算法的理解。

题目描述

平台:LeetCode
题号:587

在一个二维的花园中,有一些用 (x, y) 坐标表示的树。由于安装费用十分昂贵,你的任务是先用最短的绳子围起所有的树。只有当所有的树都被绳子包围时,花园才能围好栅栏。

你需要找到正好位于栅栏边界上的树的坐标。

示例 1:

示例1的树坐标分布与凸包示意图

输入: [[1,1],[2,2],[2,0],[2,4],[3,3],[4,2]]
输出: [[1,1],[2,0],[4,2],[3,3],[2,4]]

示例 2:

示例2的树坐标分布与凸包示意图

输入: [[1,2],[2,2],[4,2]]
输出: [[1,2],[2,2],[4,2]]
解释: 即使树都在一条直线上,你也需要先用绳子包围它们。

注意:

  1. 所有的树应当被围在一起。你不能剪断绳子来包围树或者把树分成一组以上。
  2. 输入的整数在 0100 之间。
  3. 花园至少有一棵树。
  4. 所有树的坐标都是不同的。
  5. 输入的点没有顺序。输出顺序也没有要求。

二维凸包(Andrew 算法)

这是一道「二维凸包」的板子题。我们将使用 Andrew 算法 来求解凸包上的所有点(即围成所有点的最小周长边界)。这个算法逻辑清晰,将凸包分为「上凸壳」和「下凸壳」两部分来处理。

Andrew算法将凸包分为上下两部分示意图

算法基本流程如下:

  1. 排序:对所有点进行双关键字排序,首先按 x 坐标升序排序,若 x 相同则按 y 坐标升序。按 x 排序是为了能确定一个扫描方向(例如从左到右),而按 y 排序则保证了在处理某些特殊情况时的正确性。
  2. 维护栈:使用一个栈(这里用数组模拟)来维护当前被认为是凸包边界的点(更准确地说,是维护构成边界的边)。栈中相邻的两个点代表凸包的一条边。
  3. 分别构建凸壳
    • 构建下凸壳:从左到右遍历排序后的点。对于每个新点 c,检查栈顶的两个点 abb 为栈顶)构成的向量 $\vec{ab}$ 与向量 $\vec{ac}$ 的关系。如果 $\vec{ac}$$\vec{ab}$顺时针方向(即叉积小于等于0),说明 b 点可能是凹陷的,需要弹出栈顶 b 点。重复此过程直到栈内元素少于2个或不再需要弹出,然后将当前点 c 入栈。
    • 构建上凸壳:从右到左遍历排序后的点,逻辑与构建下凸壳完全对称。需要注意的是,下凸壳已经构建好的点不能再次使用(可以用一个布尔数组标记),并且检查栈顶元素的条件从“栈内元素不少于2个”变为“栈内元素大于下凸壳的结束位置”。

具体判断向量方向时,我们可以利用向量叉积的几何意义。下图展示了判断的逻辑:

判断栈顶边是否需要删除的几何示意图

代码实现
我们使用数组 stk 模拟栈,tp 表示栈顶指针。注意,起点会被入栈两次(分别作为下凸壳的起点和上凸壳的终点),因此最终输出结果时,栈底和栈顶是同一个点,我们通常只取其中一个。

class Solution {
    // 向量相减
    int[] subtraction(int[] a, int[] b) {
        return new int[]{a[0] - b[0], a[1] - b[1]};
    }
    // 叉乘
    double cross(int[] a, int[] b) {
        return a[0] * b[1] - a[1] * b[0];
    }
    // 计算向量ab转向向量ac过程中扫过的面积(叉积),用于判断方向
    double getArea(int[] a, int[] b, int[] c) {
        return cross(subtraction(b, a), subtraction(c, a));
    }

    public int[][] outerTrees(int[][] trees) {
        // 1. 双关键字排序
        Arrays.sort(trees, (a, b)->{
            return a[0] != b[0] ? a[0] - b[0] : a[1] - b[1];
        });
        int n = trees.length, tp = 0;
        int[] stk = new int[n + 10];
        boolean[] vis = new boolean[n + 10];
        // 2. 构建下凸壳
        stk[++tp] = 0; // 起点入栈,先不标记
        for (int i = 1; i < n; i++) {
            int[] c = trees[i];
            while (tp >= 2) {
                int[] a = trees[stk[tp - 1]], b = trees[stk[tp]];
                if (getArea(a, b, c) > 0) vis[stk[tp--]] = false; // ac在ab的逆时针方向,删除b点
                else break;
            }
            stk[++tp] = i;
            vis[i] = true;
        }
        // 3. 构建上凸壳
        int size = tp; // 下凸壳的节点数
        for (int i = n - 1; i >= 0; i--) {
            if (vis[i]) continue; // 下凸壳的点不再考虑
            int[] c = trees[i];
            while (tp > size) { // 注意这里是 > size
                int[] a = trees[stk[tp - 1]], b = trees[stk[tp]];
                if (getArea(a, b, c) > 0) tp--; // 同理,逆时针则弹出
                else break;
            }
            stk[++tp] = i;
            // vis[i] = true; // 这里标记与否不影响结果
        }
        // 4. 构造结果,栈中下标从1到tp-1为凸包点(tp和0是同一个起点)
        int[][] ans = new int[tp - 1][2];
        for (int i = 1; i < tp; i++) ans[i - 1] = trees[stk[i]];
        return ans;
    }
}
  • 时间复杂度:排序复杂度为 $O(n \log n)$,构建凸壳的两遍扫描复杂度为 $O(n)$。整体复杂度为 $O(n \log n)$
  • 空间复杂度$O(n)$,用于栈和标记数组。

最后

无论是分析 OpenClaw 引发的行业现象,还是钻研一道经典的 算法题,背后都需要清晰的逻辑和扎实的功底。技术圈的动态总是精彩纷呈,而底层的 算法与数据结构 知识则是我们理解和创造这一切的基石。希望今天的分享,既能带给你一些行业思考,也能在算法学习上对你有所帮助。




上一篇:机器人产业观察:从春晚到两会,端侧大脑如何推动规模化落地与本地部署方案
下一篇:嵌入式C/C++中如何利用宏与内联函数实现函数调用性能优化
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-3-11 04:02 , Processed in 0.518735 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表