普通视图

发现新文章,点击刷新页面。
今天 — 2026年4月4日首页

Python 速记手册

2026年4月4日 04:38

Python 速记手册(含可运行 Demo 01~11)

6b41cd17ac5d47b5959ab5f226a4ec29(1).jpeg

适合人群:

  • 前端/全栈转 Python,需要“先跑起来”的最小路径
  • 只想快速掌握:语法、JSON、文件、请求、写接口、脚本自动化、Excel

git地址在这里:https://gitee.com/mslimyjj/old-ling-python/tree/master/python-cheatsheet-demos



0. 快速开始(先跑起来)

建议在 python-cheatsheet-demos/ 目录中运行命令(相对路径/生成文件最直观)。

python 01_basics.py

Windows:没有 python 命令怎么办

如果你的环境里 python 命令不可用,可以使用 Python 官方“嵌入式版本”(无需安装、不污染系统环境)。

python-cheatsheet-demos/ 目录执行:

$ver='3.11.8'
$zip="python-$ver-embed-amd64.zip"
$url="https://www.python.org/ftp/python/$ver/$zip"
$dest="..\.python-embed"
New-Item -ItemType Directory -Force -Path $dest | Out-Null
Invoke-WebRequest -Uri $url -OutFile "$dest\$zip"
Expand-Archive -Force -Path "$dest\$zip" -DestinationPath $dest
& "$dest\python.exe" 01_basics.py

后续统一用它运行 demo:

& "..\.python-embed\python.exe" 05_requests_demo.py

一键安装依赖

如果你用系统 Python:

pip install -r requirements.txt

如果你用嵌入式 Python:

& "..\.python-embed\python.exe" -m pip install -r requirements.txt

1. Demo 01:基础语法(变量 / 条件 / 循环 / 函数)

文件:01_basics.py

name = "张三"      # str
age = 20           # int
is_ok = True       # bool
arr = [1, 2, 3]    # list  = JS Array
obj = {"a": 1}     # dict  = JS Object

print(name, age, is_ok, arr, obj)

if age > 18:
    print("成年")
elif age == 18:
    print("刚成年")
else:
    print("未成年")

for item in [1, 2, 3]:
    print("item:", item)

for i in range(10):
    print("i:", i)


def add(a, b):
    return a + b


res = add(1, 2)
print("add:", res)

运行:

& "..\.python-embed\python.exe" 01_basics.py

2. Demo 02:list / dict(前端最熟)

文件:02_list_dict.py

arr = [1, 2, 3]
arr.append(4)
last = arr.pop()
print(arr, "popped:", last)
print("len:", len(arr))
print("first:", arr[0])

user = {
    "name": "tom",
    "age": 20,
}

print("name1:", user["name"])
print("name2:", user.get("name"))
print("missing:", user.get("addr"))

user["addr"] = "北京"
print(user)

你可以把 list 当成 JS 的数组,把 dict 当成 JS 的对象。

运行:

& "..\.python-embed\python.exe" 02_list_dict.py

3. Demo 03:JSON(前后端交互必备)

文件:03_json_demo.py

import json

data = json.loads('{"name":"tom","age":20}')
print(data, type(data))

str_data = json.dumps(data, ensure_ascii=False)
print(str_data, type(str_data))
  • json.loads:字符串 -> 对象
  • json.dumps:对象 -> 字符串

运行:

& "..\.python-embed\python.exe" 03_json_demo.py

4. Demo 04:文件读写(批量处理神器)

文件:04_file_io.py

import json

with open("test.txt", "w", encoding="utf-8") as f:
    f.write("hello\n")

with open("test.txt", "r", encoding="utf-8") as f:
    content = f.read()
print("content:", content)

payload = {"name": "tom", "age": 20}
with open("data.json", "w", encoding="utf-8") as f:
    json.dump(payload, f, ensure_ascii=False, indent=2)

with open("data.json", "r", encoding="utf-8") as f:
    data = json.load(f)
print("json:", data)

运行:

& "..\.python-embed\python.exe" 04_file_io.py

输出会读写当前目录的:

  • test.txt
  • data.json

5. Demo 05:requests(抓接口 / mock)

文件:05_requests_demo.py

import requests

res = requests.get("https://httpbin.org/get", params={"q": "test"}, timeout=10)
print("get status:", res.status_code)
print(res.json()["args"])

res = requests.post("https://httpbin.org/post", json={"username": "admin"}, timeout=10)
print("post status:", res.status_code)
print(res.json()["json"])

这个 demo 用 https://httpbin.org 作为测试服务,演示 GET/POST JSON。

运行:

& "..\.python-embed\python.exe" 05_requests_demo.py

6. Demo 06:FastAPI(快速写接口)

文件:06_fastapi_main.py

from fastapi import FastAPI

app = FastAPI()


@app.get("/api/user")
def get_user():
    return {"name": "tom", "age": 20}

安装依赖(如果还没装):

pip install fastapi uvicorn

运行:

uvicorn 06_fastapi_main:app --reload

访问:

  • http://localhost:8000/api/user
  • http://localhost:8000/docs

7. Demo 07:小脚本(遍历目录 / 批量重命名)

文件:07_scripts_os.py

import os

for file in os.listdir("./"):
    print(file)

imgs_dir = "./imgs"
if os.path.isdir(imgs_dir):
    for i, file in enumerate(os.listdir(imgs_dir)):
        src = os.path.join(imgs_dir, file)
        dst = os.path.join(imgs_dir, f"img{i}.png")
        if os.path.isfile(src):
            os.rename(src, dst)
            print("renamed:", src, "->", dst)

运行:

& "..\.python-embed\python.exe" 07_scripts_os.py

注意:批量重命名会操作 ./imgs 目录下文件名,运行前确认目录存在并且文件可改名。


8. Demo 08:对接 AI(HTTP 调用套路)

文件:08_ai_call.py

import requests


def call_ai(prompt: str):
    res = requests.post(
        "http://localhost:8000/ai",
        json={"prompt": prompt},
        timeout=30,
    )
    res.raise_for_status()
    return res.json()


code = call_ai("生成一个Vue3按钮组件")
print(code)

这个 demo 会调用:POST http://localhost:8000/ai

如果你本地没有启动这个服务,会出现连接被拒绝(这属于正常现象)。

运行:

& "..\.python-embed\python.exe" 08_ai_call.py

9. Demo 09:抓取网页请求并保存到 send.txt

文件:09_capture_requests.py

import argparse
import re
import sys
from urllib.parse import urlparse


def _normalize_url(u: str) -> str:
    try:
        p = urlparse(u)
        if not p.scheme or not p.netloc:
            return u
        return p._replace(fragment="").geturl()
    except Exception:
        return u


def _looks_like_api(u: str) -> bool:
    low = u.lower()
    if any(x in low for x in ("/api", "/graphql", "/v1/", "/v2/", "/rpc")):
        return True
    if any(low.endswith(x) for x in (".json", ".xml")):
        return True
    return False


def _capture_with_playwright(url: str, timeout_ms: int, only_api: bool) -> list[str]:
    try:
        from playwright.sync_api import sync_playwright  # type: ignore
    except Exception as e:
        raise RuntimeError("missing_playwright") from e

    seen: set[str] = set()
    out: list[str] = []

    def on_request(req):
        u = _normalize_url(req.url)
        if only_api and (not _looks_like_api(u)):
            return
        if u not in seen:
            seen.add(u)
            out.append(u)

    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        context = browser.new_context()
        page = context.new_page()
        page.on("request", on_request)
        page.goto(url, wait_until="networkidle", timeout=timeout_ms)
        try:
            page.wait_for_timeout(1500)
        except Exception:
            pass
        context.close()
        browser.close()

    return out


def _extract_from_html(url: str, timeout_sec: int, only_api: bool) -> list[str]:
    import requests

    html = requests.get(url, timeout=timeout_sec).text
    candidates = set(re.findall(r"https?://[^\s\"'>]+", html))
    cleaned = [_normalize_url(u) for u in candidates]
    if only_api:
        cleaned = [u for u in cleaned if _looks_like_api(u)]
    cleaned.sort()
    return cleaned


def main(argv: list[str]) -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("url")
    parser.add_argument("--out", default="send.txt")
    parser.add_argument("--timeout", type=int, default=30)
    parser.add_argument("--only-api", action="store_true")
    parser.add_argument("--mode", choices=["auto", "playwright", "html"], default="auto")
    args = parser.parse_args(argv)

    url = args.url
    out_path = args.out
    timeout_sec = args.timeout
    only_api = bool(args.only_api)
    mode = args.mode

    urls: list[str] = []
    if mode in ("auto", "playwright"):
        try:
            urls = _capture_with_playwright(url, timeout_sec * 1000, only_api)
        except RuntimeError as e:
            if str(e) != "missing_playwright" or mode == "playwright":
                raise
            urls = []

    if (not urls) and mode in ("auto", "html"):
        urls = _extract_from_html(url, timeout_sec, only_api)

    with open(out_path, "w", encoding="utf-8") as f:
        for u in urls:
            f.write(u + "\n")

    print(f"saved {len(urls)} urls -> {out_path}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main(sys.argv[1:]))

目标:给一个网页 URL,把它“页面里出现的 URL / 或页面运行时发出的请求”抓出来,写到 send.txt

9.1 推荐模式:Playwright(最接近浏览器真实请求)

安装:

pip install playwright
python -m playwright install chromium

运行(只保留更像接口的 URL):

python 09_capture_requests.py https://example.com --only-api --out send.txt

9.2 兜底模式:HTML 提取(抓不到 XHR/fetch)

如果你不安装 Playwright,脚本会自动降级为“从 HTML 源码中提取 URL”。

你也可以强制:

python 09_capture_requests.py https://example.com --mode html --out send.txt

参数速记:

  • --mode playwright:强制用浏览器抓
  • --mode html:只解析 HTML
  • --only-api:只保留更像接口的 URL(包含 /api/graphql/v1//v2/.json 等)

10. Demo 10:3 秒后“键盘输入” Helloween(不是 print)

文件:10_sleep_print.py

import time

from pynput.keyboard import Controller


time.sleep(3)
Controller().type("Helloween")

这个 demo 用 pynput 控制键盘:

  • 等待 3 秒
  • 向“当前获得焦点的窗口”键入 Helloween

使用方法:先把光标点到你想输入的位置(例如记事本/浏览器输入框),再运行脚本。

运行:

& "..\.python-embed\python.exe" 10_sleep_print.py

11. Demo 11:生成 user.xlsx(随机 10 个姓名)

文件:11_generate_user_excel.py

import os
import random

from openpyxl import Workbook


def random_cn_name() -> str:
    surnames = list("赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨朱秦尤许何吕施张孔曹严华金魏陶姜戚谢邹喻柏水窦章云苏潘葛范彭郎鲁韦昌马苗凤花方俞任袁柳酆鲍史唐费廉岑薛雷贺倪汤滕殷罗毕郝邬安常乐于时傅皮卞齐康伍余元卜顾孟平黄和穆萧尹姚邵湛汪祁毛禹狄米贝明臧计伏成戴谈宋茅庞熊纪舒屈项祝董梁杜阮蓝闵席季麻强贾路娄危江童颜郭梅盛林刁钟徐邱骆高夏蔡田樊胡凌霍虞万支柯昝管卢莫经房裘缪干解应宗丁宣贲邓郁单杭洪包诸左石崔吉钮龚程嵇邢滑裴陆荣翁荀羊於惠甄曲家封芮羿储靳汲邴糜松井段富巫乌焦巴弓牧隗山谷车侯宓蓬全郗班仰秋仲伊宫宁仇栾暴甘钭厉戎祖武符刘景詹束龙叶幸司韶郜黎蓟薄印宿白怀蒲邰从鄂索咸籍赖卓蔺屠蒙池乔阴郁胥能苍双闻莘党翟谭贡劳逄姬申扶堵冉宰郦雍却璩桑桂濮牛寿通边扈燕冀郏浦尚农温别庄晏柴瞿阎充慕连茹习宦艾鱼容向古易慎戈廖庾终暨居衡步都耿满弘匡国文寇广禄阙东欧殳沃利蔚越夔隆师巩厍聂晁勾敖融冷訾辛阚那简饶空曾毋沙乜养鞠须丰巢关蒯相查后荆红游竺权逯盖益桓公万俟司马上官欧阳夏侯诸葛闻人东方赫连皇甫尉迟公羊澹台公冶宗政濮阳淳于单于太叔申屠公孙仲孙轩辕令狐钟离宇文长孙慕容司徒司空")
    given_chars = list("一乙二十丁厂七卜人入八九几儿了力乃刀又三于干亏士工土才下寸大丈与万上小口山巾千乞川亿个夕久么勺丸凡及广亡门义之尸弓己已子卫也女飞刃习叉马乡丰王井开夫天元无云专扎艺木五支厅不太犬区历尤友匹车巨牙屯比互切瓦止少日中贝内水冈见手午牛毛气升长仁什片仆化仇币仍仅斤爪反介父从今凶分乏公仓月氏勿欠风丹匀乌凤勾文六方火为斗忆计订户认心尺引丑巴孔队办以允予劝双书幻玉刊末未示击打巧正扑扒功扔去甘世古节本术可丙左厉右石布龙平灭轧东卡北占业旧帅归且旦目叶甲申叮电号田由史只央兄叼叫另叨叹四生失禾丘付仗代仙们仪白仔他斥瓜乎丛令用甩印乐句匆册犯外处冬鸟务包饥主市立闪兰半汁汇头汉宁它讨写让礼训必议讯记永司尼民出辽奶奴召加皮边发孕圣对台矛纠母幼丝式刑动扛寺吉扣考托老执巩圾扩扫地扬场耳共芒亚芝朽朴机权过臣再协西压厌在有百存而页匠夸夺灰达列死成夹轨邪划迈毕至此贞师尘尖劣光当早吐吓虫曲团同吊吃因吸吗屿帆岁回岂则刚网肉年朱先丢舌竹迁乔伟传乒乓休伍伏优伐延件任伤价伦份华仰仿伙伪自伊血向似后行舟全会杀合兆企众爷伞创肌朵杂危旬旨负各名多争色壮冲妆冰庄庆亦刘齐交次衣产决充妄闭问闯羊并关米灯州汗污江池汤忙兴宇守宅字安讲军许论农讽设访那迅尽导异孙阵阳收阶阴防如妇好她妈戏羽观欢买红驮纤级约纪驰巡")
    surname = random.choice(surnames)
    given_len = random.choice([1, 2])
    given = "".join(random.choice(given_chars) for _ in range(given_len))
    return surname + given


def main():
    wb = Workbook()
    ws = wb.active
    ws.title = "user"

    ws.append(["id", "name"])
    for i in range(1, 11):
        ws.append([i, random_cn_name()])

    out_path = os.path.join(os.path.dirname(__file__), "user.xlsx")
    wb.save(out_path)
    print("saved ->", out_path)


if __name__ == "__main__":
    main()

这个 demo 用 openpyxl 生成 Excel:

  • 输出文件:user.xlsx
  • Sheet:user
  • 表头:idname
  • 数据:随机 10 个姓名

运行:

& "..\.python-embed\python.exe" 11_generate_user_excel.py

12. 你可以怎么用这套 demo

  • 当成“Python 最小工具箱”:复制某个脚本改两行就能完成临时需求
  • 当成“速记手册”:忘了 with open(...) / requests.get(...) 直接回来抄
  • 当成“前端同学上手模板”:从 05/06/09 开始就能快速进入“接口 + 自动化”节奏

每日一题-网格图中机器人回家的最小代价🟡

2026年4月4日 00:00

给你一个 m x n 的网格图,其中 (0, 0) 是最左上角的格子,(m - 1, n - 1) 是最右下角的格子。给你一个整数数组 startPos ,startPos = [startrow, startcol] 表示 初始 有一个 机器人 在格子 (startrow, startcol) 处。同时给你一个整数数组 homePos ,homePos = [homerow, homecol] 表示机器人的  在格子 (homerow, homecol) 处。

机器人需要回家。每一步它可以往四个方向移动:,同时机器人不能移出边界。每一步移动都有一定代价。再给你两个下标从 0 开始的额整数数组:长度为 m 的数组 rowCosts  和长度为 n 的数组 colCosts 。

  • 如果机器人往  或者往  移动到第 r  的格子,那么代价为 rowCosts[r] 。
  • 如果机器人往  或者往  移动到第 c  的格子,那么代价为 colCosts[c] 。

请你返回机器人回家需要的 最小总代价 。

 

示例 1:

输入:startPos = [1, 0], homePos = [2, 3], rowCosts = [5, 4, 3], colCosts = [8, 2, 6, 7]
输出:18
解释:一个最优路径为:
从 (1, 0) 开始
-> 往下走到 (2, 0) 。代价为 rowCosts[2] = 3 。
-> 往右走到 (2, 1) 。代价为 colCosts[1] = 2 。
-> 往右走到 (2, 2) 。代价为 colCosts[2] = 6 。
-> 往右走到 (2, 3) 。代价为 colCosts[3] = 7 。
总代价为 3 + 2 + 6 + 7 = 18

示例 2:

输入:startPos = [0, 0], homePos = [0, 0], rowCosts = [5], colCosts = [26]
输出:0
解释:机器人已经在家了,所以不需要移动。总代价为 0 。

 

提示:

  • m == rowCosts.length
  • n == colCosts.length
  • 1 <= m, n <= 105
  • 0 <= rowCosts[r], colCosts[c] <= 104
  • startPos.length == 2
  • homePos.length == 2
  • 0 <= startrow, homerow < m
  • 0 <= startcol, homecol < n

中等题的简单解法(emo了)

作者 kaifengguan
2021年11月28日 09:06

一看到题目第一感觉是用dp,但是我dp一点都没看过呀,觉得一定做不出来,遂准备放弃。突然灵光一闪,好像只要讨论四个方向的情况回家就行(以startPos为原点)😂
这里是以homePos坐标减去startPos坐标得到:

  • 第一象限:row<0, col >0;
  • 第二象限:row<0, col <0;
  • 第三象限:row>0, col <0;
  • 第四象限:row>0, col >0;
/**
 * @param {number[]} startPos
 * @param {number[]} homePos
 * @param {number[]} rowCosts
 * @param {number[]} colCosts
 * @return {number}
 */
var minCost = function(startPos, homePos, rowCosts, colCosts) {
    let res = 0;
    if (startPos[0] === homePos[0] && startPos[1] === homePos[1]) {
        return 0;
    }
    
    let row = homePos[0] - startPos[0]; // 行差
    let col = homePos[1] - startPos[1]; // 列差
    if (row >= 0 && col >= 0) {
        for (let i = 0; i < row; i++) {
            res += rowCosts[startPos[0] + i + 1];
        }
        for (let j = 0; j < col; j++) {
            res += colCosts[startPos[1] + j + 1];
        }
    } else if (row >= 0 && col < 0) {
        for (let i = 0; i < row; i++) {
            res += rowCosts[startPos[0] + i + 1];
        }
        for (let j = 0; j < Math.abs(col); j++) {
            res += colCosts[startPos[1] - j -1];
        }
    } else if (row < 0 && col >= 0) {
        for (let i = 0; i < Math.abs(row); i++) {
            res += rowCosts[startPos[0] - i - 1];
        }
        for (let j = 0; j < col; j++) {
            res += colCosts[startPos[1] + j + 1];
        }
    } else {
        for (let i = 0; i < Math.abs(row); i++) {
            res += rowCosts[startPos[0] - i - 1];
        }
        for (let j = 0; j < Math.abs(col); j++) {
            res += colCosts[startPos[1] - j -1];
        }
    }
    
    return res;
};

[Java]模拟,回家的路不需要拐弯抹角!

作者 coping_code
2021年11月28日 00:24

思路:

  • 由于给出的代价不为负,每多绕一段距离那么代价就更多一点,所以回家的路不需要拐弯抹角(直接朝着回家的方向走!)
  • 由于不能走斜线,所以回家的路只有竖着走和横着走
  • 那么,回家的代价就是模拟机器人竖着走到与家平行的位置的代价,再加上横着走到家的位置的代价

例子:
机器人在[1,0]这个位置,家在[2,3]这个位置
计算出机器人在家的左上方,所以机器人需要向朝着回家的方向走,即

  • 向下竖着走:从[1,0]走到[2,0]代价是3
  • 向右横着走:从[2,0]走到[2,1]代价是2,从[2,1]走到[2,2]代价是6,从[2,2]走到[2,3]代价是7
  • 所有代价加起来是18

###java

class Solution {
    public int minCost(int[] startPos, int[] homePos, int[] rowCosts, int[] colCosts) {
        // 计算机器人到家的纵向和横向距离
        int disX = startPos[0] - homePos[0];    // 纵向距离
        int disY = startPos[1] - homePos[1];    // 横向距离
        
        int ans = 0;

        // 计算纵向距离的代价
        if(disX < 0){
            for(int i=startPos[0]+1;i<=homePos[0];i++){
                ans += rowCosts[i];
            }
        }
        else{
            for(int i=startPos[0]-1;i>=homePos[0];i--){
                ans += rowCosts[i];
            }
        }

        // 计算横向距离的代价
        if(disY < 0){
            for(int j=startPos[1]+1;j<=homePos[1];j++){
                ans += colCosts[j];
            }
        }
        else{
            for(int j=startPos[1]-1;j>=homePos[1];j--){
                ans += colCosts[j];
            }
        }
        return ans;
    }
}

脑筋急转弯(Python/Java/C++/C/Go/JS/Rust)

作者 endlesscheng
2021年11月28日 00:10

脑筋急转弯:由于题目保证代价均为非负数,所以除了径直走以外,其它弯弯绕绕的策略都不可能更优,那么直接统计径直走的代价即可。

设起点为 $(x_0,y_0)$,终点为 $(x_1,y_1)$。

分别计算上下移动的代价,左右移动的代价,二者之和就是总代价。

  • 上下移动的代价:如果 $x_0 < x_1$,那么从起点移动到终点,$x_0+1,x_0+2,\ldots,x_1$ 这些行都要访问到,移动代价为 $\textit{rowCosts}$ 的子数组 $[x_0+1,x_1]$ 的元素和。如果 $x_0 > x_1$,那么移动代价为 $\textit{rowCosts}$ 的子数组 $[x_1+1,x_0]$ 的元素和。
  • 左右移动的代价:如果 $y_0 < y_1$,那么从起点移动到终点,$y_0+1,y_0+2,\ldots,y_1$ 这些列都要访问到,移动代价为 $\textit{colCosts}$ 的子数组 $[y_0+1,y_1]$ 的元素和。如果 $x_0 > x_1$,那么移动代价为 $\textit{colCosts}$ 的子数组 $[y_1+1,y_0]$ 的元素和。

代码实现时,不需要根据 $x_0$ 和 $x_1$ 的大小关系分情况讨论,而是计算 $\textit{rowCosts}$ 的子数组 $[\min(x_0,x_1), \max(x_0,x_1)]$ 的元素和,再减去多算的起点代价 $\textit{rowCosts}[x_0]$。对于 $y_0$ 和 $y_1$ 同理。

class Solution:
    def minCost(self, startPos: List[int], homePos: List[int], rowCosts: List[int], colCosts: List[int]) -> int:
        x0, y0 = startPos
        x1, y1 = homePos

        # 起点的代价不计入,先减去
        ans = -rowCosts[x0] - colCosts[y0]

        # 累加代价(包含起点)
        ans += sum(rowCosts[min(x0, x1): max(x0, x1) + 1])
        ans += sum(colCosts[min(y0, y1): max(y0, y1) + 1])

        return ans
class Solution {
    public int minCost(int[] startPos, int[] homePos, int[] rowCosts, int[] colCosts) {
        int x0 = startPos[0], y0 = startPos[1];
        int x1 = homePos[0], y1 = homePos[1];

        // 起点的代价不计入,先减去
        int ans = -rowCosts[x0] - colCosts[y0];

        // 累加代价(包含起点)
        int l1 = Math.min(x0, x1), r1 = Math.max(x0, x1);
        for (int i = l1; i <= r1; i++) {
            ans += rowCosts[i];
        }

        int l2 = Math.min(y0, y1), r2 = Math.max(y0, y1);
        for (int i = l2; i <= r2; i++) {
            ans += colCosts[i];
        }

        return ans;
    }
}
class Solution {
public:
    int minCost(vector<int>& startPos, vector<int>& homePos, vector<int>& rowCosts, vector<int>& colCosts) {
        int x0 = startPos[0], y0 = startPos[1];
        int x1 = homePos[0], y1 = homePos[1];

        // 起点的代价不计入,先减去
        int ans = -rowCosts[x0] - colCosts[y0];

        // 累加代价(包含起点)
        ans += reduce(rowCosts.begin() + min(x0, x1), rowCosts.begin() + max(x0, x1) + 1, 0);
        ans += reduce(colCosts.begin() + min(y0, y1), colCosts.begin() + max(y0, y1) + 1, 0);

        return ans;
    }
};
#define MIN(a, b) ((b) < (a) ? (b) : (a))
#define MAX(a, b) ((b) > (a) ? (b) : (a))

int minCost(int* startPos, int startPosSize, int* homePos, int homePosSize, int* rowCosts, int rowCostsSize, int* colCosts, int colCostsSize) {
    int x0 = startPos[0], y0 = startPos[1];
    int x1 = homePos[0], y1 = homePos[1];

    // 起点的代价不计入,先减去
    int ans = -rowCosts[x0] - colCosts[y0];

    // 累加代价(包含起点)
    int l1 = MIN(x0, x1), r1 = MAX(x0, x1);
    for (int i = l1; i <= r1; i++) {
        ans += rowCosts[i];
    }

    int l2 = MIN(y0, y1), r2 = MAX(y0, y1);
    for (int i = l2; i <= r2; i++) {
        ans += colCosts[i];
    }

    return ans;
}
func minCost(startPos, homePos, rowCosts, colCosts []int) int {
x0, y0 := startPos[0], startPos[1]
x1, y1 := homePos[0], homePos[1]

// 起点的代价不计入,先减去
ans := -rowCosts[x0] - colCosts[y0]

// 累加代价(包含起点)
for _, cost := range rowCosts[min(x0, x1) : max(x0, x1)+1] {
ans += cost
}
for _, cost := range colCosts[min(y0, y1) : max(y0, y1)+1] {
ans += cost
}

return ans
}
var minCost = function(startPos, homePos, rowCosts, colCosts) {
    const [x0, y0] = startPos;
    const [x1, y1] = homePos;

    // 起点的代价不计入,先减去
    let ans = -rowCosts[x0] - colCosts[y0];

    // 累加代价(包含起点)
    ans += _.sum(rowCosts.slice(Math.min(x0, x1), Math.max(x0, x1) + 1));
    ans += _.sum(colCosts.slice(Math.min(y0, y1), Math.max(y0, y1) + 1));

    return ans;
};
impl Solution {
    pub fn min_cost(start_pos: Vec<i32>, home_pos: Vec<i32>, row_costs: Vec<i32>, col_costs: Vec<i32>) -> i32 {
        let x0 = start_pos[0] as usize;
        let y0 = start_pos[1] as usize;
        let x1 = home_pos[0] as usize;
        let y1 = home_pos[1] as usize;

        // 起点的代价不计入,先减去
        let mut ans = -row_costs[x0] - col_costs[y0];

        // 累加代价(包含起点)
        ans += row_costs[x0.min(x1)..=x0.max(x1)].iter().sum::<i32>();
        ans += col_costs[y0.min(y1)..=y0.max(y1)].iter().sum::<i32>();

        ans
    }
}

复杂度分析

  • 时间复杂度:$\mathcal{O}(|\textit{start}{\textit{row}} - \textit{home}{\textit{row}}| + |\textit{start}{\textit{col}} - \textit{home}{\textit{col}}|)$。
  • 空间复杂度:$\mathcal{O}(1)$。Python 和 JS 把切片改成普通循环即可做到 $\mathcal{O}(1)$ 空间。

如果有负数代价呢?

本题是图论中的最短路问题。在有负数边权的情况下,可以用 Bellman-Ford 算法解决。需要注意的是,如果有负环,则最小代价为 $-\infty$。

专题训练

见下面贪心与思维题单的「§5.2 脑筋急转弯」。

分类题单

如何科学刷题?

  1. 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
  2. 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
  3. 单调栈(基础/矩形面积/贡献法/最小字典序)
  4. 网格图(DFS/BFS/综合应用)
  5. 位运算(基础/性质/拆位/试填/恒等式/思维)
  6. 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
  7. 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
  8. 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
  9. 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
  10. 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
  11. 链表、树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA)
  12. 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)

我的题解精选(已分类)

欢迎关注 B站@灵茶山艾府

昨天 — 2026年4月3日首页

省市区县乡镇街道三级四级联动数据源:2026年民政部和统计局已不再公布行政区划代码,可改用直接调国家地名信息库的接口

作者 xiangyuecn
2026年4月3日 23:29

国家地名信息库

国家地名信息库链接: dmfw.mca.gov.cn

接口服务文档:dmfw.mca.gov.cn/interface.h…

正常程序中使用时,将数据缓存起来存入文件或者数据库,比调用接口更稳定。

//直接在浏览器控制台执行,可以测试接口结果
/* 接口说明
code不填时获取省级,填了时获取对应的区划和下级数据
maxLevel=1只获取一级数据 maxLevel=2获取两级数据 maxLevel=3获取三级数据
*/
//获取全国省市区三级,将近300KB数据接口会比较慢
var response=await fetch("https://dmfw.mca.gov.cn/9095/xzqh/getList?code=&maxLevel=3");
var data=await response.json();
console.log(data);

//只获取获取省级数据,速度比较快
var response=await fetch("https://dmfw.mca.gov.cn/9095/xzqh/getList?code=&maxLevel=1");
var data=await response.json();
console.log(data);

//获取湖北省 省、市、区 三级
var response=await fetch("https://dmfw.mca.gov.cn/9095/xzqh/getList?code=420000000000&maxLevel=3");
var data=await response.json();
console.log(data);

//获取武汉市 市、区县、乡镇街道 三级
var response=await fetch("https://dmfw.mca.gov.cn/9095/xzqh/getList?code=420100000000&maxLevel=3");
var data=await response.json();
console.log(data);

注意:当直接获取省市区三级数据时,以下城市只有两级:

  1. 直辖市(如:北京、天津、上海、重庆)
  2. 不设区的市(如:东莞、中山、儋州、嘉峪关)
  3. 省直辖县级行政单位(如:济源、仙桃、琼海、胡杨河)

其他省市都有三级结构。

数据信息

统计局自2024年下半年起就不再公开统计用区划代码,改用国家地名信息库数据。

民政部公告相关链接:www.mca.gov.cn/n156/n186/i…

摘自民政部的公告:自2026年起,本栏目不再公布行政区划代码相关信息。请前往民政部门户网站首页的国家地名信息库版块查询相关信息。

已整合的开源库:github.com/xiangyuecn/…

开源库:已将四级数据整合到了单个csv文件中,同时提供标注拼音、坐标和四级边界范围。提供工具生成多级联动数据和代码,也支持将数据导入MySQL、MSSQL、PgSQL、Oracle等数据库中

【2026-04-03】国家地名信息库行政区划数据截止日期为2025年12月31日。

千里科技发布2025财报:全年实现营业收入99.99亿元,同比增长42.13%

2026年4月3日 21:25
千里科技今日发布2025年年度报告,公司收入、利润双增长,“AI+车”商业化实现突破。报告期内,全年实现营业收入99.99亿元,同比增长42.13%;归母净利润约0.84亿元,同比增长111%。制造业务板块收入达93.19亿元,同比增长37.33%。其中,汽车业务收入达64.40亿元,同比增长52.71%。整车销量同比增长83.93%;摩托车和通机业务收入达28.79亿元,摩托车销量同比增长15.11%;科技业务板块收入达3.50亿元。

最近爆火的 Harness Engineering 被我提炼成了 SKILL,小白也能快速上手

作者 Justin3go
2026年4月3日 20:53

✨文章摘要(AI生成)

笔者分享了将 Harness Engineering 知识提炼为可复用 Agent Skill 的经验。在系统阅读了 Anthropic、OpenAI、Martin Fowler、LangChain 等来源的文章后,提炼出 Harness 设计的七个核心层:项目搭建、上下文工程、约束与防护、多 Agent 架构、评估与反馈、长时间任务、诊断。最终产出的 harness-engineering 技能覆盖三大场景——新项目搭建、Agent 行为诊断、持续改进,采用渐进式披露架构。定量评估显示有技能时断言通过率 100%,无技能时 83%。核心洞察:Agent 表现不好,80% 的原因不在模型,在 Harness。

为什么写这个

最近两年,笔者在使用各种AI编码助手(Claude Code、Cursor、Copilot等)的过程中,反复遇到一个问题:Agent时好时坏,虽然整体来说随着模型能力进步是向好的,但是向好的过程是曲折波动的。

有时候它写的代码完美契合项目风格,有时候它像个第一天入职的实习生——不知道项目结构、不遵守约定、还把之前商量好的决策忘得一干二净。

然后开始从 Prompt Engineering 中使用结构化、few shot、few example 等技巧,来让 AI 的输出更加稳定。 后面又使用 Context Engineering 来让 Agent 的上下文更加丰富,来让 Agent 的表现更加稳定。

最近几周,一个更系统的词汇出现了:Harness Engineering。

Agent表现不好,80%的原因不在模型,在Harness。 - Anthropic

什么是Harness?简单说:

  • 模型 = CPU(算力本身)
  • 上下文窗口 = RAM(工作记忆)
  • Harness = 操作系统(调度、约束、反馈、文件系统——一切让CPU有效工作的基础设施)

你不会指望一个CPU在没有操作系统的裸机上高效运行。同理,你也不该指望一个模型在没有Harness的项目里稳定输出。

我学到了什么

笔者系统阅读了以下来源的文章:

  • Anthropic — 构建高效Agent、多Agent研究系统、长时间运行Agent的Harness设计
  • OpenAI — AGENTS.md设计模式、Context Engineering最佳实践
  • Martin Fowler — Harness Engineering的工程哲学("Relocating Rigor")
  • LangChain — Agent框架 vs 运行时 vs Harness的分类学
  • philschmid — 2026年Agent Harness的重要性
  • 独立开发者实践 — Hermes Agent的自演化、Vue Lynx的设计笔记驱动开发
  • 学术论文 — 自然语言Agent Harness的形式化研究

读完之后,我发现这些文章虽然角度各异,但核心思想收敛到了七个层

层级 解决什么问题 一句话总结
项目搭建 Agent不知道项目是什么 AGENTS.md是目录,不是百科全书
上下文工程 Agent看到的信息不对 给地图,不给手册
约束与防护 Agent犯重复的错 每犯一次错,加一条规则
多Agent架构 单Agent搞不定复杂任务 分工明确,协议清晰
评估与反馈 不知道Agent做得好不好 让AI检查AI
长时间任务 Agent跑着跑着就走偏了 进度文件 + 上下文重置
诊断 用户骂Agent不好用 问题在Harness,不在模型

所以我做了个技能

读完这些文章,笔者意识到这些模式完全是可复用的。不管你的项目是React前端、Python后端还是Rust CLI工具——Harness的设计原则是通用的。

于是我把这些知识提炼成了一个 Agent Skill,名叫 harness-engineering

它做什么

这个技能有三个核心使用场景:

场景一:新项目搭建

当你启动一个新项目,告诉Agent"帮我搭建Harness工程",它会:

  1. 评估你的项目类型、技术栈、团队规模
  2. 创建 AGENTS.md(表of目录式的Agent导航文件)
  3. 建立 docs/ 目录(架构、约定、数据模型等)
  4. 配置约束层(lint规则、类型检查、pre-commit hooks)
  5. 设置评估与反馈机制

场景二:Agent表现不佳时的诊断

这是最有意思的场景。当你开始抱怨——

  • "它怎么又犯同样的错误?"
  • "它根本不遵守我们的约定!"
  • "它写的代码质量太差了"

这个技能会被触发,引导Agent去诊断Harness层的缺失,而不是怪模型:

你的抱怨 大概率原因 修复方式
总犯同一个错 没有约束阻止它 加一条lint规则
不遵守约定 约定没写下来或Agent找不到 写入docs/,在AGENTS.md中引用
忘记之前的决定 跨会话上下文未持久化 用progress.md记录决策
代码质量差 没有好代码的示例 在DESIGN_NOTES.md中加示例

场景三:持续改进

每次发现新的可复用Harness模式,更新到技能中,让它在其他项目中也能受益。

它怎么组织的

技能采用渐进式加载架构:

harness-engineering/
├── SKILL.md              # 入口文件(<60行),路由到具体参考文档
└── references/
    ├── 01-project-setup.md       # 项目搭建
    ├── 02-context-engineering.md  # 上下文工程
    ├── 03-constraints.md          # 约束与防护
    ├── 04-multi-agent.md          # 多Agent架构
    ├── 05-eval-feedback.md        # 评估与反馈
    ├── 06-long-running.md         # 长时间任务
    └── 07-diagnosis.md            # 诊断

SKILL.md本身非常精简——它就像一个路由器,根据当前场景指引Agent去读对应的参考文档。这遵循了Harness Engineering本身的原则:渐进式披露,按需加载

几个让我印象深刻的模式

有几个模式特别触动笔者,感同身受,这里单独拿出来聊聊。

"给地图,不给手册"

这个观点从推文中看到。传统做法是给Agent写详细的分步指令(手册),但这让Agent变得脆弱——任何偏差都会导致它不知所措。

更好的做法是给Agent一张地图

# 不好的写法(手册)
Step 1: 打开 src/auth/login.ts
Step 2: 找到 handleLogin 函数
Step 3: 在第42行添加...

# 好的写法(地图)
Auth系统在 src/auth/。登录流程:login.ts → validate.ts → session.ts。
限流中间件在 src/middleware/rateLimit.ts——参考它的模式。
每次修改auth都要在 src/auth/__tests__/ 里加测试。

地图让Agent能自主导航,手册让它成为脆弱的执行机器。

"每犯一次错,加一条规则"

这个模式来自多篇文章的交叉验证。核心思想:

  1. Agent犯了一个错
  2. 你修复了这个错
  3. 然后你加一条规则,永远阻止这类错再次发生

这条规则可以是lint规则、类型约束、测试用例,或者只是文档中的一条约定。随着时间推移,Harness积累了越来越多的规则,Agent的错误率对已知模式趋近于零。

这其实就是Martin Fowler说的 "Relocating Rigor"——把人类通过Code Review、经验、直觉实施的质量把关,迁移到自动化检查中。Agent在被检查的边界内自由运行。

Harness = 数据集

这个观点来自Anthropic。每次Agent交互都是一个训练信号:

  • 它尝试了什么
  • 什么成功了
  • 什么失败了
  • 修复方案是什么

这些痕迹(traces)就是你的竞争优势。它们是让你的Harness随时间越来越好的数据——不是微调模型,而是优化操作系统。

技能评估:有没有用?

笔者遵循skill-creator的流程,对这个技能做了定量评估。设计了3组测试场景,每组跑with-skill和without-skill两个版本:

测试场景 有技能 无技能
新项目搭建 6/6 ✅ 4/6
Agent行为诊断 6/6 ✅ 5/6
跨模块依赖问题 6/6 ✅ 6/6
合计 18/18 (100%) 15/18 (83%)

有技能的版本在所有场景下都通过了全部断言。无技能的版本在"新项目搭建"场景下缺失较多——它不知道要创建AGENTS.md、不知道docs/应该怎么组织、不会设置渐进式披露的上下文架构。

当然,17%的差距不算巨大。但关键是:有技能时Agent的输出一致且完整,无技能时看运气。对于一个工程实践类技能来说,一致性比偶尔的惊艳更有价值。

怎么安装

这个技能可通过 GitHub 安装:

npx skills add 10xChengTu/harness-engineering

安装后,当你在Claude Code、OpenCode或其他支持Skills的Agent中工作时:

  • 启动新项目 → 技能自动触发,引导搭建Harness
  • 遇到Agent质量问题 → 开始抱怨时技能会介入诊断
  • 主动询问 → "帮我改进这个项目的Harness"

最后

Harness Engineering目前还是一个非常早期的领域。模型在变强,今天需要的约束明天可能就多余了——所以这个技能本身也遵循一个核心原则:为删除而构建

如果你也在用AI Agent做开发,不妨试试给你的项目加上Harness。从最简单的开始——一个AGENTS.md文件、几条lint规则、一个progress.md。然后观察Agent的表现变化。

你大概率会和笔者有同样的感受:不是模型不行,是我们没给它一个好的工作环境。

本文涉及的所有参考文章和完整技能源码,均可在GitHub 仓库中找到。

智己汽车官宣刘翔成为品牌代言人

2026年4月3日 20:44
4月3日,智己汽车宣布,奥运冠军、世界级田径运动员刘翔正式成为品牌代言人。此外,智己LS8自3月26日开启预售以来,45分钟小订突破10000台。据了解,智己LS8集同级首发的全线控四轮转向、全满贯百万级底盘、英伟达Thor芯片+520线超视域激光雷达、AI超级智能体IM Ultra Agent 1.0、恒星超级增程系统等技术于一体,并将于4月16日正式上市。

美国2月非农就业人数修正至减少13.3万人

2026年4月3日 20:42
4月3日消息,美国1月份非农新增就业人数从增加12.6万人上修至增加16万人;2月份非农新增就业人数从减少9.2万人下修至减少13.3万人。修正后,1月和2月新增就业人数合计较修正前低0.7万人。(界面)

How to Upgrade Debian 12 to Debian 13 Trixie

Debian 13, codenamed “Trixie”, was released on August 9, 2025. It ships with Linux kernel 6.12 LTS, GNOME 48, KDE Plasma 6, GCC 14.2, Python 3.13, and over 14,100 new packages. Debian 13 will receive full support until August 2028, with Long Term Support (LTS) extending to June 2030.

This guide walks you through upgrading Debian 12 “Bookworm” to Debian 13 “Trixie” via the command line.

Prerequisites

You need to be logged in as root or a user with sudo privileges to perform the upgrade. You can only upgrade to Debian 13 from Debian 12. If you are running an older Debian version, upgrade to Debian 12 first.

Back Up Your Data

Before starting a major version upgrade, make sure you have a complete backup of your data. If you are running Debian on a virtual machine, take a full system snapshot so you can restore quickly if anything goes wrong.

Update Currently Installed Packages

Before changing the source repositories, bring your existing Debian 12 system fully up to date.

Check whether any packages are marked as held back, which could interfere with the upgrade:

Terminal
sudo apt-mark showhold

If there are held packages, either unhold them with sudo apt-mark unhold package_name or make sure they will not cause issues during the upgrade.

Refresh the package index and upgrade all installed packages:

Terminal
sudo apt update
sudo apt upgrade

Perform a major version upgrade of the installed packages:

Terminal
sudo apt full-upgrade

Remove automatically installed dependencies that are no longer needed:

Terminal
sudo apt autoremove

Update the Sources List

The upgrade works by pointing your APT repositories from bookworm to trixie.

Open /etc/apt/sources.list with your text editor and replace every instance of bookworm with trixie. You can also do this with a single sed command:

Terminal
sudo sed -i 's/bookworm/trixie/g' /etc/apt/sources.list

If you have third-party repository files under /etc/apt/sources.list.d/, disable them before the upgrade. They may not be compatible with Debian 13 and can cause errors.

Warning
Remove any bookworm-backports entries from your sources files before upgrading. You can add trixie-backports after the upgrade is complete.

After editing, your /etc/apt/sources.list should look similar to this:

/etc/apt/sources.listini
deb https://deb.debian.org/debian/ trixie main contrib non-free non-free-firmware
# deb-src https://deb.debian.org/debian/ trixie main contrib non-free non-free-firmware

deb https://deb.debian.org/debian/ trixie-updates main contrib non-free non-free-firmware
# deb-src https://deb.debian.org/debian/ trixie-updates main contrib non-free non-free-firmware

deb https://security.debian.org/debian-security/ trixie-security main contrib non-free non-free-firmware
# deb-src https://security.debian.org/debian-security/ trixie-security main contrib non-free non-free-firmware

You can find a full list of Debian mirror addresses on the official mirrors page .

Upgrade to Debian 13 Trixie

Set the terminal output to English to make it easier to follow any prompts:

Terminal
export LC_ALL=C

Update the package index with the new Trixie repositories:

Terminal
sudo apt update

If you see errors related to third-party repositories, fix or disable them before continuing.

Run the initial upgrade. This upgrades packages that do not require installing or removing other packages:

Terminal
sudo apt upgrade --without-new-pkgs

During the upgrade, you may be asked whether services should be automatically restarted:

output
Restart services during package upgrades without asking?

You may also see prompts about configuration files. If you have not made custom changes to a file, it is safe to accept the package maintainer’s version. If you have made changes, keep the current version to avoid losing your customizations.

Once the initial upgrade finishes, run the full upgrade. This installs new packages, removes obsolete ones, and resolves any remaining dependency changes between Debian 12 and 13:

Terminal
sudo apt full-upgrade

The upgrade may take some time depending on the number of packages, your hardware, and your internet speed.

When it completes, clean up packages that are no longer needed:

Terminal
sudo apt autoremove

Reboot your system to load the new kernel:

Terminal
sudo systemctl reboot

Verify the Upgrade

After the system boots, log in and check the Debian version :

Terminal
lsb_release -a
output
No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux 13 (trixie)
Release: 13
Codename: trixie

You can also verify the kernel version:

Terminal
uname -r

The output should show a 6.12.x kernel.

Troubleshooting

Third-party repository errors during apt update
Disable any third-party sources under /etc/apt/sources.list.d/ before the upgrade. Re-enable them one by one after the upgrade completes, checking that each repository supports Debian 13.

“Packages have been kept back” during upgrade
This is normal during the initial apt upgrade --without-new-pkgs step. The subsequent apt full-upgrade resolves these held-back packages by installing new dependencies or removing conflicting ones.

Services fail to start after reboot
Check the service logs with journalctl -xe and the service status with systemctl status service_name. Configuration file format changes between major versions are a common cause. Compare your config with the package maintainer’s version in /etc/*.dpkg-dist files.

Conclusion

Your system is now running Debian 13 Trixie. Re-enable any third-party repositories you disabled, verify that your critical services are running, and consider adding trixie-backports to your sources if you need newer package versions. For a full list of known issues and detailed upgrade notes, see the official Debian 13 release notes .

强一股份:一季度净利同比预增655%-762%

2026年4月3日 20:40
36氪获悉,强一股份公告,预计2026年第一季度实现归属于上市公司股东的净利润为1.06亿元-1.21亿元,同比增加654.79%-761.60%。本期业绩同比大幅增长,主要系AI算力需求爆发及行业景气度上行,成熟产品订单放量;前期已发货未确认收入订单在本期确认;以及客户结构优化与规模效应显现共同作用所致。

东方财富:目前没有并购计划,未收到新的减持计划

2026年4月3日 20:23
东方财富在线上召开2025年年度业绩说明会,对于投资者关心的减持、是否有并购计划、股价下行、回购、研发投入下降等话题均作出回应。近两年来,东方财富的股东和董监高因为减持和询价转让受到市场关注。东方财富董事长其实在业绩说明会上表示,目前公司没有进行中的减持计划,也未收到新的减持计划。(中证网)

妙可蓝多:一季度净利润同比下降8.3%

2026年4月3日 20:17
36氪获悉,妙可蓝多发布2025年业绩报告。报告显示,2026年第一季度实现营业收入16.26亿元,同比增长31.81%;归属于上市公司股东的净利润为7555.8万元,同比下降8.3%。业绩变动主要系股权激励费用摊销影响,剔除该因素后净利润同比增长1.8%,主要得益于营收增长及C端产品品类结构优化。

模塑科技:控股股东拟合计减持不超3%股份

2026年4月3日 20:15
36氪获悉,模塑科技公告,控股股东江阴模塑集团有限公司计划自本公告披露之日起15个交易日后的3个月内,通过集中竞价和大宗交易方式,合计减持公司股份不超过2,754万股,即不超过公司总股本的3.00%。减持原因为模塑集团自身的生产经营及偿还银行贷款。通过集中竞价交易方式减持的,在任意连续90个自然日内减持的股份总数不超过公司股份总数的1%;通过大宗交易方式减持的,在任意连续90个自然日内减持的股份总数不超过公司股份总数的2%。
❌
❌