技术

agentic chat 图数据库的一些考量 LLM一些探索 Agent实践 LLM预训练 向量数据库的一些考量 fastapi+sqlalchemy进行项目开发 LLM微调实践 Python协程实现 Agent Functon Calling LLamaIndex入门 Multi-Agent探索 Python虚拟机 LLM工作流编排 Python实践 下一个平台Agent 激发LLM涌现——提示工程 LLM微调理论 大佬沉思 LLM外挂知识库 LLMOps 多模态LLM Python一些比较有意思的库 Transformers源码学习 LangChain源码学习 通用分布式计算引擎Ray Python并发 go依赖注入 go collection gc的基本原理 golang性能分析及优化 数据湖 高性能计算与存储 Linux2.1.13网络源代码学习 《大数据经典论文解读》 三驾马车学习 Spark 内存管理及调优 Yarn学习 从Spark部署模式开始讲源码分析 容器狂占内存资源怎么办? 多角度理解一致性 golang io使用及优化模式 Flink学习 c++学习 学习ebpf go设计哲学 ceph学习 学习mesh kvm虚拟化 学习MQ go编译器以及defer实现 学习go 为什么要有堆栈 汇编语言 计算机组成原理 运行时和库 Prometheus client mysql 事务 mysql 事务的隔离级别 mysql 索引 坏味道 学习分布式 学习网络 学习Linux go堆内存分配 golang 系统调用与阻塞处理 Goroutine 调度过程 重新认识cpu mosn有的没的 负载均衡泛谈 单元测试的新解读 《Redis核心技术与实现》笔记 《Prometheus监控实战》笔记 Prometheus 告警学习 calico源码分析 对容器云平台的理解 Prometheus 源码分析 并发的成本 基础设施优化 hashicorp raft源码学习 docker 架构 mosn细节 与微服务框架整合 Java动态代理 编程范式 并发通信模型 《网络是怎样连接的》笔记 go channel codereview gc分析 jvm 线程实现 go打包机制 go interface及反射 如何学习Kubernetes 《编译原理之美》笔记——后端部分 《编译原理之美》笔记——前端部分 Pilot MCP协议分析 go gc 内存管理玩法汇总 软件机制 istio流量管理 Pilot源码分析 golang io 学习Spring mosn源码浅析 MOSN简介 《datacenter as a computer》笔记 学习JVM Tomcat源码分析 Linux可观测性 学习存储 学计算 Gotty源码分析 kubernetes operator kaggle泰坦尼克问题实践 kubernetes扩缩容 神经网络模型优化 直觉上理解深度学习 如何学习机器学习 TIDB源码分析 什么是云原生 Alibaba Java诊断工具Arthas TIDB存储——TIKV 《Apache Kafka源码分析》——简介 netty中的线程池 guava cache 源码分析 Springboot 启动过程分析 Spring 创建Bean的年代变迁 Linux内存管理 自定义CNI IPAM 共识算法 spring redis 源码分析 kafka实践 spring kafka 源码分析 Linux进程调度 让kafka支持优先级队列 Codis源码分析 Redis源码分析 C语言学习 《趣谈Linux操作系统》笔记 docker和k8s安全访问机制 jvm crash分析 Prometheus 学习 Kubernetes监控 Kubernetes 控制器模型 容器日志采集 容器狂占资源怎么办? Kubernetes资源调度——scheduler 时序性数据库介绍及对比 influxdb入门 maven的基本概念 《Apache Kafka源码分析》——server Kubernetes类型系统 源码分析体会 《数据结构与算法之美》——算法新解 Kubernetes源码分析——controller mananger Kubernetes源码分析——apiserver Kubernetes源码分析——kubelet Kubernetes介绍 ansible学习 Kubernetes源码分析——从kubectl开始 jib源码分析之Step实现 线程排队 jib源码分析之细节 跨主机容器通信 jib源码分析及应用 为容器选择一个合适的entrypoint kubernetes yaml配置 《持续交付36讲》笔记 mybatis学习 程序猿应该知道的 无锁数据结构和算法 CNI——容器网络是如何打通的 为什么很多业务程序猿觉得数据结构和算法没用? 串一串一致性协议 当我在说PaaS时,我在说什么 《数据结构与算法之美》——数据结构笔记 PouchContainer技术分享体会 harbor学习 用groovy 来动态化你的代码 精简代码的利器——lombok 学习 《深入剖析kubernetes》笔记 编程语言那些事儿 rxjava3——背压 rxjava2——线程切换 spring cloud 初识 《深入拆解java 虚拟机》笔记 《how tomcat works》笔记 hystrix 学习 rxjava1——概念 Redis 学习 TIDB 学习 如何分发计算 Storm 学习 AQS1——论文学习 Unsafe Spark Stream 学习 linux vfs轮廓 《自己动手写docker》笔记 java8 实践 中本聪比特币白皮书 细读 区块链泛谈 比特币 大杂烩 总纲——如何学习分布式系统 hbase 泛谈 forkjoin 泛谈 看不见摸不着的cdn是啥 《jdk8 in action》笔记 程序猿视角看网络 bgp初识 calico学习 AQS——粗略的代码分析 我们能用反射做什么 web 跨域问题 《clean code》笔记 《Elasticsearch权威指南》笔记 mockito简介及源码分析 2017软件开发小结—— 从做功能到做系统 《Apache Kafka源码分析》——clients dns隐藏的一个坑 《mysql技术内幕》笔记 log4j学习 为什么netty比较难懂? 递归、回溯、动态规划 apollo client源码分析及看待面向对象设计 学习并发 docker运行java项目的常见问题 OpenTSDB 入门 spring事务小结 分布式事务 javascript应用在哪里 《netty in action》读书笔记 netty对http2协议的解析 ssl证书是什么东西 http那些事 苹果APNs推送框架pushy apple 推送那些事儿 编写java框架的几大利器 java内存模型和jvm内存布局 java exception Linux IO学习 netty内存管理 测试环境docker化实践 netty在框架中的使用套路 Nginx简单使用 《Linux内核设计的艺术》小结 Go并发机制及语言层工具 Linux网络源代码学习——数据包的发送与接收 《docker源码分析》小结 docker namespace和cgroup zookeeper三重奏 数据库的一些知识 Spark 泛谈 链式处理的那些套路 netty回顾 Thrift基本原理与实践(二) Thrift基本原理与实践(一) 回调 异步执行抽象——Executor与Future Docker0.1.0源码分析 java gc Jedis源码分析 深度学习泛谈 Linux网络命令操作 JTA与TCC 换个角度看待设计模式 Scala初识 向Hadoop学习NIO的使用 以新的角度看数据结构 并发控制相关的硬件与内核支持 systemd 简介 quartz 源码分析 基于docker搭建测试环境(二) spring aop 实现原理简述 自己动手写spring(八) 支持AOP 自己动手写spring(七) 类结构设计调整 分析log日志 自己动手写spring(六) 支持FactoryBean 自己动手写spring(九) 总结 自己动手写spring(五) bean的生命周期管理 自己动手写spring(四) 整合xml与注解方式 自己动手写spring(三) 支持注解方式 自己动手写spring(二) 创建一个bean工厂 自己动手写spring(一) 使用digester varnish 简单使用 关于docker image的那点事儿 基于docker搭建测试环境 分布式配置系统 JVM执行 git maven/ant/gradle/make使用 再看tcp kv系统 java nio的多线程扩展 《Concurrency Models》笔记 回头看Spring IOC IntelliJ IDEA使用 Java泛型 vagrant 使用 Go常用的一些库 Python初学 Goroutine 调度模型 虚拟网络 《程序员的自我修养》小结 Kubernetes存储 访问Kubernetes上的Service Kubernetes副本管理 Kubernetes pod 组件 Go基础 JVM类加载 硬币和扑克牌问题 LRU实现 virtualbox 使用 ThreadLocal小结 docker快速入门

架构

bert rerank微调 大模型推理tips RAG向量检索与微调 dddfirework源码分析 RAG与知识图谱 大模型推理服务框架vLLM 大模型推理服务框架 模型服务化(未完成) 大模型Post-Training 大模型训练 大模型推理 从Attention到Transformer k8s设备管理 ddd从理念到代码 如何应用LLM 小鼠如何驾驭大象(LLM)? 多类型负载协调员Koordinator controller-runtime细节分析 finops学习 kubevela多集群 kubevela中cue的应用 基于k8s的工作流 kubevela源码分析 容器和CPU那些事儿 数据集管理fluid 应用管理平台kubevela karmada支持crd 多集群管理 AutoML和AutoDL 特征平台 实时训练 分布式链路追踪 K8S YAML 资源清单管理方案 tensorflow原理——python层分析 如何学习tensorflow 数据并行——allreduce 数据并行——ps 推荐系统embedding原理及实践 机器学习中的python调用c 机器学习训练框架概述 tensornet源码分析 大模型训练和推理 X的生成——特征工程 tvm tensorflow原理——core层分析 模型演变 《深度学习推荐系统实战》笔记 keras 和 Estimator tensorflow分布式训练 分布式训练的一些问题 基于Volcano的弹性训练 图神经网络 pytorch弹性分布式训练 从混部到统一调度 从RNN到Attention pytorch分布式训练 CNN 《动手学深度学习》笔记 pytorch与线性回归 多活 volcano特性源码分析 推理服务 kubebuilder 学习 mpi 学习pytorch client-go学习 提高gpu 利用率 GPU与容器的结合 GPU入门 AI云平台梳理 tensorflow学习 tf-operator源码分析 k8s批处理调度/Job调度 喜马拉雅容器化实践 Kubernetes 实践 学习rpc BFF openkruise学习 可观察性和监控系统 基于Kubernetes选主及应用 《许式伟的架构课》笔记 Admission Controller 与 Admission Webhook 发布平台系统设计 k8s水平扩缩容 Scheduler如何给Node打分 Scheduler扩展 深入controller openkruise cloneset学习 controller-runtime源码分析 pv与pvc实现 csi学习 client-go informer源码分析 kubelet 组件分析 调度实践 Pod是如何被创建出来的? 《软件设计之美》笔记 mecha 架构学习 Kubernetes events学习及应用 CRI——kubelet与容器引擎之间的接口 资源调度泛谈 业务系统设计原则 grpc学习 元编程 以应用为中心 istio学习 下一代微服务Service Mesh 《实现领域驱动设计》笔记 概率论 serverless 泛谈 《架构整洁之道》笔记 处理复杂性 那些年追过的并发 服务器端编程 网络通信协议 架构大杂烩 如何学习架构 《反应式设计模式》笔记 项目的演化特点 反应式架构摸索 函数式编程的设计模式 服务化 ddd反模式——CRUD的败笔 研发效能平台 重新看面向对象设计 业务系统设计的一些体会 函数式编程 《左耳听风》笔记 业务程序猿眼中的微服务管理 DDD实践——CQRS 项目隔离——案例研究 《编程的本质》笔记 系统故障排查汇总及教训 平台支持类系统的几个点 代码腾挪的艺术 abtest 系统设计汇总 《从0开始学架构》笔记 初级权限系统设计 领域驱动理念 现有上传协议分析 移动网络下的文件上传要注意的几个问题 推送系统的几个基本问题 做配置中心要想好的几个基本问题 不同层面的异步 分层那些事儿 性能问题分析 用户认证问题 资源的分配与回收——池 消息/任务队列

标签

k8s设备管理 多类型负载协调员Koordinator controller-runtime细节分析 finops学习 kubevela多集群 kubevela中cue的应用 基于k8s的工作流 kubevela源码分析 容器和CPU那些事儿 数据集管理fluid 应用管理平台kubevela karmada支持crd 多集群管理 K8S YAML 资源清单管理方案 从混部到统一调度 volcano特性源码分析 kubebuilder 学习 client-go学习 tf-operator源码分析 k8s批处理调度/Job调度 喜马拉雅容器化实践 Kubernetes 实践 openkruise学习 基于Kubernetes选主及应用 Admission Controller 与 Admission Webhook k8s水平扩缩容 Scheduler如何给Node打分 Scheduler扩展 深入controller openkruise cloneset学习 controller-runtime源码分析 pv与pvc实现 csi学习 client-go informer源码分析 kubelet 组件分析 调度实践 Pod是如何被创建出来的? Kubernetes events学习及应用 CRI——kubelet与容器引擎之间的接口 资源调度泛谈 如何学习Kubernetes 以应用为中心 kubernetes operator kubernetes扩缩容 serverless 泛谈 什么是云原生 自定义CNI IPAM docker和k8s安全访问机制 Kubernetes监控 Kubernetes 控制器模型 Kubernetes资源调度——scheduler Kubernetes类型系统 Kubernetes源码分析——controller mananger Kubernetes源码分析——apiserver Kubernetes源码分析——kubelet Kubernetes介绍 Kubernetes源码分析——从kubectl开始 kubernetes yaml配置 CNI——容器网络是如何打通的 当我在说PaaS时,我在说什么 《深入剖析kubernetes》笔记 Kubernetes存储 访问Kubernetes上的Service Kubernetes副本管理 Kubernetes pod 组件
agentic chat bert rerank微调 大模型推理tips LLM一些探索 Agent实践 LLM预训练 RAG向量检索与微调 LLM微调实践 RAG与知识图谱 大模型推理服务框架vLLM Agent Functon Calling LLamaIndex入门 Multi-Agent探索 LLM工作流编排 大模型推理服务框架 模型服务化(未完成) 大模型Post-Training 大模型训练 大模型推理 从Attention到Transformer 下一个平台Agent 激发LLM涌现——提示工程 LLM微调理论 大佬沉思 LLM外挂知识库 LLMOps 多模态LLM Transformers源码学习 LangChain源码学习 如何应用LLM 小鼠如何驾驭大象(LLM)? AutoML和AutoDL 特征平台 实时训练 tensorflow原理——python层分析 如何学习tensorflow 数据并行——allreduce 数据并行——ps 推荐系统embedding原理及实践 机器学习中的python调用c 机器学习训练框架概述 tensornet源码分析 大模型训练和推理 X的生成——特征工程 tvm tensorflow原理——core层分析 模型演变 《深度学习推荐系统实战》笔记 keras 和 Estimator tensorflow分布式训练 分布式训练的一些问题 基于Volcano的弹性训练 图神经网络 pytorch弹性分布式训练 从RNN到Attention pytorch分布式训练 CNN 《动手学深度学习》笔记 pytorch与线性回归 推理服务 mpi 学习pytorch 提高gpu 利用率 GPU与容器的结合 GPU入门 AI云平台梳理 tensorflow学习 kaggle泰坦尼克问题实践 神经网络模型优化 概率论 直觉上理解深度学习 如何学习机器学习 深度学习泛谈

为什么很多业务程序猿觉得数据结构和算法没用?

2018年10月03日

简介

本文主要从业务程序猿的角度来阐述问题。

2019.2.26 补充:为什么做搜索的公司技术都很牛?为什么要学数据结构与算法?为什么业务程序猿感觉数据结构与算法没用?剖析搜索引擎背后的经典数据结构和算法 光一个最最简单的搜索引擎涉及的数据结构和算法就有:图、散列表、Trie 树、布隆过滤器、单模式字符串匹配算法、AC 自动机、广度优先遍历、归并排序等。

首先,我们先回答一个孪生问题,再从“业务发展阶段” 及 “X/Y问题”视角来论证一下。

业务程序猿为什么要学习数据结构与算法

首先,笔者针对这个问题问了好几个大牛, 汇总如下

  1. 这不是大学基础专业课吗?基础的东西,也是it行业都必须要掌握的,不要问为什么要学,这是软技能,必须掌握
  2. 具体的数据结构是次要的,对目标问题的可利用的属性、数学模型的特殊属性、以及运行系统的物理属性保持高度敏感才是关键。数据结构课程不厌其烦讲解那么多例子就是让你建立这种“机敏”的世界观
  3. 数据结构基本就干两件事:对特定问题的有效存储,以方便更有效的检索。
  4. 不同的公司、不同的人做rpc框架,架构设计思路都差不多,最后实现的功能也差不多。但有的人做出来的框架 bug很多、性能一般、扩展性也不好,只是内部使用,而有的人可以被apache收录。高手之间的竞争其实就在细节,细节在技术上往往就是数据结构和算法。
  5. 数据结构不是最用不上的,数据结构是最普遍的,就像你可能认为数学是最用不上的时候,其实它无处不在
  6. 技术会有几个终极目标,比如最好的性能(包括最少时间和最少空间占用),还有最快交付结果。第一个和数据结构算法关系密切。虽然多数人并不需要自己写算法,只需要crud,但走到高级技术时,就要自己直面难题,不了解底下原理的话,就不容易做出合适的选择以及出深刻问题时如何排查。
  7. 数据结构,算法,作为编程基础,很有用,但未必有针对性的有用。很多日常工作可能根本不会直接用到。比如,高等数学有用吗?肯定有用,对你实际工作有很大帮助吗?未必,在实际逻辑开发中可能作用还不如一个简单的设计模式有用。我觉得你要看针对性,比如我是前一两年开始研究深度学习的时候,才去复习线性代数的一些算法比如梯度下降。如果关注架构,领域建模等层面,不太需要对数据结构和算法随时保持新鲜的记忆,有一点点“肌肉记忆”即可,如果你要做偏底层的开发,比如Southgate这种,才那可能会直接用到算法。
  8. 我觉得数据结构和算法属于提升层次的一个东西,具体点,对数据结构和算法敏感通常代码审美能力比较好,知道什么代码是好的,什么代码是低效的,数据结构最大的作用就是简化代码的复杂度和提高代码的维护性,典型的例子就是比如你用个前缀树啥的做搜索你可以很清楚时间复杂度和空间复杂度是多少,如果没这种数据结构的概念就容易写出低效的代码了。再补充一点,开源方案非常多,我们选择一些方案,进行技术选型的时候肯定会去稍微看看代码,美的代码会促进你使用,而评价美与丑就是看里面一些数据结构和小的算法的使用

笔者自己在交流中的一些体会

  1. 很多时候,是不学导致用不到,学到自然会找办法用到。就好比学英语,英语不好的程序猿不看英文文档,自然也体会不到英文的用处。
  2. 跟业务领域有关系,比如你在一家做地图的公司上班,对“图”相关的算法是一定要了解的。

业务发展阶段

有时候单说问题本身,是说不出所以然的,要place it in context,本文将context 定位为 公司的发展阶段。

一个互联网公司的发展通常有以下阶段:

  1. 业务为重,因为要生存
  2. 业务与技术并重,生存是第一的,但量级增大导致技术拖了后腿
  3. 技术驱动业务,最明显的体现在两个地方

    • 大公司做一个app的成本极其低廉
    • 最近流行的 为用户、主播、商家“赋能”

具体的说

  1. 互联网公司早期业务的本质是信息化,信息化体现在技术上就是crud,也就有了很多crud boy
  2. 早期用户、数据量不大
  3. “业务为重”体现在技术上 就是尽快的交付,无暇顾及数据结构与算法
  4. 后续,用户、数据量增大本身 对技术构成挑战
  5. 竞品的出现,以及用户需求的提高,不能止步于信息化,需要个性化、智能化

大部分公司 处在前两个阶段,所以业务程序猿 面对的事情更多是信息化和快速交付,因此对数据结构 与算法的 必要性感受不深。

一个很直观的例子, 大家谁能说的清楚自己的项目扛得住多大的QPS?有没有试过单机最大扛多少QPS?有没有体验过 最大QPS 下代码会出现哪些问题?很少。为何很多业务程序猿很少考虑这个问题呢?因为出了问题哪有时间想这些,代码逻辑没错就行,性能不够就加机器啊。

X/Y 问题

X/Y 问题说的是:你让我干Y,但其实为什么需要Y呢,是因为X,而实现X的方法 不是只有Y。说的是 做事情、看问题 要寻找本源。针对本文的问题可以衍射出两个问题

  1. 当我在说“数据结构与算法”的时候,我在说什么
  2. 数据结构与算法是Y,那么X是什么?

    对数据结构的认识问题

大部分人在说 数据结构 和算法的时候,其实说的是大学学的《数据结构》那本书,再具体一点就是清华大学出版社的那本。那本书 定义了 我们看到 数据结构 这四个字时的条件反射,即线性表、树、图、排序算法等。

所以,我们说学习数据结构与算法有什么用?对大部分人来说,可以转换为:学习“线性表、树、图、排序算法” 有什么用? 就这个具体问题而言,除了代码里必不可少的数组/List 之外,其它的确实用的少。再者,笔者确实没碰到业务场景说 一定要将ArrayList 替换为LinkedList 。

对应前文中大牛提到的观点:数据结构基本就干两件事:对特定问题的有效存储,以方便更有效的检索。 所以数据结构不只是线性表、树和图,业务数据的结构化都可以归类到数据结构问题,进而考量数据有哪些检索场景?是否高效?

真的是为了数据结构本身么?

我们学习数据结构 与算法 是为了“更优的数据结构和算法” 本身么?不是,性能不高 加机器就好了呀。

我们学习数据结构与算法, 不是为了死记硬背几个知识点,是为了不断提高自己的意识

  1. 从无到有写代码的时候,培养对空间、时间浪费的罪恶感
  2. 从有到更好。出了问题,你的应对手段多一个思维方向,而不是只有“加机器”/“求助” 两条路

结合笔者的工作经历提一个问题:netty最牛的地方在哪里?用了nio?用了主从线程模型?内存零拷贝?数据处理pipeline?使用arena 接管内存分配和释放? 都对也都不对,是netty 在不断迭代的过程中,不断地对自己提要求,不断地挖掘问题点以支持更高的性能。

netty 的版本一直在迭代,业务当前很稳定,自然没有必要升netty的版本。类似的,如果你没有这样的意识,学数据结构与算法 也毫无必要。

如何学习数据结构与算法——有度的学习

数据结构 在技术中的 整体地位

做偏中间件开发的人,对算法和偏底层的比如网络的运用是比较多的,一般数据结构和算法能力都比较好,但他们对“工程”架构的东西关注不足。

因此凡事都可以一体两面的去看,技术能力可以分为

  1. 基础能力,包括但不限于语言、计算机组成原理、操作系统、数据结构与算法等
  2. 工程能力,如何应用基础能力,以及需求分析、项目设计、测试、维护和文档等
  3. 技术管理,人员项目协调、进度把控、技术氛围等

数据结构、计算机组成原理、操作系统等 经过文章、博客、课本的普及,成为一种“显学”。而“工程/架构”、”技术管理“等 因为模糊 提的少, 被归类为软技能。软技能在做他人/自我评估时,便容易被漏掉,一些工程能力/管理能力还不错的同学 也容易因为数据结构 不好而觉得不自信。

结合上文公司的发展阶段也可以看到,业务从无到有的过程 对工程能力和技术管理比较看重,业务从有到更好阶段 则更为看重基础能力。

有理有利有节

记忆有以下几种

  1. 有随时“新鲜”的记忆
  2. 不常用但是了解原理的“常识“记忆
  3. “肌肉”记忆,跟直觉一样

工作内容尽量要覆盖在新鲜记忆上。结合公司的发展阶段 以及自己的兴趣 爱好 和 定位 来把控自己的学习节奏,要不要学?学到什么程度? 很多时候,学不到位会误事,太超前了则容易受挫,进而打击积极性。此外,要随着项目、阶段的变化调整自己的策略,有些事要提前布局,有些事被动跟进就可以了。

刷题

对于初学者来说,做题有点像是撞大运,非常依赖苦思冥想之后的灵光一闪。而高手做题则不然,他们的思路非常有章法,知道如何从蛛丝马迹的细节中锁定解法。所以这就是为什么有些题目用到的算法即使新手学过,但拿到题还是一样做不出来,而高手却能秒切的原因。当然想要拥有这样的功力也不是一朝一夕的,也需要长久、反复的训练。至少我们在刷题的过程中可以意识到这点,在做完题之后多尝试,尝试构建出从问题分析出解法的推衍过程。推衍得多了,自然熟悉的套路也多,做题也就会变得顺手起来。在面试的时候,这个技能同样非常有用。哪怕最后想不出解法,只要能合理地分析问题,找对思路,也是一个巨大的加分点。很多时候做到这样就足够打动面试官了。

计算机领域有一句名言:程序等于算法加数据结构。数据结构针对的是数据层面,提供数据的存储和查询,而算法针对的是操作层面,对数据进行操作,达成我们期望的效果。算法和数据结构相辅相成,算法基于数据结构实现,而数据结构的实现本身就需要用到算法。一道题本质上就是若干个算法和数据结构的组合,我们只要能找到合理的算法和数据结构,就可以获得AC。如果你觉得拿到题目之后很蒙圈,无从下手,那么不妨将算法和数据结构分开进行思考。

  1. 数据结构说白了就是数据的增删改查,只不过题目一般都会对性能做出要求,需要保证增删改查的复杂度满足一定的限制。但限制本身也是一种提示,因为常用的数据结构也就那么几种,熟悉了之后,一结合复杂度要求,几乎可以瞬间锁定。
  2. 算法就是在数据结构基础上对数据的进一步加工,使得满足题目的要求。比如搜索、动态规划、贪心等本质上都是数据的操作。

我们常说的LeetCode题,大体上可以分为三种:算法题、数据结构题和综合题。顾名思义,算法题就是以算法考察为主,比如排序、搜索、贪心、动态规划相关的问题,数据结构都比较简单,可能就是普通数组就行。数据结构题也类似,就是考数据结构,比如线段树、树状数组、链表、图等等,你不会这些数据结构就做不出来。最后一种就是综合题,既考察算法又考察数据结构。一般来说综合题最难,因为需要都会。总的来说,LeetCode Medium难度的题目,算法和数据结构只会主要考察一种。用到了比较高级的数据结构,就不会过多涉及算法,同样,如果需要对算法设计做深入思考,用到的数据结构就不会很难。而Hard难度的题,往往是这两者的结合,或者是某一方面的深入考察。

理解了这些之后,当你拿到问题感觉无从下手的时候,不妨可以将算法和数据结构拆开来思考。这道题对于数据增删改查有没有特殊的性能要求?可能需要用到什么数据结构?在有了对应的数据结构之后又该使用什么算法得到答案?说不定就能灵光一闪,找到突破口。此外,凭空思考一个最优解是很难的,相比之下先想出一个方法再慢慢优化要容易得多。所以不要看不起那些一眼就不是正解的“弱智”解法,它们经过优化是有可能构成正解的,很多时候这是我们效率最高的思考方式。这个方法在面试的时候尤其有用,面试官很多时候不是只想要一个正解。有时候你直接告诉他解法,他反而可能觉得你是背的答案或者是刚好之前做到过。他更想听我们的思考过程,看看我们的思维能力以及分析能力。这种抽丝剥茧,一点点优化的方式是很多面试官喜欢的,即使离正解还差一点,也一样能得到高分。

个人微信订阅号