可怜百度人

可怜的百度股民

注意,这里说的是持有百度股票的股民,不是百度,百度没啥好可怜的。

前天(3月25日)中午,财联社爆料百度和 Apple 达成合作,百度将为苹果今年发布的 iPhone16、Mac 系统和 iOS18 提供 AI 功能。

这对百度来说属于利好,于是盘中一度高涨 6.5% 个点。

但可惜,虽然百度在 H 股上市,但本质还是中国公司,只要是中国公司,就逃脱不了「出利好 = 高开低走」的宿命。

于是当天百度的股价走势是这样的:

前一天收盘价 98.2,开盘 99.2,消息出来后,最高 104.9(涨幅约 6.5%),然后开始冲高回落,最终收盘 100.7(涨幅 2.55%)。

收盘价低于当日成交均价 101.1,这意味着那些因为利好消息冲进去的股民,当日收盘大概率是浮亏的。

PS. 记住这个当日成交均价,待会要考。

后续结果你猜怎么着?

昨天一位接近苹果的知情人士跳出来,否认了苹果已和百度达成 AI 合作的消息。

前面说的「出利好 = 高开低走」只是中国公司的传统艺能之一,另外一个传统艺能是「出利空 = 集体抢跑 = 低开低走」,于是今天的百度走势是:

午盘价为 99.3,盘中最低去到了 98.3,比消息出来前的午盘价还要低。

你可能会说,现在的 99.3 和消息当天开盘价的 99.2 看起来差的不多嘛,没消息股价也会波动的呀。

是的,但是股民的成本价可不是 99.2,大概率是要比前面说的日成交均价 101.1 要高,因为拉升是发生在午盘,消息当天交易量异动那段时间,均价其实接近 102。

即使我们用 101.1 去算,那么这批股民也 3 天亏了 2 个点。

我本身没有过任何交易百度股票以及相关衍生物的经历,我也几乎不抓这种热点投机。

但平心而论,你能说这批股民错信小作文吃亏,是单纯活该吗?

不太能,小道消息的投机是有反水风险,但每次都明牌的高开低走,简直就离谱。

尤其是百度在出利好小作文的前段时间,已经跌了一段时间了:

因此不存在内幕消息抢跑,爆料小作文后趁机出货的情况,所以当天的高开低走完全就是市场惯性。

这是市场投资者普遍没有耐心,只想镰刀相见,把投资玩成零和游戏的表现。

不难评,但不适合评。

如果这次你在百度小作文这里交了学费,以后不要交;如果这次没有交学费,看着这推文,以后要学会忍手。

...

回归主线。

继续来一道和「百度」社招相关算法原题。

题目描述

平台:LeetCode

题号:934

给你一个大小为 n x n 的二元矩阵 g,其中 1 表示陆地,0 表示水域。

岛是由四面相连的 1 形成的一个最大组,即不会与非组内的任何其他 1 相连,g 中恰好存在两座岛。

你可以将任意数量的 0 变为 1 ,以使两座岛连接起来,变成一座岛。

返回必须翻转的 0 的最小数目。

示例 1:

lua 复制代码
输入:g = [[0,1],[1,0]]

输出:1

示例 2:

lua 复制代码
输入:g = [[0,1,0],[0,0,0],[0,0,1]]

输出:2

示例 3:

css 复制代码
输入:g = [[1,1,1,1,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,0,1],[1,1,1,1,1]]

输出:1

提示:

  • <math xmlns="http://www.w3.org/1998/Math/MathML"> n = g . l e n g t h = g [ i ] . l e n g t h n = g.length = g[i].length </math>n=g.length=g[i].length
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> 2 < = n < = 100 2 <= n <= 100 </math>2<=n<=100
  • g[i][j]01
  • g 中恰有两个岛

并查集 + 双向 BFS

使用「并查集」将两个岛标记出来,然后将两个岛的点分别入队,再运用「双向 BFS」来找最短通路。

对于所有满足 <math xmlns="http://www.w3.org/1998/Math/MathML"> g [ i ] [ j ] = 1 g[i][j] = 1 </math>g[i][j]=1 的节点与其四联通的方向,值同为 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 1 </math>1 的节点进行并查集连通性维护。

随后建立两个队列 d1d2 分别存储两个岛的节点(以二元组 <math xmlns="http://www.w3.org/1998/Math/MathML"> ( x , y ) (x, y) </math>(x,y) 的方式出入队),并使用两个哈希表 m1m2 来记录从两岛屿出发到达该节点所消耗的步数(以节点的一维编号为 key,以消耗步数为 value)。

最后是使用「双向 BFS」来求解使两岛屿联通的最小通路:每次从队列中较少的进行拓展,只有尚未被处理过的节点(没有被当前哈希表所记录)才进行入队并更新消耗步数,当拓展节点在另外一个队列对应的哈希表表中出现过,说明找到了最短通路。

Java 代码:

Java 复制代码
class Solution {
    static int N = 10010;
    static int[] p = new int[N];
    static int[][] dirs = new int[][]{{1,0},{-1,0},{0,1},{0,-1}};
    int n;
    int getIdx(int x, int y) {
        return x * n + y;
    }
    int find(int x) {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }
    void union(int x, int y) {
        p[find(x)] = p[find(y)];
    }
    public int shortestBridge(int[][] g) {
        n = g.length;
        for (int i = 0; i <= n * n; i++) p[i] = i;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (g[i][j] == 0) continue;
                for (int[] di : dirs) {
                    int x = i + di[0], y = j + di[1];
                    if (x < 0 || x >= n || y < 0 || y >= n) continue;
                    if (g[x][y] == 0) continue;
                    union(getIdx(i, j), getIdx(x, y));
                }
            }
        }
        int a = -1, b = -1;
        Deque<int[]> d1 = new ArrayDeque<>(), d2 = new ArrayDeque<>();
        Map<Integer, Integer> m1 = new HashMap<>(), m2 = new HashMap<>();
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (g[i][j] == 0) continue;
                int idx = getIdx(i, j), root = find(idx);
                if (a == -1) a = root;    
                else if (a != root && b == -1) b = root;
                if (root == a) {
                    d1.addLast(new int[]{i, j});
                    m1.put(idx, 0);
                } else if (root == b) {
                    d2.addLast(new int[]{i, j});
                    m2.put(idx, 0);
                }
            }
        }
        while (!d1.isEmpty() && !d2.isEmpty()) {
            int t = -1;
            if (d1.size() < d2.size()) t = update(d1, m1, m2);
            else t = update(d2, m2, m1);
            if (t != -1) return t - 1;
        }
        return -1; // never
    }
    int update(Deque<int[]> d, Map<Integer, Integer> m1, Map<Integer, Integer> m2) {
        int sz = d.size();
        while (sz-- > 0) {
            int[] info = d.pollFirst();
            int x = info[0], y = info[1], idx = getIdx(x, y), step = m1.get(idx);
            for (int[] di : dirs) {
                int nx = x + di[0], ny = y + di[1], nidx = getIdx(nx, ny);
                if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
                if (m1.containsKey(nidx)) continue;
                if (m2.containsKey(nidx)) return step + 1 + m2.get(nidx);
                d.addLast(new int[]{nx, ny});
                m1.put(nidx, step + 1);
            }
        }
        return -1;
    }
}

Python 代码:

Python 复制代码
import queue

class Solution:
    def shortestBridge(self, g: List[List[int]]) -> int:
        def getIdx(x, y):
            return x * n + y

        def find(x):
            if p[x] != x:
                p[x] = find(p[x])
            return p[x]

        def union(x, y):
            p[find(x)] = p[find(y)]

        def update(d, cur, other):
            sz = d.qsize()
            while sz != 0:
                x, y = d.get()
                idx, step = getIdx(x, y), cur.get(getIdx(x, y))
                for di in dirs:
                    nx, ny = x + di[0], y + di[1]
                    nidx = getIdx(nx, ny)
                    if nx < 0 or nx >= n or ny < 0 or ny >= n:
                        continue
                    if nidx in cur:
                        continue
                    if nidx in other:
                        return step + 1 + other.get(nidx)
                    d.put([nx, ny])
                    cur[nidx] = step + 1
                sz -= 1
            return -1

        n = len(g)
        p = [i for i in range(n * n + 10)]
        dirs = [[1, 0], [-1, 0], [0, 1], [0, -1]]
        for i in range(n):
            for j in range(n):
                if g[i][j] == 0:
                    continue
                for di in dirs:
                    x, y = i + di[0], j + di[1]
                    if x < 0 or x >= n or y < 0 or y >= n:
                        continue
                    if g[x][y] == 0:
                        continue
                    union(getIdx(i, j), getIdx(x, y))
        a, b = -1, -1
        d1, d2 = queue.Queue(), queue.Queue()
        m1, m2 = {}, {}
        for i in range(n):
            for j in range(n):
                if g[i][j] == 0:
                    continue
                idx, root = getIdx(i, j), find(getIdx(i, j))
                if a == -1:
                    a = root
                elif a != root and b == -1:
                    b = root
                if a == root:
                    d1.put([i, j])
                    m1[idx] = 0
                elif b == root:
                    d2.put([i, j])
                    m2[idx] = 0
        while not d1.empty() and not d2.empty():
            t = -1
            if d1.qsize() < d2.qsize():
                t = update(d1, m1, m2)
            else:
                t = update(d2, m2, m1)
            if t != -1:
                return t - 1
        return -1

TypeScript 代码:

TypeScript 复制代码
let n: number
const p = new Array<number>(10010).fill(0)
const dirs = [[0,1],[0,-1],[1,0],[-1,0]]
function shortestBridge(g: number[][]): number {
    function getIdx(x: number, y: number): number {
        return x * n + y
    }
    function find(x: number): number {
        if (p[x] != x) p[x] = find(p[x])
        return p[x]
    }
    function union(x: number, y: number): void {
        p[find(x)] = p[find(y)]
    }
    function update(d: Array<Array<number>>, m1: Map<number, number>, m2: Map<number, number>): number {
        let sz = d.length
        while (sz-- > 0) {
            const info = d.shift()
            const x = info[0], y = info[1], idx = getIdx(x, y), step = m1.get(idx)
            for (const di of dirs) {
                const nx = x + di[0], ny = y + di[1], nidx = getIdx(nx, ny)
                if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue
                if (m1.has(nidx)) continue
                if (m2.has(nidx)) return step + 1 + m2.get(nidx)
                d.push([nx, ny])
                m1.set(nidx, step + 1)
            }
        }
        return -1
    }
    n = g.length
    for (let i = 0; i < n * n; i++) p[i] = i
    for (let i = 0; i < n; i++) {
        for (let j = 0; j < n; j++) {
            if (g[i][j] == 0) continue
            for (const di of dirs) {
                const x = i + di[0], y = j + di[1]
                if (x < 0 || x >= n || y < 0 || y >= n) continue
                if (g[x][y] == 0) continue
                union(getIdx(i, j), getIdx(x, y))
            }
        }
    }
    let a = -1, b = -1
    const d1 = new Array<number[]>(), d2 = new Array<number[]>()
    const m1 = new Map<number, number>(), m2 = new Map<number, number>()
    for (let i = 0; i < n; i++) {
        for (let j = 0; j < n; j++) {
            if (g[i][j] == 0) continue
            const idx = getIdx(i, j), root = find(idx)
            if (a == -1) a = root
            else if (a != root && b == -1) b = root
            if (a == root) {
                d1.push([i, j])
                m1.set(idx, 0)
            } else if (b == root) {
                d2.push([i, j])
                m2.set(idx, 0)
            }
        }
    }
    while (d1.length != 0 && d2.length != 0) {
        let t = -1
        if (d1.length < d2.length) t = update(d1, m1, m2)
        else t = update(d2, m2, m1)
        if (t != -1) return t - 1
    }
    return -1
}
  • 时间复杂度: <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n 2 ) O(n^2) </math>O(n2)
  • 空间复杂度: <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n 2 ) O(n^2) </math>O(n2)

最后

给大伙通知一下 📢 :

全网最低价 LeetCode 会员目前仍可用,快来薅羊毛!!!

📅 年度会员:有效期加赠两个月!! ; 季度会员:有效期加赠两周!!

🧧 年度会员:获 66.66 现金红包!! ; 季度会员:获 22.22 现金红包!!

🎁 年度会员:参与当月丰厚专属实物抽奖(中奖率 > 30%)!!

专属链接:leetcode.cn/premium/?pr...

更多详情请戳 这里

我是宫水三叶,每天都会分享算法知识,并和大家聊聊近期的所见所闻。

欢迎关注,明天见。

更多更全更热门的「笔试/面试」相关资料可访问排版精美的 合集新基地 🎉🎉

相关推荐
passerby60613 小时前
完成前端时间处理的另一块版图
前端·github·web components
KYGALYX3 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了3 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅3 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅4 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
爬山算法4 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
崔庆才丨静觅4 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment4 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅5 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊5 小时前
jwt介绍
前端