标签「go」下的文章

bjmayor发布于2025-11-07

最大化最小值 / 最小化最大值 - 算法套路总结

一、什么是"最大化最小值"问题?

在算法题中,经常会遇到这样的描述:

  • “让所有工人的最大工作量尽可能小”
  • “让所有城市的最小电量尽可能大”
  • “让木材切割后的最小长度尽可能大”
  • “让学生分配到的最大任务数尽可能小”

这类问题有个共同特点:求在某种约束条件下,某个极值指标的最优值

乍一看这类问题很难直接求解,但有一个巧妙的思路:把"求最优值"转换为"判断某个值是否可行"


二、核心思想:二分答案法

2.1 为什么要二分答案?

直接思路的困境:
假设要求"分配任务后,学生们的最大任务量的最小值",如果直接枚举所有可能的分配方案,复杂度会是指数级的,根本无法接受。

转换思路:
我们换个角度问问题:

  • 原问题:“最优答案是多少?”(不知道怎么求)
  • 新问题:“答案能否达到 X?”(相对容易判断)

如果能高效判断"答案是否能达到 X",那我们就可以用二分搜索在所有可能的答案中找到最优的那个!

2.2 为什么二分法有效?关键在于单调性

二分答案法之所以可行,是因为这类问题有一个关键性质:单调性

以"最大化最小值"为例:

  • 如果"让所有城市电量都达到 10"可以实现,那么"让所有城市电量都达到 9、8、7…"肯定也可以实现(要求更低了)
  • 如果"让所有城市电量都达到 10"无法实现,那么"让所有城市电量都达到 11、12、13…"肯定也无法实现(要求更高了)

这种单调性意味着:存在一个临界值 M,小于等于 M 的都可以实现,大于 M 的都无法实现

答案值:  0   1   2   3   4   5   6   7   8   9   10  11  12
是否可行: ✓   ✓   ✓   ✓   ✓   ✓   ✓   ✓   ✗   ✗   ✗   ✗   ✗
                                      ↑
                                   我们要找的最优答案

这正是二分搜索的应用场景!我们要找的就是那个"从可行到不可行"的临界点。


三、解题框架(四步走)

第一步:识别问题类型

看到以下关键词就要想到二分答案法:

  • “最大化最小值”
  • “最小化最大值”
  • “在…约束下,求…的最优值”
  • “让…尽可能大/小”

第二步:确定二分搜索范围

需要确定答案的可能范围 [left, right]

  • left(最小可能值):通常是理论最小值,比如 0,或者初始状态下已有的最小值
  • right(最大可能值):通常是理论最大值,比如所有资源之和,或者题目给定的上限

第三步:设计 check(mid) 函数

这是最关键的一步!

check(mid) 函数的作用:判断答案能否达到 mid

  • 返回 true:说明 mid 这个答案可以实现,真正的最优答案 ≥ mid
  • 返回 false:说明 mid 这个答案无法实现,真正的最优答案 < mid

设计 check 函数时,通常会用到贪心、滑动窗口、差分数组等技巧。

第四步:二分搜索主循环

def solve(): left, right = 确定搜索范围 while left < right: mid = (left + right + 1) // 2 # 对于"最大化最小值"问题 if check(mid): # mid 可行 left = mid # 尝试更大的值 else: # mid 不可行 right = mid - 1 # 尝试更小的值 return left # 最终 left == right,就是答案

注意:

  • "最大化最小值"问题:mid = (left + right + 1) // 2,可行时 left = mid
  • "最小化最大值"问题:mid = (left + right) // 2,可行时 right = mid

阅读全文»

bjmayor发布于2025-10-26

开源第一天-starup

今天开始做开源项目。
一方面因为自己做的事情我感觉没啥挑战,锻炼下技术能力,基于场景深挖下。
另一方面是近些年的项目经历实在过于单薄,感觉拿不出手。除了全栈,多面手,就没亮点了。

考虑到我近些年的经验主要是 web开发。
所以我预计做 4 个项目,慢慢做。会写下自己的思考过程,以及实现过程中遇到的坑,还有一些反思。

因为是验证想法和达到目的,所以主要是vibe coding.

我有github copliot, claude code, droid, iflow cli.
主要编程工具是 zed, vscode.
考虑到主要是验证自己的想法,所以就白嫖iflow cli,也行,国内的模型。vscode review代码。最终就是vscode+ iflow cli extention.

项目 关键主题 技术类型
1. 高并发抽奖系统 缓存 + 异步 + 压测 极限性能架构
2. AI内容平台 调度 + 自动化 + AI能力 智能系统架构
3. WebSocket系统 实时通信 + 分布式消息 实时体验架构
4. 🛒 电商核心系统 数据一致性 + 事务保真 企业级业务架构

day1: 建仓库:高并发抽奖系统
技术选型:
我个人会的技术栈是php/python/golang/rust
rust一直没用起来,所以我打算玩下rust后端, vue 做前端。
基于我之前阅读过极客课程,《如何做秒杀系统》。印象中的思想就是 层层过滤。
抽奖也是一样的, 你能不能抽中其实是个概率问题。
那么从性能优化的角度思考,我可以把概率计算放到每个环节。

阅读全文»

bjmayor发布于2022-01-22

go并发模式: Context

go并发模式: Context

原文链接

介绍

在 Go 服务器中,每个传入请求都在其自己的 goroutine 中处理。请求处理程序通常会启动额外的 goroutine 来访问数据库和 RPC 服务等后端服务。处理请求的一组 goroutine 通常需要访问特定于请求的值,例如最终用户的身份、授权令牌和请求的截止日期。当请求被取消或超时时,所有处理该请求的 goroutines 都应该快速退出,以便系统可以回收它们正在使用的任何资源。

在 Google,我们开发了一个context包,可以轻松地将请求范围的值、取消信号和截止日期跨 API 边界传递给处理请求所涉及的所有 goroutine。该软件包作为context公开可用 。本文介绍了如何使用该包并提供了一个完整的工作示例。

阅读全文»

bjmayor发布于2022-01-11

go工具链

[TOC]

交叉编译

交叉编译

通过go env GOARCH 可获取到当前平台的架构。一般有 amd64,386,

mac上编译linux和windows二进制

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build

阅读全文»

bjmayor发布于2021-10-27

goroutine分析

本文档最后一次更新时所用的 Go 版本是 1.15.6,但是大多数情况下,新老版本都适用。

描述

Go 运行时在一个称为 allgs 简单切片追踪所有的 goroutines。这里面包含了活跃的和死亡的 goroutine 。死亡的 goroutine 保留下来,等到生成新的 goroutine 时重用。

Go 有各种 API 来监测 allgs中活跃的 goroutine 和这些 goroutines 当前的堆栈跟踪信息,以及各种其他属性。一些 API 将这些信息公开为统计摘要,而另外一些 API 则给每个单独的 goroutine 信息提供查询接口。

尽管 API 之间有差异,但是活跃的 goroutine 都有如下共同 定义

  • 非死
  • 不是系统 goroutine,也不是 finalizer goroutine。

换句话说,正在运行的 goroutine 和那些等待 i/o、锁、通道、调度的 goroutine 一样,都被认为是活跃的。尽管人们可能会天真的认为后面那几种等待的 goroutine 是不活跃的。

阅读全文»

bjmayor发布于2021-10-18

GMP调度器

GMP调度器

主要内容来自 潘少 的 gnet开源说。 https://github.com/gocn/opentalk

G、M、P 是什么

image-20211018161626840

G: 表示 Goroutine,每个 Goroutine 对应一个 G 结构体,G 存储 Goroutine 的运行堆栈、状态以及任务函数,可重用。G 并非执行体,每个 G 需要绑 定到 P 才能被调度执行。

P: Processor,表示逻辑处理器, 对 G 来说,P 相当于 CPU 核,G 只有绑定到 P(在 P 的 local runq 中)才能被调度。对 M 来说,P 提供了相关的执行 环境(Context),如内存分配状态(mcache),任务队列(G)等,P 的数量决定了系统内最大可并行的 G 的数量(前提:物理 CPU 核数 >= P 的数量),P 的数量由用户设置的 GOMAXPROCS 决定,但是不论 GOMAXPROCS 设置为多大,P 的数量最大为 256。

M: Machine,OS 线程抽象,代表着真正执行计算的资源,在绑定有效的 P 后,进入 schedule 循环;而 schedule 循环的机制大致是从 Global 队列、P 的 Local 队列以及 wait 队列中获取 G,切换到 G 的执行栈上并执行 G 的函数,调用 goexit 做清理工作并回到 M,如此反复。M 并不保留 G 状态,这是 G 可以跨 M 调度的基础,M 的数量是不定的,由 Go Runtime 调整,为了防止创建过多 OS 线程导致系统调度不过来,目前默认最大限制为 10000个。

阅读全文»