普通视图
昨天 — 2025年5月17日技术
# Vue 中 provide/inject 与 props/emit 的对比与选择
2025年5月17日 21:05
一、核心设计理念差异 1. 数据流向的明确性 props/emit 遵循严格的单向数据流: provide/inject 则是隐式的跨层级通信: 二、必须使用 props/emit 的场景 1
Vue 中 provide/inject 与传统状态管理的深度对比
2025年5月17日 21:00
一、provide/inject 基础原理 1. 基本用法 2. 响应式数据传递 二、provide/inject 的优势 1. 组件树穿透能力 场景:多层嵌套组件共享配置 2. 减少 props
O(n) 插入排序,简洁写法(Python/Java/C++/C/Go/JS/Rust)
2025年5月17日 08:57
不让用 $\texttt{sort}$ 吗?有意思……
技巧:O(1) 插入元素
假设现在有一个有序数组 $a=[0,0,1,1,2,2]$。在 $a$ 中插入一个 $0$,同时保证 $a$ 是有序的,你会怎么做?
最暴力的想法是,把 $0$ 插在数组的最左边,原来的元素全体右移一位,得到 $[0,0,0,1,1,2,2]$。这样做是 $\mathcal{O}(n)$ 的。
实际上,我们可以「狸猫换太子」:不是插入元素,而是修改元素!
对比一下插入前后:
- 插入前 $[0,0,1,1,2,2]$。
- 插入后 $[0,0,0,1,1,2,2]$。
竖着看,其实只有 $3$ 个位置变了:
- 原来的 $a[2]$ 变成 $0$。
- 原来的 $a[4]$ 变成 $1$。
- 末尾新增一个 $2$,相当于 $a[6]=2$。
怎么知道要修改的位置(下标)?
- 维护 $0$ 的个数,即为改成 $0$ 的位置,记作 $p_0$。上例中 $p_0=2$。把 $a[p_0]$ 改成 $0$。
- 维护 $0$ 和 $1$ 的个数,即为改成 $1$ 的位置,记作 $p_1$。上例中 $p_1=4$。把 $a[p_1]$ 改成 $1$。
- 末尾新增的位置记作 $i$,把 $a[i]$ 改成 $2$。
细节
如果 $a$ 中没有 $2$ 呢?上面第三步就错了。
比如现在 $a=[1]$,插入一个 $0$,变成 $[0,1]$。
如果按照上面三步走,最后把 $a[1]$ 改成 $2$,得到的是 $[0,2]$,这就错了。
要写很多 $\texttt{if-else}$,特判这些特殊情况吗?
不需要,我们可以倒过来算:先把 $a[1]$ 改成 $2$,再把 $a[1]$ 改成 $1$(覆盖),最后 $a[0]$ 改成 $0$,得到 $[0,1]$。这种「覆盖」等价于「没有 $2$ 的时候不改成 $2$」。
如果插入的是 $1$ 呢?
跳过「把 $a[p_0]$ 改成 $0$」这一步。
如果插入的是 $2$ 呢?
只需要把 $a[i]$ 改成 $2$ 即可。
本题思路
对 $\textit{nums}$ 执行插入排序,也就是对 $i=0,1,2,\ldots,n-1$ 依次执行如下过程:
- 现在前缀 $\textit{nums}[0]$ 到 $\textit{nums}[i-1]$ 是有序的,我们把 $\textit{nums}[i]$ 插入到这个有序前缀中,从而把前缀 $\textit{nums}[0]$ 到 $\textit{nums}[i]$ 变成有序的。
- 算法执行完后,$\textit{nums}$ 就是一个有序数组了。
class Solution:
def sortColors(self, nums: List[int]) -> None:
p0 = p1 = 0
for i, x in enumerate(nums):
nums[i] = 2
if x <= 1:
nums[p1] = 1
p1 += 1
if x == 0:
nums[p0] = 0
p0 += 1
class Solution {
public void sortColors(int[] nums) {
int p0 = 0;
int p1 = 0;
for (int i = 0; i < nums.length; i++) {
int x = nums[i];
nums[i] = 2;
if (x <= 1) {
nums[p1++] = 1;
}
if (x == 0) {
nums[p0++] = 0;
}
}
}
}
class Solution {
public:
void sortColors(vector<int>& nums) {
int p0 = 0, p1 = 0;
for (int i = 0; i < nums.size(); i++) {
int x = nums[i];
nums[i] = 2;
if (x <= 1) {
nums[p1++] = 1;
}
if (x == 0) {
nums[p0++] = 0;
}
}
}
};
void sortColors(int* nums, int numsSize) {
int p0 = 0, p1 = 0;
for (int i = 0; i < numsSize; i++) {
int x = nums[i];
nums[i] = 2;
if (x <= 1) {
nums[p1++] = 1;
}
if (x == 0) {
nums[p0++] = 0;
}
}
}
func sortColors(nums []int) {
p0, p1 := 0, 0
for i, x := range nums {
nums[i] = 2
if x <= 1 {
nums[p1] = 1
p1++
}
if x == 0 {
nums[p0] = 0
p0++
}
}
}
var sortColors = function(nums) {
let p0 = 0, p1 = 0;
for (let i = 0; i < nums.length; i++) {
const x = nums[i];
nums[i] = 2;
if (x <= 1) {
nums[p1++] = 1;
}
if (x === 0) {
nums[p0++] = 0;
}
}
};
impl Solution {
pub fn sort_colors(nums: &mut Vec<i32>) {
let mut p0 = 0;
let mut p1 = 0;
for i in 0..nums.len() {
let x = nums[i];
nums[i] = 2;
if x <= 1 {
nums[p1] = 1;
p1 += 1;
}
if x == 0 {
nums[p0] = 0;
p0 += 1;
}
}
}
}
复杂度分析
- 时间复杂度:$\mathcal{O}(n)$,其中 $n$ 是 $\textit{nums}$ 的长度。
- 空间复杂度:$\mathcal{O}(1)$。
分类题单
- 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
- 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
- 单调栈(基础/矩形面积/贡献法/最小字典序)
- 网格图(DFS/BFS/综合应用)
- 位运算(基础/性质/拆位/试填/恒等式/思维)
- 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
- 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
- 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
- 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
- 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
- 链表、二叉树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA/一般树)
- 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)
欢迎关注 B站@灵茶山艾府
大厂面试:与HTML相关的基础知识点解析
2025年5月17日 17:42
在前端开发的面试中,HTML 是最基础也是最重要的知识点之一。 尤其是大厂的前端面试,往往会围绕 HTML 的核心概念和语义化标签进行深入考察。 本文将带你梳理一些常见的 HTML 面试问题
译:自由实验你的代码—Git worktree
2025年5月17日 17:23
编者注: Git worktree 是 Git 提供的一个强大功能,它允许你在同一个仓库中同时处理多个分支,而不会干扰当前的工作环境。1) 通过创建新的 worktree,你可以并行处理多个任务,比如
ts极速封装axios,关注点分离,包会、包爽!
2025年5月17日 17:22
axios还用封装? 不着急,咱先聊聊为什么要封装axios,或者说我们的封装目标是什么。axios还用封装? 不着急,咱先聊聊为什么要封装axios,或者说我们的封装目标是什么。
Cesium基础(四):部署离线地图和地形资源
2025年5月17日 17:14
这篇文章主要介绍cesium怎么在断网条件下进行开发和调试,具体内容包括地图与地形的下载,切片和部署。最后会在断网条件下进行初始cesium。
npm link本地测试React组件库报错“Invalid hook call”?从多实例到pnpm依赖的完整排查指南
2025年5月17日 16:58
npm link到本地测试时,遇到了报错:Warning: Invalid hook call,经过多轮排查,最终发现到React多实例冲突与pnpm对peerDependencies的隐式安装是关键
Koa2 跨域实战:`withCredentials`场景下响应头配置全解析
2025年5月17日 16:51
在withCredentials场景下,Koa2 通过动态源校验、中间件封装及安全策略配置,可有效解决跨域凭证携带问题。核心原则是:严格限制允许的源,避免滥用通配符,始终遵循最小权限原则。通过结合环境
React 闭包陷阱攻防:函数式编程思想的应用
2025年5月17日 16:43
在 React 开发中,闭包陷阱是一个常见且令人头疼的问题。当我们在 `useEffect`、`us
大学生常用-原生js实现:点击切换图片,轮播图,tab切换,分页符,秒杀等等......直接copy就能使
2025年5月17日 16:38
本文详细介绍了多种前端开发中常见的功能实现,涵盖了交互组件、表单处理、数据存储、动态内容处理、实用工具、用户体验优化和视觉效果等多个方面。具体内容包括轮播图、Tab切换、模态框、下拉菜单、手风琴效果、
JS进阶-异步编程、跨域、懒加载
2025年5月17日 16:29
本文主要介绍了异步编程、跨域问题和懒加载技术。在异步编程部分,详细解释了其基本概念、事件循环机制、JavaScript中的常见实现方式(如回调函数、Promise、async/await)以及最佳实践
Agentic Loop与MCP:大模型能力扩展技术解析
2025年5月17日 16:22
MCP(Model Context Protocol)是一种用于大语言模型与外部工具交互的协议框架。它允许大语言模型能够调用各种外部工具来扩展其能力边界,如访问文件系统、搜索引擎、数据库等。
Flutter中的Key详解
2025年5月17日 16:21
在 Flutter 开发中,Key 是一个经常被提及但又容易被忽视的概念。它在 Widget 树的更新和状态管理中扮演着至关重要的角色。本文将详细介绍 Flutter 中 Key 的作用、类型、常见使
你以为你很忙,其实你只是在拼命挖坑
2025年5月17日 16:15
很多开发者以为自己很忙,实则陷入了低效的重复劳动。通过搜索区、表格、编辑等场景,深度剖析封装误区与进阶策略,强调从组件到系统能力的跃迁,重构重复逻辑,提升协作效率,实现从页面能力到系统建设力的转变。
UniApp组件开发七日通-单元格
2025年5月17日 16:13
`h-cell` 是一个基于 Vue 3 的跨端单元格组件(适用于 uni-app 框架),主要用于展示列表项信息。支持标题、图标、右侧内容、箭头指示和下边框等功能。
纯血鸿蒙开发之广告服务(1)
2025年5月17日 15:43
前言 大家好,我是青蓝逐码的云杰,今天我想来聊一聊学习一下鸿蒙的广告服务! Ads Kit(广告服务) Ads Kit(广告服务)依托华为终端平台与数据能力为您提供流量变现服务,帮助您解决流量变现的难