当前位置: 首页 > news >正文

2026华为OD面试题001:两个字符串间的最短路径问题

题目描述

给你两个字符串 A 和 B,比如A = "ABCABBA"B = "CBABAC"

想象一个棋盘,横轴是 A 的字符,纵轴是 B 的字符。从左上角(0, 0)走到右下角(m, n),每次只能往右、往下,或者斜着往右下走。

  • 往右走:消耗 B 的一个字符,代价 1。
  • 往下走:消耗 A 的一个字符,代价 1。
  • 斜着走:只有当前两个字符相同才能走,代价 1,但一下搞定两个方向。

问题是:从起点到终点的最短距离是多少?

讲个故事:小明的最短通勤路

小明住在(0, 0),公司在(m, n)。他有三条路可以选:

  • 平路:往东走一格,或者往南走一格,各花 1 块钱。
  • 捷径:如果路口招牌一样,可以走对角线,花 1 块钱但等于同时走了东和南。

小明当然想多走捷径。

能走多少条捷径?取决于 A 和 B 里有多少字符能按顺序对上。这就是最长公共子序列。

核心原理:为什么答案是 m + n - LCS?

这道题看着像在网格里找路,其实就是**最长公共子序列(LCS)**的换皮题。答案等于len(A) + len(B) - LCS(A, B)

假设我们找到了一条最长公共子序列,长度为L

  • 这 L 个字符可以走斜边,花 L 块钱。
  • A 还剩下m - L个字符,必须往下走,花m - L块钱。
  • B 还剩下n - L个字符,必须往右走,花n - L块钱。

总花费 =L + (m - L) + (n - L) = m + n - L

所以只要求出 LCS 长度,答案就出来了。

拿样例验证一下:A = "ABCABBA"长度 7,B = "CBABAC"长度 6,LCS 长度是 4(比如 “BABA” 或者 “CABA”)。最短距离就是7 + 6 - 4 = 9,和题目给的结果一致。

怎么求 LCS?

用动态规划。设dp[i][j]表示A[0..i-1]B[0..j-1]的最长公共子序列长度。

转移方程:

  • 如果A[i-1] == B[j-1]dp[i][j] = dp[i-1][j-1] + 1
  • 否则:dp[i][j] = max(dp[i-1][j], dp[i][j-1])

初始化:dp[0][j] = 0dp[i][0] = 0

代码实现

C 语言

#include<stdio.h>#include<stdlib.h>#include<string.h>intminPath(char*A,char*B){intm=strlen(A),n=strlen(B);int**dp=(int**)malloc((m+1)*sizeof(int*));for(inti=0;i<=m;i++){dp[i]=(int*)calloc(n+1,sizeof(int));}for(inti=1;i<=m;i++){for(intj=1;j<=n;j++){if(A[i-1]==B[j-1]){dp[i][j]=dp[i-1][j-1]+1;}else{dp[i][j]=dp[i-1][j]>dp[i][j-1]?dp[i-1][j]:dp[i][j-1];}}}intresult=m+n-dp[m][n];for(inti=0;i<=m;i++)free(dp[i]);free(dp);returnresult;}intmain(){charA[10005],B[10005];scanf("%s %s",A,B);printf("%d\n",minPath(A,B));return0;}

C++

#include<bits/stdc++.h>usingnamespacestd;intminPath(conststring&A,conststring&B){intm=A.size(),n=B.size();vector<vector<int>>dp(m+1,vector<int>(n+1,0));for(inti=1;i<=m;i++){for(intj=1;j<=n;j++){if(A[i-1]==B[j-1]){dp[i][j]=dp[i-1][j-1]+1;}else{dp[i][j]=max(dp[i-1][j],dp[i][j-1]);}}}returnm+n-dp[m][n];}intmain(){string A,B;cin>>A>>B;cout<<minPath(A,B)<<endl;return0;}

Java

importjava.util.Scanner;publicclassMain{publicstaticintminPath(StringA,StringB){intm=A.length(),n=B.length();int[][]dp=newint[m+1][n+1];for(inti=1;i<=m;i++){for(intj=1;j<=n;j++){if(A.charAt(i-1)==B.charAt(j-1)){dp[i][j]=dp[i-1][j-1]+1;}else{dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);}}}returnm+n-dp[m][n];}publicstaticvoidmain(String[]args){Scannersc=newScanner(System.in);StringA=sc.next();StringB=sc.next();System.out.println(minPath(A,B));}}

JavaScript

functionminPath(A,B){constm=A.length,n=B.length;constdp=Array.from({length:m+1},()=>newArray(n+1).fill(0));for(leti=1;i<=m;i++){for(letj=1;j<=n;j++){if(A[i-1]===B[j-1]){dp[i][j]=dp[i-1][j-1]+1;}else{dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);}}}returnm+n-dp[m][n];}// 输入处理constreadline=require('readline');constrl=readline.createInterface({input:process.stdin});rl.on('line',(line)=>{const[A,B]=line.trim().split(/\s+/);console.log(minPath(A,B));rl.close();});

Python

defmin_path(A,B):m,n=len(A),len(B)dp=[[0]*(n+1)for_inrange(m+1)]foriinrange(1,m+1):forjinrange(1,n+1):ifA[i-1]==B[j-1]:dp[i][j]=dp[i-1][j-1]+1else:dp[i][j]=max(dp[i-1][j],dp[i][j-1])returnm+n-dp[m][n]A,B=input().split()print(min_path(A,B))

空间优化(进阶)

如果你发现内存不够,可以用滚动数组把空间复杂度压到O(min(m, n))

defmin_path_optimized(A,B):iflen(A)<len(B):A,B=B,A m,n=len(A),len(B)prev=[0]*(n+1)curr=[0]*(n+1)foriinrange(1,m+1):forjinrange(1,n+1):ifA[i-1]==B[j-1]:curr[j]=prev[j-1]+1else:curr[j]=max(prev[j],curr[j-1])prev,curr=curr,prevreturnm+n-prev[n]

复杂度分析

  • 时间复杂度:O(m * n)
  • 空间复杂度:O(m * n),滚动数组优化后是O(min(m, n))

总结一下

这道题的关键不是背网格图,而是看出:

  • 斜边 = 公共子序列里的一个字符
  • 最短路径 = 总长度 - 最长公共子序列长度

下次看到"字符串网格"“最短路径”"匹配"这类关键词,脑子里先蹦出 LCS。

你平时做 OD 题最怕哪种题型?欢迎在评论区聊聊。

http://www.jsqmd.com/news/1125543/

相关文章:

  • 防止对话上下文腐败(Context Corruption)的策略
  • 泡沫的是估值与投机,不是技术本身:不要天天看,而是了解行业,消除噪音报价
  • 数据指标 SLA:报表准时不代表指标可信
  • 老鸟对菜鸟的一些建议
  • JSM2300 20V/6A N 沟道功率 MOSFET
  • 操作系统死锁避免核心:银行家算法超详细图解+实战案例
  • 告别技术空谈:九尾狐AI发布2026年最新企业AI培训体系,主推‘战略到变现‘全周期陪跑模式
  • Scikit-learn 1.5.0 心脏病预测实战:5种分类算法调参与模型融合策略
  • 若依系统登录密码RSA加密实战:jsencrypt前端加密与Spring Boot后端解密
  • web第十、十一次作业
  • AI上台模特AI特效全面探索,服饰行业高效换装实测对比
  • 智慧滑坡监测数据集构建与YOLO模型训练指南
  • 打破显存瓶颈TESHY 活体架构与全维异步管道的端侧革命从静态文件到呼吸生命
  • 探索虚幻引擎游戏资产的终极利器:FModel深度解析与实战指南
  • 企业微信二次开发中的文件系统设计:媒体资源、临时文件与业务附件
  • 从零到一:使用OWASP ZAP对DVWA进行自动化安全扫描实战
  • 从零构建AI Agent:基于LangChain的智能数据查询助手实战
  • JSON转表格使用教程:从入门到精通
  • 原来网站排名还能“买”到?
  • 从问答机到协作者:Codex如何通过理解项目上下文提升AI编程效率
  • 开源自建还是企业级 API 中转?选型对比指南
  • SOME/IP通信调试血泪史——组播地址出错
  • 西安正规GEO公司推荐
  • 8人硕博团队,单月获客100+!留学赛道的“王炸打法”藏不住了
  • 整理了大半年的全品类少儿编程备课资源,终于把坑都踩平了
  • python lambda 入门+实战
  • 京东JoyAI-VL-Interaction实时视频交互模型部署与应用指南
  • 基于STM32单片机智能充电桩计费设计 电动车充电桩计费系统 成品21(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_
  • 【JAVA毕设源码分享】基于springboot电子外设销售系统的设计与实现(程序+文档+代码讲解+一条龙定制)
  • GPIO 中断抖动排查:软件消抖不能替硬件背锅