普通视图

发现新文章,点击刷新页面。
今天 — 2025年12月21日首页

湖南:前11个月规模以上工业增加值同比增长6.1%

2025年12月21日 12:07
湖南省统计局近日发布的全省经济运行数据显示,1至11月,全省规模工业增加值同比增长6.1%,工业经济展现出稳健发展的韧性与活力。装备制造业表现突出。1至11月,全省装备制造业增加值同比增长9.3%,拉动规模工业增长3.1个百分点;航空航天器及设备制造业、电子及通信设备制造业,分别增长18%、16.8%。智能产品市场活跃,规模工业企业新能源汽车、光电子器件产量均实现约四成增长,服务机器人、传感器的产量分别增长33.4%、21.8%。(证券时报)

美飞行器成功发射,搭载“轮椅使用者”进入太空

2025年12月21日 11:49
美国蓝色起源公司的“新谢泼德”飞行器20日在一次载人太空飞行中,把6名乘员送入太空,其中包括一名截瘫女性,她也成为首名进入太空的“轮椅使用者”。美国中部时间20日8时16分许(北京时间20日22时16分许),“新谢泼德”飞行器从得克萨斯州西部一处发射场升空,到达距地面约100千米处的地球亚轨道后与运载火箭分离,自主飞行数分钟后在降落伞缓冲下返回地面。整个飞行过程持续约10分钟。(新华社)

乐乐茶致歉:核査全国门店苹果糖系列出品,不符合标准的产品立即下架

2025年12月21日 11:29
36氪获悉,乐乐茶发布致歉声明:12月19日上午,我们陆续收到来自多家门店顾客和线上平台的反馈,主要集中在以下几个问题:1.杯中的苹果没有裹上糖;2.裹糖太少,苹果容易氧化;3.糖裹得太厚,口感过粘;4.糖浆温度过高,导致苹果颜色变深;5.顶部装饰漏放或摆放不标准。收到反馈后,我们第一时间全面核査了全国门店的苹果糖系列出品。不符合标准的产品已立即下架,相关门店已责令立即整改,并对出品严重不符的门店进行了严厉处罚。目前全国门店苹果糖系列陆续恢复上架。

韩国监管机构:已准备好采取先发制人措施稳定市场

2025年12月21日 11:14
韩国金融服务委员会主席Lee Eog-weon周日在电视采访中表示,若有需要,韩国随时准备采取先发制人措施,以稳定金融市场。Lee指出,目前市场对债券收益率上升及汇率波动保持警惕,但他强调,韩国金融体系的稳健性及危机应对能力均无重大问题。此前周五,受韩元持续走弱引发通胀担忧影响,韩国央行已宣布临时措施,旨在增加本土外汇市场的美元供给。(新浪财经)

JavaScript 列表转树(List to Tree)详解:前端面试中如何从递归 O(n²) 优化到一次遍历 O(n)

2025年12月21日 10:53

前言:Offer 是怎么没的?

在前端面试的江湖里,「列表转树(List to Tree)」 是一道妥妥的高频题。

很多同学一看到这道题,内心 OS 都是:

😎「简单啊,递归!」

代码写完,自信抬头。
面试官却慢悠悠地问了一句:

🤨「如果是 10 万条数据 呢?
👉 时间复杂度多少?
👉 会不会栈溢出?」

空气突然安静。

今天这篇文章,我们就把这道题彻底拆开:
从「能写」到「写得对」,再到「写得漂亮」。


一、为什么面试官总盯着这棵“树”?

因为在真实业务中,后端给你的几乎永远是扁平数据

例如:

const list = [
  { id: 1, parentId: 0, name: '北京市' },
  { id: 2, parentId: 1, name: '顺义区' },
  { id: 3, parentId: 1, name: '朝阳区' },
  { id: 4, parentId: 2, name: '后沙峪' },
  { id: 121, parentId: 0, name: '江西省' },
  { id: 155, parentId: 121, name: '抚州市' }
];

而前端组件(Menu、Tree、Cascader)要的却是👇

省
 └─ 市
     └─ 区

🎯 面试官的真实考点

  • 数据结构理解:是否真正理解 parentId
  • 递归意识 & 代价:不只会写,还要知道坑在哪
  • 性能优化能力:能否从 O(n²) 优化到 O(n)
  • JS 引用理解:是否理解对象在内存中的表现

二、第一重境界:递归法(能写,但不稳)

1️⃣ 最基础的递归写法

function list2tree(list, parentId = 0) {
  return list
    .filter(item => item.parentId === parentId)
    .map(item => ({
      ...item,
      children: list2tree(list, item.id)
    }));
}

逻辑非常直观:

  • 找当前 parentId 的所有子节点
  • 对每个子节点继续递归
  • 没有子节点时自然退出

三、进阶:ES6 优雅写法(看起来很高级)

如果你在面试中写出下面这段代码👇
面试官大概率会先点头。

const list2tree = (list, parentId = 0) =>
  list
    .filter(item => item.parentId === parentId)
    .map(item => ({
      ...item,              // 解构赋值,保持原对象纯净
      children: list2tree(list, item.id)
    }));

这一版代码:

  • ✅ 箭头函数
  • filter + map 链式调用
  • ✅ 解构赋值,不污染原数据
  • ✅ 可读性很好,看起来很“ES6”

👉 很多同学到这一步就觉得稳了。


🤔 面试官的经典追问

「这个方案,有什么问题?」


🎯 标准回答(一定要说出来)

「这个方案的本质是 嵌套循环
每一层递归,都会遍历一次完整的 list

👉 时间复杂度是 O(n²)
👉 如果层级过深,还可能导致 栈溢出(Stack Overflow) 。」

📌 一句话总结

ES6 写法只是“看起来优雅”,
性能问题不会因为代码好看就自动消失。


四、第二重境界:Map 优化(面试及格线)

既然慢,是因为反复遍历找父节点
那就用 Map 建立索引

👉 典型的:空间换时间


核心思路

  1. 第一遍:把所有节点放进 Map
  2. 第二遍:通过 parentId 直接挂载
  3. 利用 JS 对象引用,自动同步树结构

代码实现

function listToTreeWithMap(list) {
  const map = new Map();
  const tree = [];

  // 初始化
  for (const item of list) {
    map.set(item.id, { ...item, children: [] });
  }

  // 构建树
  for (const item of list) {
    const node = map.get(item.id);
    if (item.parentId === 0) {
      tree.push(node);
    } else {
      const parent = map.get(item.parentId);
      parent && parent.children.push(node);
    }
  }

  return tree;
}

⏱ 复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

📌 到这一步,已经可以应付大多数面试了。


五、终极奥义:一次遍历 + 引用魔法(Top Tier)

面试官:
「能不能只遍历一次?」

答案是:能,而且这才是天花板解法。


核心精髓:占位 + 引用同步

  • 子节点可能先于父节点出现
  • 先在 Map 里给父节点 占位
  • 后续再补全数据
  • 引用地址始终不变,树会“自己长好”

代码实现(一次遍历)

function listToTreePerfect(list) {
  const map = new Map();
  const tree = [];

  for (const item of list) {
    const { id, parentId } = item;

    if (!map.has(id)) {
      map.set(id, { children: [] });
    }

    const node = map.get(id);
    Object.assign(node, item);

    if (parentId === 0) {
      tree.push(node);
    } else {
      if (!map.has(parentId)) {
        map.set(parentId, { children: [] });
      }
      map.get(parentId).children.push(node);
    }
  }

  return tree;
}

🏆 为什么这是王者解法?

  • ✅ 一次遍历,O(n)
  • ✅ 支持乱序数据
  • ✅ 深度理解 JS 引用机制
  • ✅ 面试官一眼就懂你是“真会”

六、真实开发中的应用场景

  • 🔹 权限 / 菜单树(Ant Design / Element)
  • 🔹 省市区 / Cascader
  • 🔹 文件目录结构(云盘、编辑器)

七、面试总结 & 避坑指南

方案 时间复杂度 评价
递归 O(n²) 能写,但危险
Map 两次遍历 O(n) 面试合格
一次遍历 O(n) 面试加分

面试加分表达

  • 主动提 空间换时间
  • 点出 JS 对象是引用类型
  • 询问 parentId 是否可能为 null
  • 说明是否会修改原数据(必要时深拷贝)

结语

算法不是为了为难人,
而是为了在复杂业务中,
选出那条最稳、最优雅的路。

如果这篇文章对你有帮助👇
👍 点个赞
💬 评论区聊聊你在项目里遇到过的奇葩数据结构

海南三亚机场2025年旅客吞吐量创通航以来历史新高

2025年12月21日 10:53
三亚凤凰国际机场消息,2025年12月20日,海南三亚凤凰国际机场2025年旅客吞吐量突破历史峰值,创通航以来历史新高。截至12月20日,三亚机场2025年全年累计保障运输航班起降133599架次,旅客吞吐量2184.9万人次,货邮吞吐量11.3万吨,较去年同期增长7.0%、5.8%和16.3%。其中,旅客吞吐量创历史最高纪录,国际旅客量达89.5万人次,同比大幅增长46.6%,表现尤为亮眼,充分展现了自贸港的国际化吸引力。(央视新闻)

前端轮子(1)--前端部署后-判断页面是否为最新

2025年12月21日 10:18

前端轮子系列:

  1. 前端部署后-判断页面是否为最新
  2. 如何优雅diy响应数据
  3. 如何优雅进行webview调试
  4. 如何实现测试环境的自动登录

项目部署后:通知更新、强制刷新、自测访问的页面为最新代码(是否发版成功)
重点:自测、提测、修改bug后,确认访问的为最新页面

check-version.gif

实现思路

目的:生成新的版本标识,通过对比标识 ==> 当前为最新 还是 旧页面

  1. 生成版本号:如:1.1.10 ,或者时间戳(202512201416)
    • 自动化脚本生成
    • 手动控制
  2. 对比版本号:相等=> 当前为最新;不等 => 当前为旧页面
  3. 通过对比结果 对应处理产品逻辑 完事儿~

具体实现

方案一:生成时间戳,注入变量,控制台打印

在vue-cli项目中

通过vue.config.js 入变量
然后在main.js中打印变量

// main.js
console.log('__BUILD_TIME__', __BUILD_TIME__)
// vue.config.js
const _date = new Date()
const BUILD_TIME = _date.toLocaleString ? _date.toLocaleString() : _date.getTime()

module.exports = {
  configureWebpack: {
    plugins: [
      new webpack.DefinePlugin({
        __BUILD_TIME__: JSON.stringify(BUILD_TIME)
      })
    ]
  },
}

在vite项目中

通过vite.config.js 注入 BUILD_TIME 变量
然后在main.js中打印 BUILD_TIME 变量

// main.js
console.log('__BUILD_TIME__', __BUILD_TIME__)
// vite.config.js
const _date = new Date()
const BUILD_TIME = _date.toLocaleString ? _date.toLocaleString() : _date.getTime()
export default defineConfig(() => {
  return {
    define: {
      __BUILD_TIME__: JSON.stringify(BUILD_TIME)
    },
  }
})

这种方案,实现了在控制台打印。但是对于生产环境,无法做到版本号的对比
为啥? 因为上线 一般会去掉日志的打印, 所以咱通过版本号来~

方案二:记录版本号,轮询对比版本号

  1. 编写生成版本号的脚本,生成版本号文件
  2. build结束,调用脚本去生成版本号文件
  3. 轮询对比版本号文件,如果版本号不一致,做相应操作
// dist/version.json
{
  "buildTime": "2025-12-20 14:16:00"
}

prebuild: build前执行的脚本
postbuild:build结束后执行的脚本,用于生成版本号文件

// package.json
{
  "scripts": {
    "postbuild": "node scripts/generate-version-dist.mjs"
  }
}
// scripts/generate-version-dist.mjs
import { writeFile } from 'node:fs/promises'
import path from 'node:path'
import { fileURLToPath } from 'node:url'

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const root = path.resolve(__dirname, '..')


async function main() {
  const _date = new Date()
  const BUILD_TIME = _date.toLocaleString ? _date.toLocaleString() : _date.getTime()

  const outPath = path.join(root, 'dist', 'version.json')
  await writeFile(outPath, JSON.stringify({ BUILD_TIME }, null, 2) + '\n', 'utf-8')

}

main().catch((e) => {
  console.error('[generate-version] failed', e)
  process.exit(1)
})

轮询对比版本号

  1. 轮询对比版本号文件,如果版本号不一致,做相应操作
  2. 页面隐藏、切后台时,停止轮询,页面关闭时,停止轮询
  3. 页面显示、切前台时,开始轮询
// main.js
import { createVersionPoller } from './utils/versionPoller'
createVersionPoller({
  versionUrl: '/version.json',
  storageKey: '__VERSION_CHECK__CURRENT_BUILD_TIME__',
  intervalMs: 15_000,
  maxDelayMs: 60_000,
  onResult: ({ remoteVersion, remoteBuildTime }) => {
    // 轮询到json文件 成功,额外处理逻辑
  },
  onError: (e) => {
    // 轮询失败,额外处理逻辑
  },
  onUpdate: () => {
    // 版本号不一致,需要更新,额外处理逻辑
  }
}).start()


/**
 * 轮询 /version.json,对比 buildTime 判断是否需要更新(setTimeout + 错误指数退让)
 *
 * 行为说明:
 * - start() 会自动注册监听:visibilitychange / beforeunload / unload
 * - stop() 会清理定时器并卸载监听
 * - 请求失败会指数退让(delay *= 2,最大不超过 maxDelayMs);成功后恢复 intervalMs
 * - currentBuildTime 会写入 localStorage(storageKey)
 *
 * @param {Object} options
 * @param {string} [options.versionUrl='/version.json'] 版本文件地址
 * @param {string} [options.storageKey='__VERSION_CHECK__CURRENT_BUILD_TIME__'] localStorage key
 * @param {number} [options.intervalMs=15000] 正常轮询间隔(毫秒)
 * @param {number} [options.maxDelayMs=60000] 退让最大间隔(毫秒)
 * @param {(info:{localBuildTime:string,remoteBuildTime:string,remoteVersion:string,data:any})=>void} [options.onResult] 每次成功拉取后的回调
 * @param {(error:any)=>void} [options.onError] 拉取失败回调
 * @param {(info:{localBuildTime:string,remoteBuildTime:string,remoteVersion:string,data:any})=>void} [options.onUpdate] 发现新 buildTime 时回调(默认会 stop)
 */
export function createVersionPoller({
  versionUrl = '/version.json',
  storageKey = '__VERSION_CHECK__CURRENT_BUILD_TIME__',
  intervalMs = 15000,
  maxDelayMs = 60000,
  onResult,
  onError,
  onUpdate
} = {}) {
  let timer = null
  let stopped = true
  let delayMs = intervalMs
  let bound = false

  const readLocal = () => window.localStorage.getItem(storageKey) || ''
  const writeLocal = (v) => v && window.localStorage.setItem(storageKey, String(v))

  function clear() {
    if (!timer) return
    window.clearTimeout(timer)
    timer = null
  }

  function isVisible() {
    return document.visibilityState !== 'hidden'
  }

  async function fetchRemote() {
    const sep = versionUrl.includes('?') ? '&' : '?'
    const url = `${versionUrl}${sep}t=${Date.now()}`
    const res = await fetch(url, { cache: 'no-store', headers: { 'Cache-Control': 'no-cache' } })
    if (!res.ok) throw new Error(`fetch ${versionUrl} failed: ${res.status}`)
    return await res.json()
  }

  async function tick() {
    if (stopped || !isVisible()) return

    const localBuildTime = readLocal() || ''

    try {
      const data = await fetchRemote()
      const remoteVersion = String(data?.version || '')
      const remoteBuildTime = String(data?.BUILD_TIME || '')

      delayMs = intervalMs
      onResult?.({ localBuildTime, remoteBuildTime, remoteVersion, data })

      console.log( remoteBuildTime , '=>', localBuildTime)

      if (remoteBuildTime && remoteBuildTime !== localBuildTime) {
        // 记录最新 buildTime,避免重复提示同一个更新
        writeLocal(remoteBuildTime)
        onUpdate?.({ localBuildTime, remoteBuildTime, remoteVersion, data })
      }
    } catch (e) {
      delayMs = Math.min(maxDelayMs, Math.max(500, delayMs * 2))
      onError?.(e)
    }

    timer = window.setTimeout(tick, delayMs)
  }

  function onVisibilityChange() {
    if (stopped) return
    if (!isVisible()) return clear()
    clear()
    timer = window.setTimeout(tick, 0)
  }

  function ensureBound() {
    if (bound) return
    bound = true
    document.addEventListener('visibilitychange', onVisibilityChange)
    window.addEventListener('beforeunload', stop)
    window.addEventListener('unload', stop)
  }

  function ensureUnbound() {
    if (!bound) return
    bound = false
    document.removeEventListener('visibilitychange', onVisibilityChange)
    window.removeEventListener('beforeunload', stop)
    window.removeEventListener('unload', stop)
  }

  function start() {
    if (!stopped) return
    stopped = false
    delayMs = intervalMs
    ensureBound()
    if (isVisible()) timer = window.setTimeout(tick, 0)
  }

  function stop() {
    stopped = true
    clear()
    ensureUnbound()
  }

  return { start, stop }
}

注意点

  • 轮询版本文件,拼 时间戳、设置请求头 避免命中缓存
  • 轮询版本文件,时间间隔不要太短,耗费网络,虽然已经做了轮询指数退让
  • 生成的版本文件 生成到dist下 注意访问路径
  • 版本号需要上传到git,需要手动执行脚本&commit + push

源码

xiaoyi1255

结语

如果本文对你有收获,麻烦动动发财的小手,点点关注、点点赞!!!👻👻👻

因为收藏===会了

如果有不对、更好的方式实现、可以优化的地方欢迎在评论区指出,谢谢👾👾👾

融资丨朗毅机器人连续完成两轮数千万元融资

近日,全球领先的具身导航大脑服务商——朗毅机器人宣布完成数千万元天使+轮融资。继今年7月完成天使轮融资后,半年内朗毅机器人再次获得资本市场青睐。天使轮和天使+轮融资已陆续引入英诺天使基金、嘉道资本、光谷金控、江阴人才基金、奇绩创坛等知名机构投资,不仅为朗毅机器人注入“资金活水”,更凭借多方投资方的产业资源协同,为其具身导航技术的规模化落地按下“加速键”。

两轮融资资金将重点聚焦具身导航模组的研发与量产、空间智能算法的升级迭代、多场景规模化拓展,以及与头部机器人厂商的生态共建升级,全力推动机器人从“功能演示”向“全自主实用”跨越。朗毅的具身导航模组已适配多款具身机器人,成功落地工业制造、安防巡检、商业服务等多元场景。

技术迭代升级,空间智能不断突破

朗毅机器人是全球首个实现人形机器人自主导航方案的企业,持续升级迭代空间智能算法,不断提高技术壁垒。

全球首个实现人形机器人自主导航方案:在2024年,朗毅机器人既已推出30余个自由度的全尺寸人形的全自主导航系统,攻克了震动剧烈、算力有限、自由度多、延迟大、非线性极强等系统难点,当人形机器人普遍被质疑为“遥控玩具”之际,朗毅成为业内首家实现人形机器人彻底摆脱遥控器的核心供应商,该技术优势持续领跑全球。

生态协作,行业市占率第一,场景广度第一:朗毅机器人秉持生态共建理念,已与数十家头部机器人本体厂商达成深度合作,实现商业化落地。朗毅推出的软硬件一体具身导航模组——灵睛智能感知导航系统,不仅体积小、场景适应性极强,适配速度更仅需1-3日。在2025WRC(世界机器人大会)与2025WAIC(世界人工智能大会)上,朗毅的灵睛智能感知导航系统已成为多家参展企业的核心技术支撑,其技术实力在现场静态及动态展示中充分彰显。目前,朗毅正与合作伙伴开展场景落地深度联动,确保技术迭代与行业需求实时同频,充分展现出在室内、室外、商业场景、工业厂区等多类场景下的超强适用性,场景覆盖广度与核心产品市占率均稳居行业第一。得益于朗毅行业头部的技术实力,央视对朗毅机器人进行了多次关注和报道。

唯一全自主跑步亮相机器人运动会队伍:在备受瞩目的首届世界机器人运动会上,朗毅机器人作为开幕式上唯一全自主跑步的队伍闪耀亮相。依托纯视觉端到端导航方案,朗毅机器人全自主完成100米、400米、1500米竞赛项目,最终在1500米决赛中斩获团队第三名。这一成绩,充分展现出朗毅灵睛智能感知导航系统业界领先且经得起严苛现场考验的核心实力。

场景规模化落地,从“单点验证”到“多行业复制”

依托技术升级与资本加持,朗毅机器人的具身导航模组——灵睛智能感知导航系统已从“工业试点”走向“多行业规模化落地”,覆盖四大核心场景,成为人形机器人厂商的“标配选择”。

工业制造场景:朗毅具身导航模组已部署于多家工厂和仓储基地,支持机器人24小时连续自主导航与搬运作业,大幅提升生产效率与自动化水平。

安防巡检场景:配备具身导航模组的人形机器人依托高通过性和空间交互能力,已在高价值、高风险环境完成安全巡检与操作任务,有效减少人力安全隐患,降低安全成本。

公共服务场景:在多个景区、商场与展览厅投入使用的人形机器人,凭借流畅的导航与环境交互,承担导览讲解及引导服务,提升了公共服务的交互性、客户体验和效率。

家庭陪护方向:朗毅正积极探索智能陪护机器人市场,致力于构建家庭及养老场景的关键基座设施,推动机器人规模化进入千家万户。

95后博士团队掌舵,以“导航大脑”推动人形机器人成为“通用劳动力”

朗毅的快速成长,离不开一支“懂技术、懂产业、有信仰”的核心团队。公司核心成员均毕业于华中科技大学、香港理工大学、电子科技大学、浙江大学等知名高校,研发人员比例高达75%,累计拥有十年以上空间智能算法与机器人产品开发经验;工程团队更有华为、大疆等企业背景,具备从算法到量产的快速转化能力。

创始人兼CEO杨鸿城(华中科技大学人工智能博士)表示:“人形机器人的终极使命是成为‘通用劳动力’,而空间智能就是实现这一目标的‘神经中枢’。半年两轮融资不是终点,而是新起点——我们将继续聚焦‘场景→数据→模型’技术闭环,让机器人不仅能‘自主走’,还能‘懂场景、会沟通、会做事’,真正成为人类的得力伙伴。”

未来,朗毅机器人将以具身导航技术为核心,深化与产业链上下游的合作,持续推动人形机器人在更多场景实现规模化落地,为具身智能时代筑牢“导航基础设施”,让每一台机器人都能畅行世界。

查看更多项目信息,请前往「睿兽分析」。

油电共存、小车称王、比亚迪退守,2025 卖得最好的 20 辆车,和你想的不一样

作者 芥末
2025年12月21日 10:00

如果要为 2025 年的车市选一个关键词,那么「重塑」或许最为贴切。

新能源渗透率已越过高速增长拐点,市场进入结构性调整阶段,不再是所有玩家都能分一杯羹的增量时代,而是优胜劣汰的存量竞争。无论车企宣传多么天花乱坠,最终都要靠销量兑现。

董车会统计了 2023 年、2024 年及 2025 年前 11 个月销量超过 18 万辆的车型,发现三年间榜单变动剧烈,有品牌快速崛起,也有曾经的头部选手掉出前列。这背后,是产品力、定价策略、渠道效率乃至组织反应速度的全面比拼。

▲ 2025 年 1-11 月各车型销量排名

而这场重塑中最引人注目的信号,莫过于来到榜首位置的,不是特斯拉也不是比亚迪,而是一辆强势崛起的小车。

失去榜首的比亚迪

过去两年,国内新能源汽车销量榜首之争主要在特斯拉 Model Y 与比亚迪秦 PLUS 之间展开。Model Y 凭借其全球统一的产品力与品牌号召力,稳居第一梯队——2023 年售出 45.6 万辆,2024 年进一步提升至 48 万辆;而比亚迪则以「车海战术」全面出击,旗下秦、宋、元、海豚、海鸥等多款车型齐头并进,在 2024 年巅峰时期一举包揽销量 Top 10 中的五个席位,几乎占据半壁江山。

然而,进入 2025 年,格局骤变。吉利星愿以 44.6 万辆的成绩空降榜首,星越 L 与博越 L 也稳居榜单前列。作为老牌自主车企,吉利在经历转型阵痛后,凭借高性价比的小型与紧凑型产品成功反攻,一举打破了比亚迪此前近乎垄断的市场地位。

曾长期称霸该细分市场的海鸥与海豚,在 2023–2024 年合计贡献了可观销量,但到了 2025 年,二者双双失守。

海鸥销量跌至 34.1 万辆,排名滑落至第五;海豚更是一路下滑至第 32 位。与此同时,吉利星愿以更大空间、更精致的设计以及更具竞争力的配置,在同价位区间精准狙击了这两款比亚迪「走量利器」。

▲ 比亚迪海鸥

雪上加霜的是,曾经的旗舰轿车汉,也悄然消失在销量榜单之中。

2024 年尚能卖出 22.8 万辆的汉,2025 年销量几近腰斩,仅录得 13.7 万辆。面对小米 SU7(27.2 万辆)、特斯拉 Model 3(19.3 万辆)以及极氪、领克等新老对手的围剿,老款「汉」的产品力已显疲态;而改款后的新车型,无论在设计语言还是核心体验上,都未能赢得市场广泛认可,销量表现可谓惨淡。

海鸥

但也有好消息。

秦 L(第 8 名,27.8 万辆)和海豹 06(第 14 名,23 万辆)这两款更新的车型成功完成了迭代,稳固住了其在 10-15 万级轿车市场的基本盘。

▲比亚迪海豹 06  DM—i

旗下高端品牌腾势 D9 和方程豹钛 7 也表现出了不错的爆款潜力。

明年的比亚迪,如何在前后夹击的态势下稳住份额,相当值得期待。

吉利,成功渡劫

在一众合资品牌及传统自主品牌(如长城、长安、上汽)被比亚迪打得节节败退之际,吉利出手了。

此前两年,吉利在新能源销量榜上表现平平。然而到了 2025 年,局面彻底改写,吉利不仅一举夺得年度销冠,其星越 L 与博越 L 更强势稳居榜单前列,彰显出在紧凑型 SUV 领域的全面统治力。

▲ 销冠星愿

吉利已成为目前唯一一家在燃油车与新能源两大赛道均跑赢行业大盘的传统车企。

尽管在新能源转型上起步较晚,且早期一度犹豫不决,但吉利的转身不可谓不坚决。早在 2015 年,吉利便提出「蓝色行动」战略,雄心勃勃地设下到 2020 年实现新能源车型销量占比达 90% 的目标。

然而到 2020 年之时,吉利实际的新能源车销量占比却只有 5.2%。

真正促使吉利下定决心的,是比亚迪与理想等新势力在混动与增程赛道上的爆发式成功。自此,吉利果断修订原战略,推出升级版「蓝色吉利行动计划」,全面押注节能技术(涵盖燃油、混动、增程)与智能纯电双线并进。

之后比亚迪的每个爆款吉利几乎都做了对标,银河 L6 对标秦 PLUS DM-i,银河 E8 对标汉 EV,银河 E5 对标元家族,星舰 7 则瞄准了宋 Pro DM-i,星愿则对标海豚和海豹两款小车。

▲ 吉利银河 E8

产品矩阵上如此,技术竞争上同样如此。

2024 年 5 月,比亚迪发布第五代 DM-i 技术,以 46.06% 的量产发动机热效率刷新纪录;仅半年后,吉利便在银河星舰 7 上搭载全新 EM-i 雷神混动系统,以 46.5% 的热效率反超对手,重夺技术制高点。

今年 2 月,比亚迪宣布旗下 21 款车型全部搭载「天神之眼」辅助驾驶系统,仅在 1 个月之后,吉利就宣布银河系列的后续车型都将搭载「千里浩瀚」不同层级的辅助驾驶方案。

吉利的策略简单而高效,配置多一点、设计好一点、价格再低一点,期望用用极致的性价比与快速迭代能力,逐个击破比亚迪的主力车型。

星愿登顶销冠,或许只是吉利全面反攻的序章。

消失的埃安

对比三年的销量,有一个品牌的变化非常明显:广汽埃安。

2023 年,埃安尚处在高光时刻。AION Y 以 23.5 万辆的成绩位列第 12 名,AION S 也以 22 万辆紧随其后(第 15 名),两款车型共同撑起了品牌在主流市场的存在感。然而到了 2024 和 2025 年,这两款曾经的主力车型却彻底从销量榜上消失,再无踪影。

除了车型老化的问题外,背后更多折射出来的是 10-15 万级纯电市场的逻辑变了。2023 年,该细分市场仍由大量 B 端需求(尤其是网约车)托底;而进入 2024–2025 年后,随着比亚迪、吉利银河等兼具设计感、智能化与家庭属性的新车型密集入场,那些缺乏 C 端吸引力、仅具「工具属性」的纯电动车迅速被边缘化。

数据印证了这一趋势。据乘联会统计,2023 年全国用于出租及网约车的新车销量达 85 万辆,其中埃安贡献约 22 万辆,占其全年总销量的 45%,也占当年网约车新增总量的近四分之一。然而,随着网约车市场快速饱和,B 端订单锐减,埃安失去了最重要的销量支柱,市场表现随之急转直下。

▲ 2025 年 11 月埃安各车型销量

面对困局,埃安曾试图通过向上突破来寻找出路。他们推出了高端品牌「昊铂」,陆续布局了昊铂 GT、SSR、HT 等车型。

但高端品牌的建设本就依赖长期技术积累、用户信任与体系化运营,而彼时的埃安显然准备不足。结果,昊铂系列多数月份销量仅百辆上下,市场反响平平,不仅未能打开新局面,反而分散了本应用于主品牌的资源,导致埃安在 15 万元左右的核心价位段产品力停滞不前,尤其在智能化配置上明显落后于竞品。

所幸,埃安在今年终于意识到战略偏差。随着昊铂品牌正式独立运营,埃安得以重新聚焦主品牌,将研发、产品、渠道与营销资源全面回调。业内消息显示,公司内部已启动一轮深度调整,从组织架构到产品定义,从技术路线到用户运营,均在进行系统性「换血」。

最近几款新车的产品力都很能打,如 9 月份推出的埃安 RT 就以 9.98 万元起的亲民价格提供了十分越级的体验。市场反馈也比以往热烈了不少。

但究竟效果如何,只能明年再看了。

燃油车最后的堡垒

我们一直以来通常认为燃油车在溃败,表面上看,电动化浪潮席卷一切,但细看销量数据,会发现一个反直觉的现象,2023 年,两款车型全年销量分别约为 19 万辆和 18.9 万辆;而到了 2025 年前 11 个月,帕萨特已售出 23.8 万辆,迈腾也达到 20.2 万辆。是榜单上极少数还能维持 20 万+年销量的合资 B 级车。

▲ 上汽大众帕萨特近一年销量走势 数据来源:车主之家

大众精准捕捉到了那些对新技术持谨慎态度、更看重可靠性与使用确定性的「保守派」用户。

面对价格战与电动化的双重压力,上汽大众和一汽-大众选择了一条务实路径——大幅降价、配置拉满、强化信任。

帕萨特部分车型终端售价已下探至 13 万元区间,IQ.Drive 智驾系统、自动泊车、全景影像等以往只属于高配车型的配置,也开始下放到中低配车型上。

整个合资阵营虽在新能源冲击下整体承压,却并未全面崩盘,而是退守到自己最擅长的细分市场

日系的轩逸、RAV4 荣放和凯美瑞的销量确实较巅峰时期有所下滑,但依然稳居各自细分榜单前列。

这些车型的共同点在于,它们早已完成产品心智的沉淀,即便在智能化和加速性能上落后于新势力,它们在油耗、保值率、维修便利性和长期使用成本上的优势,依然对三四线城市用户家庭第二辆车等特定群体构成强大吸引力。尤其是在充电基础设施尚未完全覆盖的区域,燃油车仍是无可替代的实用工具。

▲一汽丰田 RAV4

市场的真相或许比「电替代油」的简单叙事复杂得多。未来几年,中国汽车市场大概率不会走向单一技术路线的垄断,而是进入一个油电长期共存、各取所需的多元阶段——电动化是方向,但燃油车仍有活路

特斯拉 Model Y,铁杆盘稳固,但已到天花板

回顾特斯拉 Model Y 在中国市场近三年的销量,始终在 45 万至 48 万辆的区间内震荡。即便面对问界 M7、理想 L6 L7、小米 YU7 等强劲新势力车型的轮番冲击,甚至在价格战愈演愈烈的背景下,Model Y 的销量曲线依然异常平直——既未大幅下滑,也未显著上扬。

Model Y 在中国似乎已经形成一个高度稳定的「铁杆用户群」。这部分消费者对品牌高度认同,对产品性能、智能化体验或特斯拉生态有强烈偏好,其购买决策几乎不受外部竞争或短期促销影响。无论市场如何喧嚣,他们始终是 Model Y 最可靠的销量基石。

▲特斯拉 Model Y 近一年销量走势 数据来源:车主之家

然而,这种稳定性或许也说明 Model Y 的增长已经到达了天花板。

自 2021 年国产以来,Model Y 在核心设计、三电系统和智能座舱架构多年未有颠覆性更新。尽管特斯拉通过软件迭代和推出特供车型来维持竞争力,但增量空间极其有限。

正因如此即便 Model Y 本身并未「变弱」,它也在 2025 年让出了年度销冠的位置。取而代之的是星愿这类主打高性价比、精准切入大众市场的车型。

Model Y 的销量波动,或许也是中国新能源产品不断演进的缩影。特斯拉已经完成了「鲶鱼」的历史使命,若无下一代产品或重大技术突破,Model Y 很可能长期徘徊在 45–50 万辆/年的「稳态区间」,成为一座坚固但不再扩张的孤岛。

▲ 特斯拉 Model YL 座舱内部

绕不开的小米 SU7

小米 SU7 和特斯拉 Model Y 是销量榜前十中唯二的平均售价在 20 万元以上高端车型。

曾经中国家庭用户的首选永远是 SUV,在 SU7 出现之前,纯电轿车被认为是一个上限不高的细分市场。

如蔚来 ET5、小鹏 P7 等车型都曾在细分市场都遇到了「月销 1 万」的的隐形墙,但小米 SU7 把年销量做到了 27 万辆,月均 2 万以上,证明了纯电轿车可以不仅是「代步工具」,更可以成为像 iPhone 一样的「科技时尚单品」。

另一个有象征意义的数据是,小米 SU7 今年的总销量超越了特斯拉 Model 3(19.3 万辆)。

Model 3 上市多年,虽然经历了改款,但在中国消费者眼中,它已经越来越像一个「标准化的纯电车」。它很强,但缺乏新鲜感和情绪价值。

而小米 SU7 在 Model 3 建立的「极简+操控」的基础上,做了两件 Model 3 做不到的事——「互联互通」和「配置堆料」。

中国消费者虽然认可特斯拉的品牌,但如果能用同样甚至更低的价格,买到更大的空间、更好的内饰、更本土化的智能生态,他们会毫不犹豫地倒戈。

小米 SU7 实际上是吃掉了 Model 3 增长停滞后的溢出份额,并抢夺了那些原本还在犹豫是否购买特斯拉的摇摆用户。

过去年轻人的第一台「体面车」通常是 34C,而现在,在马力变得廉价之后,开一辆「科技属性」更强的小米,比开一辆丐版「宝马 3 系似乎更能代表」现代生活方式。

问界,突破 BBA 的护城河

如果把榜单往后再翻几页,我们还能看到另一个有意思的现象。

在 40 万元以上,且年销能超过 10 万辆的高端豪华车市场,能和 BBA 掰手腕的国产品牌,依旧只有问界。

如果单看 SUV 车型,问界 M8 以 13.3 万辆的成绩超越了奥迪 Q5L 的 11.9 万辆,是过去一年卖得最好的豪华 SUV。

要理解问界的上位,首先要理解 BBA 等传统豪车护城河的消解。

在燃油车时代,BBA 的溢价逻辑是可感知的物理豪华感,V6/V8 发动机的轰鸣、毫秒级换挡的变速箱,底盘调教的厚重感,这些都是极高门槛的技术壁垒。

消费者为此买单,买的是这一套复杂的机械艺术品,以及随之而来的社会地位。那时候的「豪华」,是静态的展示,无论你开不开它,那个立在车头的 Logo 和车内的真皮实木都在彰显价值。

然而,电动化时代带来了一场残酷的「机械平权」。电机轻易地让 20 几万的车型拥有了过去百万级豪车的加速体验;空气悬架和 CDC 减震器的供应链下放,让底盘质感的差异被无限缩小。

当原本的稀缺资源变得廉价,传统豪车就出现了「价值真空」。 这正是问界切入的时刻,它没有在旧赛道上过多纠缠,而是通过智能化,建立了一套新的价值坐标系。

在旧时代,车是冷冰冰的工具,人必须去适应车,而在问界构建的体系里,车更像是一个有感知能力的智能终端。

鸿蒙座舱让车机像手机一样省心顺手,不需要你去适应机器,而乾崑智驾把安全从「耐撞」升维成了「避险」,能在关键时刻帮你踩停、替你挡灾,这种实实在在的「保命」能力,才是科技时代最高级的溢价。

系统能力之争

如果把这些品牌和车型放在一张更大的时间轴上看,会发现一个越来越清晰的事实:中国汽车市场已经从「技术路线之争」,进入了「系统能力之争」。

过去几年,电动化是唯一的主线,谁能更快「上电」,谁就能拿到红利。但当新能源渗透率越过拐点,技术不再是稀缺品,真正拉开差距的,开始变成三件事:对用户的理解深度、产品迭代的速度,以及组织执行的确定性。

比亚迪今年的转变是最好的例子。

比亚迪的下滑很大程度上在于它太早成功,也太早暴露了边界。当所有对手都学会用更低的价格、更精细的定位、更快的反应去拆解它的优势时,比亚迪需要重新回答一个问题:除了性价比,它还能用什么继续扩大用户池?

他们花了一整年找到的答案是「用户价值」。

他们为多款车型都增加了配置更高,价格更低的车型。升级点都集中在用户最关注的续航和舒适性的部分,像联动底盘、动力、座舱三大系统的定眩智能防晕车功能、与生态伙伴共同定制的宠物座椅和安全座椅配件都能让用户感知更强,用车舒适度更高。

简单点说就是尝试将技术转化为用户实实在在的体验。

市场营销学中有个经典的 4P 理论。

产品(Product)、价格(Price)、营销(Promotion)、渠道(Place)是四个决定销量的关键要素。

今天的中国车市,奖励的就是两点以上的长期稳定输出。

能把产品和价格同时做到极致的,才能吃下最大规模;能把产品和营销高度耦合的,才能制造现象级爆款;而三点、四点同时成立的玩家,才有资格谈「长期统治」。

未来几年,中国汽车市场不会有单一赢家,但一定会不断淘汰那些,只靠运气和红利活着的玩家。

#欢迎关注爱范儿官方微信公众号:爱范儿(微信号:ifanr),更多精彩内容第一时间为您奉上。

爱范儿 | 原文链接 · 查看评论 · 新浪微博


我国成功发射通信技术试验卫星二十三号

2025年12月21日 09:49
北京时间2025年12月20日20时30分,我国在文昌航天发射场使用长征五号运载火箭,成功将通信技术试验卫星二十三号发射升空,卫星顺利进入预定轨道,发射任务获得圆满成功。该卫星主要用于开展多频段、高速率卫星通信技术验证。此次任务是长征系列运载火箭的第618次飞行。(央视新闻)

具身智能老炮再获数亿融资,移动多臂机器人已批量工业落地|36氪首发

2025年12月21日 09:23

作者丨欧雪

编辑丨袁斯来

硬氪获悉,具身智能机器人公司飒智智能近期连续完成A++轮及A+++轮融资,累计金额达数亿元。我们总结了最新两轮融资信息和该公司几大亮点:

 

融资金额及领投机构

融资轮次:A++轮及A+++轮

融资金额:数亿元

投资方:海通开元和国元直投

资金用途:40%用于技术研发,30%用于海外市场拓展,15-20%用于智能制造产线建设,剩余用于流动资金补充

 

公司基本信息

成立时间:2018年

公司总部:上海

核心产品:单臂、双臂、四臂机器人;AMR移动机器人;

技术亮点:飒智智能自主研发的SAGE-OS机器人操作系统与一体化控制器SAGE-Brain,实现了从感知、决策、规划到控制的低延迟实时闭环,从根本上解决了传统工业自动化在柔性化、智能化方面的瓶颈。

在自主作业方面,公司构建了“本体智能-群体智能-规模化智能”三层技术体系,通过融合视觉、力学、语音等多模态感知实现复杂工件的识别与定位,并借助自研的VLAS大模型、底层运动控制算法与多臂协同规划,在动态工业环境下完成毫米级(±0.05mm)精度的装配与检测作业。

应用场景:在高端离散制造领域,可用于汽车零部件(如线束检测、精密装配、电驱制造、热交换器加工)、3C电子(如SMT飞达上下料、主板检测)、生物制药(无菌分拣、实验室自动化)等行业的柔性产线与智能化升级。

公司当前以汽车、电子等行业的头部制造企业为突破口,通过“抓龙头、立标杆、拓渠道”的策略实现规模化复制,并同步向新能源、高端食品药品等更广阔的工业场景拓展。

飒智智能四臂机器人(图源/企业)

 

市场体量

工业机器人市场正处于从“固定自动化”向“移动智能化”转型的关键阶段。从第三方行业报告看到,当前全球工业机器人市场规模已达千亿级,但传统机器人主要服务于仅占生产环节约30%的连续结构化场景。而占制造业70%的离散制造场景因对柔性化、智能化的高要求,自动化渗透率仍处于低位,构成了巨大的存量替代空间。

随着新能源汽车、高端电子等行业加速向“小批量、多品种”的柔性制造模式转型,对能够自主移动、多空间作业的智能机器人需求持续爆发。

 

公司业绩

飒智智能已实现多年盈利,近年来营收保持50%-120%的年增速,明年预期增长将达300%。公司当前年出货量约千台,产能正积极扩建,目标提升至5000台年产能。目前,公司已成功为理想汽车、强生、三菱等头部客户打造项目,并带动了广泛的中腰部客户拓展,形成了可复制的规模化增长路径。

 

团队背景

公司创始人兼CEO张建政为上海交通大学机器人方向博士,拥有21年研发经验,曾任职于全球工业机器人巨头发那科(FANUC),主导开发了国内首套应用于汽车行业的3D视觉手眼协调系统。团队其他核心成员也多曾在罗克韦尔自动化、ABB等自动化和机器人企业担任关键技术职务,平均从业年限超过15年。

 

创始人思考

硬氪:与传统的工业机器人相比,飒智的差异化优势在哪里?

张建政:传统机器人是固定式作业,适合连续生产,比如汽车焊接、喷涂。但现在新势力造车是混线生产,工艺每年都在迭代变化。况且整个制造业中离散制造占70%,需要多批量小品种的柔性作业,传统方式做不了。

我们判断,机器人要完全替代人,必须解决移动作业和多元多空间作业的问题。不是在固定地方干活,而是像人一样在智能化工厂的多个空间里干不同的事。这需要在开放、非结构化的场景下,自主辨识场景、规划路径、感知作业变化并调整作业效果。所以,我们的机会是用具备移动作业能力的具身智能机器人,在离散制造环节或连续多变环节替换掉固定机器人。本质上,我们和他们不是同一类产品,我们解决的是他们解决不了的问题。

硬氪:目前公司已经实现盈利,这是怎么做到的?

张建政:我们被很多投资者贴过标签——“唯一能盈利的工业智能机器人公司”。实际上,我们多年有净利润,也证明我们的商业模式是成立的。定价上,我们按“代替人工”来算,让客户用1.5到2年的工人工资回收机器人成本。技术上,我们自研操作系统和控制器,硬件不足算法补,模块化设计像搭乐高,成本更低。

硬氪:公司在技术和市场方面接下来有哪些具体的发展规划?

张建政:在技术方面,我们将重点推进“本体智能、群体智能、规模化智能”三大方向。我们计划明年发布新一代具身智能机器人,进一步提升机器人在复杂作业场景中的多任务协同能力。

在市场方面,我们将加快全球布局。目前海外收入占比已超过20%,未来目标提升至50%左右。我们正在加强东南亚、墨西哥、欧洲、中东等地区的本地化团队建设,建立销售、技术支持和服务中心。

 

投资人思考

海通开元表示:飒智智能在推进全球战略的同时,以其高超的技术能力和深厚的场景经验,其具身智能机器人已成功进入多家世界巨头客户的供应商体系,验证了其技术方案在真实工业场景中的可靠性与实用性,我们看好其在智能制造这一广阔蓝海中的技术领先优势和工程化落地能力。随着全球制造业向柔性化转型加速,飒智具身智能机器人将成为智能制造的核心生产力之一,为实体经济带来真正的效率革命。

世贸报告:人工智能到2040年或推动全球贸易增长近四成

2025年12月21日 09:16
世界贸易组织发布《2025年世界贸易报告》指出,在配套政策到位的情况下,人工智能有望通过提升生产率、降低贸易成本,到2040年将跨境货物和服务贸易额提高34%至37%,全球GDP增长12%至13%。报告强调,需弥合数字基础设施差距、加强技能培训,并保持开放、可预期的贸易环境,确保增长更具包容性。世贸组织总干事伊维拉表示,贸易可在让人工智能“惠及所有经济体”方面发挥关键作用。(新华社)

每日一题-删列造序 II🟡

2025年12月21日 00:00

给定由 n 个字符串组成的数组 strs,其中每个字符串长度相等。

选取一个删除索引序列,对于 strs 中的每个字符串,删除对应每个索引处的字符。

比如,有 strs = ["abcdef", "uvwxyz"],删除索引序列 {0, 2, 3},删除后 strs["bef", "vyz"]

假设,我们选择了一组删除索引 answer,那么在执行删除操作之后,最终得到的数组的元素是按 字典序strs[0] <= strs[1] <= strs[2] ... <= strs[n - 1])排列的,然后请你返回 answer.length 的最小可能值。

 

    示例 1:

    输入:strs = ["ca","bb","ac"]
    输出:1
    解释: 
    删除第一列后,strs = ["a", "b", "c"]。
    现在 strs 中元素是按字典排列的 (即,strs[0] <= strs[1] <= strs[2])。
    我们至少需要进行 1 次删除,因为最初 strs 不是按字典序排列的,所以答案是 1。
    

    示例 2:

    输入:strs = ["xc","yb","za"]
    输出:0
    解释:
    strs 的列已经是按字典序排列了,所以我们不需要删除任何东西。
    注意 strs 的行不需要按字典序排列。
    也就是说,strs[0][0] <= strs[0][1] <= ... 不一定成立。
    

    示例 3:

    输入:strs = ["zyx","wvu","tsr"]
    输出:3
    解释:
    我们必须删掉每一列。
    

     

    提示:

    • n == strs.length
    • 1 <= n <= 100
    • 1 <= strs[i].length <= 100
    • strs[i] 由小写英文字母组成

    从左到右贪心 + 优化(Python/Java/C++/Go)

    作者 endlesscheng
    2025年12月11日 11:29

    例如 $\textit{strs}=[\texttt{ac},\texttt{ad},\texttt{ba},\texttt{bb}]$,竖着看就是

    $$
    \begin{aligned}
    & \texttt{ac} \
    & \texttt{ad} \
    & \texttt{ba} \
    & \texttt{bb} \
    \end{aligned}
    $$

    第一列是升序,可以不删。

    • 如果删第一列,那么需要完整地比较第二列的四个字母是不是升序。
    • 如果不删第一列,那么对于第二列,由于 $\texttt{d}$ 和 $\texttt{a}$ 前面的字母不同,只看第一列的字母就能确定 $\texttt{ad} < \texttt{ba}$,所以我们不需要比较 $\texttt{d}$ 和 $\texttt{a}$ 的大小。此时第二列分成了两组 $[\texttt{c},\texttt{d}]$ 和 $[\texttt{a},\texttt{b}]$,只需判断组内字母是不是升序,而不是完整地比较第二列的四个字母。

    由此可见,当列已经是升序时,不删更好,后面需要比较的字母更少,更容易满足要求,最终删除的列更少。

    如果列不是升序,那么一定要删(否则最终得到的数组不是字典序排列)。

    优化前

    ###py

    class Solution:
        def minDeletionSize(self, strs: List[str]) -> int:
            n, m = len(strs), len(strs[0])
            a = [''] * n  # 最终得到的字符串数组
            ans = 0
            for j in range(m):
                for i in range(n - 1):
                    if a[i] + strs[i][j] > a[i + 1] + strs[i + 1][j]:
                        # j 列不是升序,必须删
                        ans += 1
                        break
                else:
                    # j 列是升序,不删更好
                    for i, s in enumerate(strs):
                        a[i] += s[j]
            return ans
    

    ###java

    class Solution {
        public int minDeletionSize(String[] strs) {
            int n = strs.length;
            int m = strs[0].length();
            String[] a = new String[n]; // 最终得到的字符串数组
            Arrays.fill(a, "");
    
            int ans = 0;
            next:
            for (int j = 0; j < m; j++) {
                for (int i = 0; i < n - 1; i++) {
                    if ((a[i] + strs[i].charAt(j)).compareTo(a[i + 1] + strs[i + 1].charAt(j)) > 0) {
                        // j 列不是升序,必须删
                        ans++;
                        continue next;
                    }
                }
                // j 列是升序,不删更好
                for (int i = 0; i < n; i++) {
                    a[i] += strs[i].charAt(j);
                }
            }
            return ans;
        }
    }
    

    ###cpp

    class Solution {
    public:
        int minDeletionSize(vector<string>& strs) {
            int n = strs.size(), m = strs[0].size();
            vector<string> a(n); // 最终得到的字符串数组
            int ans = 0;
            for (int j = 0; j < m; j++) {
                bool del = false;
                for (int i = 0; i < n - 1; i++) {
                    if (a[i] + strs[i][j] > a[i + 1] + strs[i + 1][j]) {
                        // j 列不是升序,必须删
                        ans++;
                        del = true;
                        break;
                    }
                }
                if (!del) {
                    // j 列是升序,不删更好
                    for (int i = 0; i < n; i++) {
                        a[i] += strs[i][j];
                    }
                }
            }
            return ans;
        }
    };
    

    ###go

    func minDeletionSize(strs []string) (ans int) {
    n, m := len(strs), len(strs[0])
    a := make([]string, n) // 最终得到的字符串数组
    next:
    for j := range m {
    for i := range n - 1 {
    if a[i]+string(strs[i][j]) > a[i+1]+string(strs[i+1][j]) {
    // j 列不是升序,必须删
    ans++
    continue next
    }
    }
    // j 列是升序,不删更好
    for i, s := range strs {
    a[i] += string(s[j])
    }
    }
    return
    }
    

    复杂度分析

    • 时间复杂度:$\mathcal{O}(nm^2)$,其中 $n$ 是 $\textit{strs}$ 的长度,$m$ 是 $\textit{strs}[i]$ 的长度。比较 $\mathcal{O}(nm)$ 次大小,每次 $\mathcal{O}(m)$。
    • 空间复杂度:$\mathcal{O}(nm)$。

    优化

    回顾前文的例子:

    $$
    \begin{aligned}
    & \texttt{ac} \
    & \texttt{ad} \
    & \texttt{ba} \
    & \texttt{bb} \
    \end{aligned}
    $$

    第一列升序,不删。由于 $\textit{strs}[1][0] < \textit{strs}[2][0]$,后续 $a[1] < a[2]$ 必定成立,所以不需要比较这两个字符串。对于其余相邻字符串来说,由于第一列的字母都一样,所以只需比较第二列的字母,无需比较整个字符串

    怎么维护需要比较的下标(行号)呢?可以用哈希集合,或者布尔数组,或者创建一个下标列表,删除列表中的无需比较的下标。最后一种方法最高效,我们可以用 27. 移除元素 的方法,原地删除无需比较的下标,见 我的题解

    ###py

    class Solution:
        def minDeletionSize(self, strs: List[str]) -> int:
            n, m = len(strs), len(strs[0])
            check_list = list(range(n - 1))
    
            ans = 0
            for j in range(m):
                for i in check_list:
                    if strs[i][j] > strs[i + 1][j]:
                        # j 列不是升序,必须删
                        ans += 1
                        break
                else:
                    # j 列是升序,不删更好
                    new_size = 0
                    for i in check_list:
                        if strs[i][j] == strs[i + 1][j]:
                            # 相邻字母相等,下一列 i 和 i+1 需要继续比大小
                            check_list[new_size] = i  # 原地覆盖
                            new_size += 1
                    del check_list[new_size:]
            return ans
    

    ###java

    class Solution {
        public int minDeletionSize(String[] strs) {
            int n = strs.length;
            int m = strs[0].length();
            int size = n - 1;
            int[] checkList = new int[size];
            for (int i = 0; i < size; i++) {
                checkList[i] = i;
            }
    
            int ans = 0;
            next:
            for (int j = 0; j < m; j++) {
                for (int t = 0; t < size; t++) {
                    int i = checkList[t];
                    if (strs[i].charAt(j) > strs[i + 1].charAt(j)) {
                        // j 列不是升序,必须删
                        ans++;
                        continue next;
                    }
                }
                // j 列是升序,不删更好
                int newSize = 0;
                for (int t = 0; t < size; t++) {
                    int i = checkList[t];
                    if (strs[i].charAt(j) == strs[i + 1].charAt(j)) {
                        // 相邻字母相等,下一列 i 和 i+1 需要继续比大小
                        checkList[newSize++] = i; // 原地覆盖
                    }
                }
                size = newSize;
            }
            return ans;
        }
    }
    

    ###cpp

    class Solution {
    public:
        int minDeletionSize(vector<string>& strs) {
            int n = strs.size(), m = strs[0].size();
            vector<int> check_list(n - 1);
            ranges::iota(check_list, 0);
    
            int ans = 0;
            for (int j = 0; j < m; j++) {
                bool del = false;
                for (int i : check_list) {
                    if (strs[i][j] > strs[i + 1][j]) {
                        // j 列不是升序,必须删
                        ans++;
                        del = true;
                        break;
                    }
                }
                if (del) {
                    continue;
                }
                // j 列是升序,不删更好
                int new_size = 0;
                for (int i : check_list) {
                    if (strs[i][j] == strs[i + 1][j]) {
                        // 相邻字母相等,下一列 i 和 i+1 需要继续比大小
                        check_list[new_size++] = i; // 原地覆盖
                    }
                }
                check_list.resize(new_size);
            }
            return ans;
        }
    };
    

    ###go

    func minDeletionSize(strs []string) (ans int) {
    n, m := len(strs), len(strs[0])
    checkList := make([]int, n-1)
    for i := range checkList {
    checkList[i] = i
    }
    
    next:
    for j := range m {
    for _, i := range checkList {
    if strs[i][j] > strs[i+1][j] {
    // j 列不是升序,必须删
    ans++
    continue next
    }
    }
    // j 列是升序,不删更好
    newCheckList := checkList[:0] // 原地
    for _, i := range checkList {
    if strs[i][j] == strs[i+1][j] {
    // 相邻字母相等,下一列 i 和 i+1 需要继续比大小
    newCheckList = append(newCheckList, i)
    }
    }
    checkList = newCheckList
    }
    return
    }
    

    复杂度分析

    • 时间复杂度:$\mathcal{O}(nm)$,其中 $n$ 是 $\textit{strs}$ 的长度,$m$ 是 $\textit{strs}[i]$ 的长度。
    • 空间复杂度:$\mathcal{O}(n)$。

    专题训练

    见下面贪心题单的「§1.4 从最左/最右开始贪心」。

    分类题单

    如何科学刷题?

    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站@灵茶山艾府

    ❌
    ❌