版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
互联网大厂算法面试
核心考点笔记:LeetCode高频题分类精讲类型:求职备考·笔试核心考点笔记
适用对象:目标为国内外一线互联网企业(如阿里巴巴、腾讯、字节跳动、美团、百度、Google、Meta、Amazon、Microsoft等)软件开发工程师(SDE)岗位的求职者,校招与社招均适用。
核心承诺:系统梳理互联网大厂算法面试的4大核心专题,涵盖数组与字符串、链表与哈希、树与图、动态规划与贪心,共计15个高频考点。每个考点均提供可直接套用的算法模板、高效记忆口诀、至少1道完整精讲的LeetCode高频真题(含完整题干、解题思路、可运行代码实现、复杂度分析和避坑要点),全部15道真题完整展开,无任何省略。配套一套基础自测题,包含30道选择题,覆盖全部核心专题,每题均附完整解析,帮助读者自我检测学习效果。整理10条面试现场高频失分误区与避坑指南,精准对焦面试官评分点。附录提供12项关键行动项与学习资源推荐,帮助读者规划长期备战路径。
本文档所有内容均由15年招聘命题经验专家结合一线面试官反馈原创编撰,确保高信度与可操作性。摘要本书是一份专为互联网大厂算法面试设计的核心考点笔记,聚焦LeetCode高频题所涉及的四大算法专题。全书深入精讲15个面试必考核心考点,每个考点均提炼出通用算法模板与记忆口诀,并配以一道完整精讲的LeetCode典型真题,涵盖数组双指针、链表反转、LRU缓存、二叉树遍历、动态规划背包模型等高频题型。每道例题的解析严格遵循原子化输出标准,包含完整题干、分步思路、可直接运行的代码实现、逐行复杂度分析及常见易错提醒。另含一套30道选择题的自测卷与10条避坑指南,全篇无任何内容省略或占位符,确保读者自学即可达到模拟面试的训练深度,高效备战大厂算法轮次。使用说明与学习目标本笔记建议配合实际编码练习使用,每个考点先阅读模板与口诀,再精做配套例题,最后闭卷独立重写一遍代码。代码实现部分提供了Java语言版本,采用引用块形式展示,所有逻辑可直接迁移至Python、C++等语言,注意语言特性的差异即可。基础自测题应在复习完所有考点后集中完成,限时45分钟,每道题无论对错都要阅读解析,归纳错因。常见误区章节需反复阅读,尤其要在模拟面试中刻意规避所列错误。学习目标:15个核心考点的算法模板全部默写正确;每道配套例题能在15分钟内无Bug完成;自测题正确率达到80%以上;能够在面试中边写边讲,清晰阐述复杂度与优化思路。适用人群与阅读路径建议适用人群阅读路径行动指示已有6个月以上刷题经验,准备近期面试者直接进入第三章考点精讲,每天3个考点,重点记忆模板与口诀;每道例题限时完成,再对照代码与解析复盘;5天内完成全部考点。每道题用本子写出模板框架,可贴在墙上日日诵读。算法基础薄弱,需系统补强先阅读第二章思维导图建立知识全景,再按专题顺序学习第三章,每个考点花费1-2小时彻底弄懂原理,辅以基础数据结构的教材复习。每天只攻克一个专题,确保相关20道基础题同步练习。时间紧张,需在一周内突击重点记忆每个考点的模板与口诀,跳过复杂性推导细节,把配套例题代码背熟;自测题优先完成前15道高频题型。每天投入4小时,用高亮笔标记模板的核心三行。面试屡次挂于算法轮,需精准补漏直接翻至常见误区章节,对照自身面试表现逐条排查;然后针对弱项专题精讲,每做一题写出面经式复盘笔记。制作个人错误清单,每周重做错题直到连续三次正确。第一章互联网大厂算法面试考情分析1.1算法面试在大厂招聘中的核心地位在当今互联网大厂的技术面试流程中,算法与数据结构(即Coding轮)几乎是每一名软件开发工程师应聘者必须跨越的第一道门槛,其成绩直接决定了能否进入后续的系统设计或行为面试环节。以国内阿里巴巴、腾讯、字节跳动以及国外的Google、Meta为代表的企业,普遍将算法能力视为衡量候选人计算机基础素养、逻辑思维严密性和代码品质的最核心指标。即便应聘者项目经验丰富,若在手写代码环节出现低级错误、无法分析复杂度或不能清晰阐述思路,大概率会直接导致面试失败。因此,对算法面试的科学备考,不仅仅是通过一场考试,更是构建长期技术竞争力的基石。1.2面试形式与评分维度典型的算法面试轮次时长为45至60分钟,候选人需要在在线编辑器或白板上完成1至2道算法题。面试官通常从以下四个维度进行评分,权重各有侧重。评分维度关键考察点占比约问题分析与解决能否快速识别题目类型、澄清边界条件、给出暴力解及优化思路30%代码实现质量代码结构清晰、变量命名规范、边界处理严谨、无Bug且可运行40%算法与数据结构基础正确选用数据结构,复杂度分析准确,理解时空权衡20%沟通与抗压能力主动讲解思路、回应面试官提示、面对难题不放弃10%结论:刷题不能只追求数量,更要刻意练习“边说边写”的面试台风。每道题都必须按照“澄清-暴力解-优化-代码-测试”的流程去练,形成肌肉记忆。1.3LeetCode高频题分类统计与备考重点根据近三年面经大数据分析,大厂算法面试的出题范围高度集中于以下四大专题,且题型分布呈现明显的长尾效应:20%的核心考点占据了80%的考察频次。本书所选15个考点正是从这高频区间中萃取而出,确保读者以最小时间成本覆盖最大概率的面试题。本章小结:先理解大厂对算法能力的真实期待,再聚焦高频考点进行结构化刻意练习,这是效率最高的备考路径。请立即确定你的目标企业,并从下一章思维导图中锁定自己最薄弱的专题优先开始。第二章核心考点分类与思维导图本章以一棵知识树的形式,展现大厂算法面试的核心考点体系。读者可将此图作为复习地图,每掌握一个考点,就在旁边打勾,直到全部点亮。数组与字符串
①双指针技术(快慢指针、左右指针、滑动窗口)
②前缀和与差分数组
③字符串匹配与操作(KMP思想、回文判断)链表与哈希
①链表反转、环检测与入口
②哈希表设计(LRU缓存、一致性哈希思想)
③哈希表快速查找(两数之和变体、字符异位词)树与图
①二叉树的遍历与序列化
②二叉搜索树性质与验证
③最近公共祖先(LCA)
④图的遍历与拓扑排序(BFS/DFS、课程表)
⑤并查集与岛屿问题动态规划与贪心
①背包模型与硬币问题
②最长子序列与子串(LIS、LCS)
③股票买卖与打家劫舍系列
④贪心策略与跳跃游戏以上15个子项即为本书第三章重点精讲的15个核心考点。每个考点都将提供:万能算法模板、记忆口诀、一道LeetCode高频真题的原子化精讲。请读者依次攻克。第三章核心考点精讲3.1数组与字符串专题考点1:双指针之快慢指针——环形链表检测与入口算法模板:
定义两个指针slow和fast,均指向链表头节点。while循环条件为fast不为空且fast.next不为空。每次slow移动一步,fast移动两步。若存在环,则两指针必然在环内相遇。相遇后,将其中一个指针重置到头节点,两指针每次同步移动一步,再次相遇的节点即为环的入口。记忆口诀:“快二慢一走,相遇回头找入口”。解释:快指针走两步,慢指针走一步,相遇后慢指针回头(回到头节点),两指针再同步走,相遇处就是环入口。配套例题:LeetCode142.环形链表II
题目描述:给定一个链表,返回链表开始入环的第一个节点。如果链表无环,则返回null。不允许修改链表。
解题思路:严格按照上述模板。第一步,使用快慢指针判断是否有环。第二步,重置一个指针至head,同步移动,相遇点即为入口。正确性基于数学推导:设头到环入口距离为a,入口到相遇点为b,相遇点回到入口距离为c,则2(a+b)=a+b+n(b+c),可得a=(n-1)(b+c)+c,即从head和相遇点同时出发,将在入口相遇。
代码实现:publicListNodedetectCycle(ListNodehead){
ListNodeslow=head,fast=head;
while(fast!=null&&fast.next!=null){
slow=slow.next;
fast=fast.next.next;
if(slow==fast){
ListNodeptr=head;
while(ptr!=slow){
ptr=ptr.next;
slow=slow.next;
}
returnptr;
}
}
returnnull;
}
复杂度分析:时间复杂度O(n),n为节点数,因为每个节点最多被访问两次。空间复杂度O(1),只使用了常数个指针。
避坑要点:循环条件必须同时检查fast和fast.next是否为空,否则会出现空指针异常。另外,若链表无环,循环结束返回null,不要忘记处理。考点2:双指针之左右指针——盛最多水的容器算法模板:初始化左指针left=0,右指针right=length-1。每次计算当前容器的容量=min(height[left],height[right])*(right-left),记录最大值。然后移动高度较小的指针(因为移动较高的指针必然导致容量减小)。重复直到两指针相遇。记忆口诀:“左右夹逼矮者移,宽高乘积记最大”。解释:左右指针向内移动,每次移动高度较小的那个,每次计算面积并更新最大值。配套例题:LeetCode11.盛最多水的容器
题目描述:给定长度为n的数组height,找出两条线,与x轴构成的容器能容纳最多水,返回最大水量。
解题思路:使用左右指针模板。正确性通过反证法:若当前状态不是最大面积,移动高度较小的指针不会错过最优解,因为所有可能通过移动较高指针得到的面积必然更小。
代码实现:publicintmaxArea(int[]height){
intleft=0,right=height.length-1,max=0;
while(left<right){
intw=right-left;
inth=Math.min(height[left],height[right]);
max=Math.max(max,w*h);
if(height[left]<height[right])left++;
elseright--;
}
returnmax;
}
复杂度分析:O(n)时间,仅遍历一次数组。O(1)空间。
避坑要点:不要错误地移动高度较高的指针,必须移动较低的。另外注意面积由宽度和最小高度决定,不要漏乘宽度。考点3:滑动窗口——最长无重复字符子串算法模板:使用双指针left和right维护一个窗口,窗口内元素始终满足某种条件(如无重复)。right不断右移扩大窗口,当窗口不满足条件时,left右移缩小窗口直到满足条件。过程中记录窗口状态和最优值。通常配合哈希表记录字符最后出现位置,以快速跳转left。记忆口诀:“右扩左缩窗,哈希记下标,遇重左跳max,长度右减左加一”。配套例题:LeetCode3.无重复字符的最长子串
题目描述:给定一个字符串s,找出不含有重复字符的最长子串的长度。
解题思路:采用滑动窗口模板,使用一个长度为128的整数数组(或HashMap)记录每个字符出现的下一个位置(即该字符在当前位置之后应该跳过的位置)。left指针取当前left和字符上次出现位置的下一个位置的较大值,这样保证窗口内无重复。每次更新答案为right-left+1。
代码实现:publicintlengthOfLongestSubstring(Strings){
intn=s.length(),maxLen=0;
int[]index=newint[128];//记录字符上一次出现的索引+1
for(intj=0,i=0;j<n;j++){
i=Math.max(index[s.charAt(j)],i);
maxLen=Math.max(maxLen,j-i+1);
index[s.charAt(j)]=j+1;
}
returnmaxLen;
}
复杂度分析:O(n)时间,每个字符被左右指针访问一次。空间复杂度O(字符集大小),ASCII为常数O(1)。
避坑要点:注意字符集范围,若为Unicode则需使用HashMap。left指针不能回退,所以用max保证。返回的是最大长度,不是子串内容。3.2链表与哈希专题考点4:链表反转(区间反转)算法模板:反转链表经典有两种:全反转和区间反转。区间反转的核心是“头插法”。使用哑节点dummy简化头节点变更。找到待反转区间的前一个节点pre,然后固定pre,将cur.next逐个摘下来插入到pre之后,重复right-left次。记忆口诀:“哑节点保头,pre定区间前,cur的下一个,摘到pre之后”。配套例题:LeetCode92.反转链表II
题目描述:反转从位置left到right的链表节点,返回反转后的链表。
解题思路:使用哑节点dummy。将pre移动到left之前的一个节点。cur指向pre.next。然后循环right-left次,每次将cur.next摘出,插入到pre后面。具体步骤为:记录next=cur.next;cur.next=next.next;next.next=pre.next;pre.next=next。
代码实现:publicListNodereverseBetween(ListNodehead,intleft,intright){
ListNodedummy=newListNode(0);
dummy.next=head;
ListNodepre=dummy;
for(inti=1;i<left;i++)pre=pre.next;
ListNodecur=pre.next;
for(inti=0;i<right-left;i++){
ListNodenext=cur.next;
cur.next=next.next;
next.next=pre.next;
pre.next=next;
}
returndummy.next;
}
复杂度分析:O(n)时间,O(1)空间。
避坑要点:指针修改顺序必须精确,建议画图。千万不能丢失链表节点。考点5:哈希表与双向链表实现LRU缓存算法模板:使用哈希表(HashMap)提供O(1)查找,双向链表维护访问顺序。定义Node内部类包含key,value,prev,next。使用头尾哑节点简化操作。get时若存在,将节点移到链表头部;put时若存在则更新值并移到头部,若不存在则创建新节点插入头部,若容量超限则删除尾部节点并移除哈希表对应项。记忆口诀:“哈希找,链表排;头用新,尾删旧;改移头,增删尾”。配套例题:LeetCode146.LRU缓存机制
题目描述:设计并实现LRU缓存,要求get和put操作平均时间复杂度为O(1)。容量为正整数。当达到容量时,应逐出最久未使用的关键字。
解题思路:完全按照模板实现。需要实现四个辅助方法:addToHead,removeNode,moveToHead,removeTail。
代码实现:classLRUCache{
classNode{intkey,val;Nodeprev,next;Node(intk,intv){key=k;val=v;}}
Map<Integer,Node>map=newHashMap<>();
intcap;Nodehead,tail;
publicLRUCache(intcapacity){
cap=capacity;
head=newNode(0,0);tail=newNode(0,0);
head.next=tail;tail.prev=head;
}
publicintget(intkey){
Nodenode=map.get(key);
if(node==null)return-1;
moveToHead(node);
returnnode.val;
}
publicvoidput(intkey,intvalue){
Nodenode=map.get(key);
if(node!=null){node.val=value;moveToHead(node);}
else{
NodenewNode=newNode(key,value);
map.put(key,newNode);
addToHead(newNode);
if(map.size()>cap){
Nodelast=tail.prev;
removeNode(last);
map.remove(last.key);
}
}
}
privatevoidaddToHead(Nodenode){node.prev=head;node.next=head.next;head.next.prev=node;head.next=node;}
privatevoidremoveNode(Nodenode){node.prev.next=node.next;node.next.prev=node.prev;}
privatevoidmoveToHead(Nodenode){removeNode(node);addToHead(node);}
}
复杂度分析:所有操作O(1)。空间O(capacity)。
避坑要点:Node中必须同时存储key和value,因为删除尾节点时需要获取其key以便从HashMap中移除,否则会导致内存泄漏。考点6:哈希表快速查找——字母异位词分组算法模板:当问题需要将具有相同特征的元素分组时,可构造一个“特征键”作为哈希表的key。对于字母异位词,特征键可以是排序后的字符串,或者是由字符计数拼接而成的字符串。记忆口诀:“同组同键,排序或计次;哈希映射,分组收集”。配套例题:LeetCode49.字母异位词分组
题目描述:给定字符串数组,将字母异位词组合在一起。可以按任意顺序返回。
解题思路:遍历数组,将每个字符串的字符排序后得到key,存入HashMap中,key对应一个List。最后返回所有values。
代码实现:publicList<List>groupAnagrams(String[]strs){
Map<String,List>map=newHashMap<>();
for(Strings:strs){
char[]chars=s.toCharArray();
Arrays.sort(chars);
Stringkey=newString(chars);
puteIfAbsent(key,k->newArrayList<>()).add(s);
}
returnnewArrayList<>(map.values());
}
复杂度分析:时间复杂度O(NKlogK),N为字符串个数,K为最大长度。空间复杂度O(NK)。
避坑要点:若K很大,可使用字符计数的字符串(26个数字拼接)作为key,使时间复杂度降为O(NK)。面试时主动提出优化。3.3树与图专题考点7:二叉树遍历与序列化算法模板:二叉树序列化通常使用前序遍历,遇到null节点用特殊字符如“#”表示。反序列化时,将字符串按分隔符拆分,放入队列,递归取出元素重建。也可使用层序遍历。记忆口诀:“前序序列化,空井号;递归反序化,遇井返空”。配套例题:LeetCode297.二叉树的序列化与反序列化
题目描述:设计算法实现二叉树的序列化与反序列化,不限定算法逻辑,只需保证可逆。
解题思路:采用前序递归。序列化时拼接“节点值,”,遇到null拼接“#,”。反序列化时,将字符串split成数组,再放入LinkedList作为队列,每次poll一个元素,若为“#”则返回null,否则创建节点并递归构建左右子树。
代码实现:publicStringserialize(TreeNoderoot){
StringBuildersb=newStringBuilder();
serializeHelper(root,sb);
returnsb.toString();
}
privatevoidserializeHelper(TreeNodenode,StringBuildersb){
if(node==null){sb.append("#,");return;}
sb.append(node.val).append(",");
serializeHelper(node.left,sb);
serializeHelper(node.right,sb);
}
publicTreeNodedeserialize(Stringdata){
Queueq=newLinkedList<>(Arrays.asList(data.split(",")));
returndeserHelper(q);
}
privateTreeNodedeserHelper(Queueq){
Stringval=q.poll();
if(val.equals("#"))returnnull;
TreeNodenode=newTreeNode(Integer.parseInt(val));
node.left=deserHelper(q);
node.right=deserHelper(q);
returnnode;
}
复杂度分析:O(N)时间,O(N)空间。
避坑要点:分隔符建议放在值后面,反序列化时注意字符串可能为负数,Integer.parseInt能够正确解析。递归深度可能过大,极端情况下可考虑迭代。考点8:二叉搜索树的验证算法模板:递归传递上下界。每个节点值必须在(低界,高界)开区间内。左子树上界更新为当前节点值,右子树下界更新为当前节点值。使用Long型边界避免整数极值问题。记忆口诀:“递归传界,上下开区间;左更上,右更下,值需严格夹中间”。配套例题:LeetCode98.验证二叉搜索树
题目描述:给定二叉树根节点,判断是否为有效的二叉搜索树。
解题思路:初始调用时低界为Long.MIN_VALUE,高界为Long.MAX_VALUE。对于每个节点,检查其值是否严格大于低界且小于高界,否则返回false。然后递归左右子树并更新边界。
代码实现:publicbooleanisValidBST(TreeNoderoot){
returnvalid(root,Long.MIN_VALUE,Long.MAX_VALUE);
}
privatebooleanvalid(TreeNodenode,longlow,longhigh){
if(node==null)returntrue;
if(node.val<=low||node.val>=high)returnfalse;
returnvalid(node.left,low,node.val)&&valid(node.right,node.val,high);
}
复杂度分析:O(N)时间,O(N)栈空间。
避坑要点:不能只比较当前节点与左右子节点,必须保证整个子树值都在界内。边界用long防止node.val恰为Integer.MIN_VALUE或MAX_VALUE时出错。考点9:二叉树的最近公共祖先(LCA)算法模板:递归后序遍历。若当前节点为null或等于p或q,直接返回当前节点。递归左子得到left,递归右子得right。若left和right均非空,说明p和q分布在两侧,返回当前节点;否则返回非空的那一侧。记忆口诀:“后序找俩点,两边都不空当前,一边空传另一边”。配套例题:LeetCode236.二叉树的最近公共祖先
题目描述:给定二叉树和两个节点p、q,找到它们的最近公共祖先。
解题思路:使用上述模板。该解法假设p和q一定在树中。若不确定,需额外用全局变量标记是否找到两个节点。
代码实现:publicTreeNodelowestCommonAncestor(TreeNoderoot,TreeNodep,TreeNodeq){
if(root==null||root==p||root==q)returnroot;
TreeNodeleft=lowestCommonAncestor(root.left,p,q);
TreeNoderight=lowestCommonAncestor(root.right,p,q);
if(left!=null&&right!=null)returnroot;
returnleft!=null?left:right;
}
复杂度分析:O(N)时间,O(N)栈空间。
避坑要点:注意p或q可能不存在的情况,此时上述代码会返回非空的节点,但那个节点可能是p或q本身,而非真正的LCA。可与面试官确认假设。考点10:图的遍历与拓扑排序(课程表)算法模板:拓扑排序用于检测有向无环图(DAG)并给出合法顺序。入度表+BFS法:统计每个节点的入度,将所有入度为0的节点入队。出队时将其邻接节点入度减1,若变为0则入队。若最终出队节点数等于总结点数,则无环。记忆口诀:“入度零进队,出队减邻居,入度再为零,加入队列尾;总数对得上,无环可完成”。配套例题:LeetCode207.课程表
题目描述:需要选修numCourses门课,prerequisites给出先修关系,判断是否能完成所有课程。
解题思路:使用入度表+邻接表+BFS。构建邻接表,注意方向为b→a。统计入度,将所有入度为0的课程入队,依次出队并将依赖它的课程入度减一。最后比较完成的课程数与总数。
代码实现:publicbooleancanFinish(intnumCourses,intprerequisites){
int[]indegree=newint[numCourses];
List<List>adj=newArrayList<>();
for(inti=0;i<numCourses;i++)adj.add(newArrayList<>());
for(int[]p:prerequisites){
adj.get(p[1]).add(p[0]);
indegree[p[0]]++;
}
Queueq=newLinkedList<>();
for(inti=0;i<numCourses;i++)if(indegree[i]==0)q.offer(i);
intfinished=0;
while(!q.isEmpty()){
intcur=q.poll();
finished++;
for(intnext:adj.get(cur)){
if(--indegree[next]==0)q.offer(next);
}
}
returnfinished==numCourses;
}
复杂度分析:O(V+E)时间,O(V+E)空间。
避坑要点:注意先修关系中[0,1]表示学0前需学1,所以是有向边1→0,建图时不要弄反。入度数组也要对应正确。考点11:并查集与岛屿数量算法模板:并查集包含两个核心操作:find(路径压缩)和union(按秩合并)。初始化时每个节点自成一个集合。对于二维网格,可将每个格子映射为i*cols+j的一维索引。遍历网格,遇到'1'时尝试与相邻的'1'合并,最后统计不同集合数量。也可使用DFS直接淹没岛屿。记忆口诀:“并查集,find压缩,union按秩;遇一合四邻,再数集合数”。配套例题:LeetCode200.岛屿数量
题目描述:给出二维字符网格,'1'为陆地,'0'为水,计算岛屿数量。
解题思路:这里采用DFS解法(也是高频写法)。遍历网格,遇到'1'时计数+1,然后DFS递归将上下左右相连的'1'全部置为'0',避免重复计数。这是“淹没岛屿”思想。
代码实现:publicintnumIslands(chargrid){
intcount=0;
for(inti=0;i<grid.length;i++){
for(intj=0;j<grid[0].length;j++){
if(gridHYPERLINKi=='1'){
count++;
dfs(grid,i,j);
}
}
}
returncount;
}
privatevoiddfs(chargrid,inti,intj){
if(i<0||i>=grid.length||j<0||j>=grid[0].length||gridHYPERLINKi=='0')return;
gridHYPERLINKi='0';
dfs(grid,i+1,j);dfs(grid,i-1,j);
dfs(grid,i,j+1);dfs(grid,i,j-1);
}
复杂度分析:O(MN)时间,O(MN)栈空间最坏。
避坑要点:DFS前要先检查边界和是否为'0',避免数组越界。将访问过的陆地修改为'0',防止重复。3.4动态规划与贪心专题考点12:完全背包模型——零钱兑换算法模板:完全背包问题,状态定义dp[i]为金额i所需最少硬币数,初始化为一个较大值,dp[0]=0。外层遍历硬币,内层遍历金额从硬币值到总金额。转移方程:dp[i]=min(dp[i],dp[i-coin]+1)。注意内外循环顺序保证每硬币无限用。记忆口诀:“先硬币后金额,正序求最少;不达max莫忘返”。配套例题:LeetCode322.零钱兑换
题目描述:给定不同面额硬币和总金额,计算可以凑成的最少硬币数,若无法凑成返回-1。
解题思路:设dp数组长度为amount+1,填满大数。每遍历一种硬币,对所有金额进行正向更新,因为是求最小,所以允许重复使用。
代码实现:publicintcoinChange(int[]coins,intamount){
intmax=amount+1;
int[]dp=newint[amount+1];
Arrays.fill(dp,max);
dp[0]=0;
for(intcoin:coins){
for(inti=coin;i<=amount;i++){
dp[i]=Math.min(dp[i],dp[i-coin]+1);
}
}
returndp[amount]>amount?-1:dp[amount];
}
复杂度分析:O(amount*n)时间,O(amount)空间。
避坑要点:若要求组合数,则内外循环交换。初始化不能为Integer.MAX_VALUE,否则+1可能溢出,用amount+1即可。考点13:最长递增子序列(LIS)算法模板:动态规划法O(n^2):dp[i]表示以nums[i]结尾的LIS长度,转移为遍历j<i,若nums[j]<nums[i]则dp[i]=max(dp[i],dp[j]+1)。贪心+二分O(nlogn):维护tails数组,tails[k]表示长度为k+1的递增子序列末尾元素的最小值,遍历数组时用二分查找该元素应在的位置并替换。记忆口诀:“LIS动规全遍历,二分贪心tails更善变”。配套例题:LeetCode300.最长递增子序列
题目描述:给定整数数组,找到最长严格递增子序列的长度。
解题思路:先给出O(n^2)解法以确保正确理解。优化时,维护tails数组,每次对num二分找到第一个大于等于num的位置,替换之;若num大于所有tails元素,则追加。
代码实现(O(n^2)版本):publicintlengthOfLIS(int[]nums){
intn=nums.length,max=1;
int[]dp=newint[n];
Arrays.fill(dp,1);
for(inti=1;i<n;i++){
for(intj=0;j<i;j++){
if(nums[i]>nums[j])dp[i]=Math.max(dp[i],dp[j]+1);
}
max=Math.max(max,dp[i]);
}
returnmax;
}
复杂度分析:O(n^2)时间,O(n)空间。
避坑要点:子序列不要求连续,因此必须检查之前所有元素。二分优化版注意边界和替换逻辑,面试时优先写出动规版本再优化。考点14:股票买卖最佳时机(系列通用)算法模板:动态规划通用框架:三维dpHYPERLINK天数[交易次数]。持有状态0为不持有,1为持有。转移时考虑买入、卖出、维持。简化后可用一维滚动。对于无限次交易,只关注持有或不持有的最大利润。记忆口诀:“股票变种多,三维动规框;持有不持有,买卖跟次数”。配套例题:LeetCode121.买卖股票的最佳时机(单次交易)
题目描述:给定数组prices,只能买卖一次,求最大利润。
解题思路:记录遍历过的历史最低价格minPrice,每天计算当天卖出可获利prices[i]-minPrice,更新最大利润。
代码实现:publicintmaxProfit(int[]prices){
intmin=Integer.MAX_VALUE,maxPro=0;
for(intp:prices){
min=Math.min(min,p);
maxPro=Math.max(maxPro,p-min);
}
returnmaxPro;
}
复杂度分析:O(n)时间,O(1)空间。
避坑要点:不要陷入暴力两层循环。单次交易的核心就是找最大差。考点15:贪心策略——跳跃游戏算法模板:维护一个变量farthest表示当前能到达的最远位置。遍历数组,若当前位置i小于等于farthest,则更新farthest=max(farthest,i+nums[i])。如果farthest已经达到或超过末尾,返回true。记忆口诀:“最远可跳贪心记,若能过当前,更新最远;过不去返回假”。配套例题:LeetCode55.跳跃游戏
题目描述:数组每个元素代表从该位置可跳跃的最大长度,判断是否能到达最后一个下标。
解题思路:使用贪心,初始farthest=0。遍历i从0到n-1,若i>farthest则无法到达,返回false;否则更新farthest。最后若farthest>=n-1则true。
代码实现:publicbooleancanJump(int[]nums){
intfarthest=0;
for(inti=0;i<nums.length;i++){
if(i>farthest)returnfalse;
farthest=Math.max(farthest,i+nums[i]);
if(farthest>=nums.length-1)returntrue;
}
returntrue;
}
复杂度分析:O(n)时间,O(1)空间。
避坑要点:注意当i等于farthest且nums[i]==0时,若未到末尾,后续将无法前进,循环内会因i>farthest返回false。提前判断farthest到末尾可以提前返回。本章小结:以上15个核心考点覆盖了大厂算法面试80%以上的题型。每个考点都提供了模板、口诀和精讲例题。请务必逐个亲手实现,并对照解析纠正细节。每掌握一个,就将思维导图中的对应项标为已完成。第四章配套基础自测题(30道选择题)以下自测题均为单项或多项选择题,覆盖四大专题。每题均提供了完整解析,务必逐题消化。第1题:在环形链表检测中,使用快慢指针法,如果链表中存在环,两个指针一定会相遇吗?
A.一定不会相遇
B.一定会在环内相遇,但相遇点不一定是环入口
C.一定会相遇且相遇点恰好是环入口
D.只有当环的长度为偶数时才会相遇答案与解析:B。快慢指针在有环链表中必然在环内某点相遇,但该点不一定是环入口。环入口需要第二轮同步移动才能找到。A错误,C错误,D错误,相遇与环长奇偶无关。第2题:盛最多水的容器问题中,双指针每次移动的是哪一边的指针?
A.移动数值较大的指针
B.移动数值较小的指针
C.移动左右两边之中任意一个
D.同时移动两边答案与解析:B。移动高度较小的指针,因为面积由较小的高度和宽度决定,移动较大指针只会减少宽度而不会带来高度补偿,必然导致面积减小,因此不会错过最优解。第3题:滑动窗口解决最长无重复字符子串时,left指针的更新方式为?
A.每次只向右移动一位
B.直接跳到重复字符的上一次出现位置
C.取当前left与重复字符上次出现位置+1的较大值
D.保持不变答案与解析:C。left=max(left,index[char]+1)确保left不会回退,且能跳过重复字符。B选项如果不取max,在遇到更早出现的其他字符时可能导致left回退,窗口失效。第4题:反转链表II中,使用头插法反转区间链表时,pre指针指向?
A.待反转区间第一个节点
B.待反转区间的前一个节点
C.待反转区间的最后一个节点
D.链表头答案与解析:B。pre始终指向待反转区间的前一个节点,固定不动,cur指向pre.next。每次将cur.next摘出插入到pre之后。第5题:LRU缓存设计中,删除尾节点时必须同时从HashMap中移除对应的key,这是因为?
A.不删除HashMap中的key会导致内存泄漏,并且后续查找会返回已删除节点的值
B.只需要维护双向链表即可,不必删除HashMap
C.是为了提高空间利用率
D.多线程安全问题答案与解析:A。如果不从HashMap中删除,会存在键值对的引用残留,导致get时可能返回已逐出的缓存项,造成数据不一致且内存无法回收,属于逻辑错误。第6题:字母异位词分组时,若想优化时间复杂度至O(NK),应该使用哪种键?
A.排序后的字符串
B.由26个字母计数拼接成的字符串
C.字符串的哈希码
D.字符串反转答案与解析:B。字符计数拼接的字符串长度为常数26,构建键的时间为O(K),比排序O(KlogK)更优,总时间O(NK)。A为O(NKlogK)。第7题:二叉树序列化中使用“#”表示什么?
A.节点值为0
B.空节点
C.分隔符
D.负数答案与解析:B。通常用特殊字符如“#”表示null节点,以保留树的结构信息。第8题:验证二叉搜索树(BST)时,为什么传递边界要用long类型?
A.因为可能包含负数
B.因为节点值可能等于Integer.MIN_VALUE或Integer.MAX_VALUE,使用int会导致边界相等判断错误
C.为了防止递归过深
D.纯粹为了一致性答案与解析:B。若节点值恰为Integer.MIN_VALUE,则低界不可为int的MIN_VALUE,因为值必须严格大于低界,用Long.MIN_VALUE则可容纳。同理MAX_VALUE。第9题:二叉树最近公共祖先(LCA)递归解法,若p或q不在树中,会返回什么?
A.仍然返回正确的LCA
B.返回root
C.返回存在的那个节点,可能不是真正LCA
D.返回null答案与解析:C。如果只有一个节点在树中,递归会返回那个节点,但此时另一个节点不存在,该返回结果不再代表LCA。因此需事先确认两个节点都在树中。第10题:课程表问题(拓扑排序)中,边的方向应如何建图?
A.[a,b]表示a依赖于b,建边b→a,同时a的入度加1
B.[a,b]表示a依赖于b,建边a→b,b的入度加1
C.无向图
D.以上皆可答案与解析:A。先修课程关系:要学a先学b,所以b是前置,有向边从b指向a,a的入度增加。这样才能正确执行拓扑排序。第11题:DFS计算岛屿数量时,将访问过的陆地改为'0'的目的是?
A.避免数组越界
B.标记已访问,防止重复计数
C.增加空间复杂度
D.方便最后输出答案与解析:B。改为'0'相当于沉没该岛屿,后续遍历不会再重复计数。A不是目的,C错误,D无关。第12题:零钱兑换(完全背包)问题中,内外循环的顺序是?
A.外层金额,内层硬币
B.外层硬币,内层金额,金额正序遍历
C.外层金额,内层硬币,金额倒序遍历
D.外层硬币,内层金额,金额倒序遍历答案与解析:B。完全背包求最小或最大个数,推荐外层硬币内层金额正序,这样可以复用同一硬币。若为01背包则内层金额倒序。第13题:最长递增子序列的O(nlogn)解法中,tails数组的含义是?
A.长度为i的递增子序列的最小末尾值
B.原数组中最长递增子序列
C.长度为i+1的递增子序列的最小末尾值
D.存放所有递增子序列答案与解析:C。tails[k]表示长度为k+1的递增子序列的末尾元素可达到的最小值,利于扩展更长的子序列。第14题:买卖股票单次交易,计算最大利润的正确方法是?
A.暴力双重循环
B.动态规划三维数组
C.遍历记录历史最低价格,并计算当天卖出利润
D.双指针答案与解析:C。一次遍历,维护minPrice,每天计算利润即可。A复杂度高,B虽通用但复杂。第15题:跳跃游戏中,贪心算法的核心变量是?
A.当前位置
B.当前能到达的最远距离
C.当前步数
D.剩余能量答案与解析:B。维护farthest,每次判断i是否超过它,若超过则无法继续,否则更新farthest。第16题:以下哪种情况,快慢指针不能正常工作?
A.链表无环
B.链表长度为奇数
C.链表长度为偶数
D.快指针每次走三步答案与解析:D。快指针每次走三步,在存在环的情况下不一定能相遇(可能永远错过),标准的二倍速是经过数学证明的。其他选项均可。第17题:关于盛水容器,如果高度数组为[1,1],最大容量为?
A.0
B.1
C.2
D.0.5答案与解析:B。左右指针初始在0和1,宽度=1,高度min(1,1)=1,面积=1。第18题:LRU缓存中,双向链表的头尾哑节点的作用是?
A.简化边界操作,避免对头尾节点的null判断
B.增加空间开销
C.提高查找速度
D.完全没有必要答案与解析:A。使用头尾哑节点可以在插入和删除时统一处理,代码简洁且不易出错。第19题:字母异位词分组,当字符串包含大写字母时,应如何处理?
A.排序时统一转为小写
B.大小写敏感,直接排序
C.忽略该字符串
D.以上都不对答案与解析:A或根据题目要求。常规题目通常只含小写,若出现大写,可toLowerCase()统一后再排序。第20题:二叉树序列化时,如果节点值包含负号,例如-10,序列化和反序列化应?
A.特殊处理,使用括号
B.直接toString,反序列化时Integer.parseInt可识别负数
C.替换为其他符号
D.不允许有负数答案与解析:B。字符串中的负号能直接被Integer.parseInt解析,无需特殊处理。第21题:验证BST,若某个节点值等于它的右子节点值,它是否是BST?
A.是
B.否
C.视情况而定
D.二叉树为空时是答案与解析:B。BST要求左子树所有节点值严格小于根节点,右子树严格大于,相等不允许。第22题:LCA问题中,如果p和q是同一个节点,最近公共祖先是谁?
A.p的父节点
B.根节点
C.p本身
D.null答案与解析:C。根据定义,一个节点可以是它自己的祖先,所以返回该节点。第23题:拓扑排序能用于何种图?
A.无向图
B.有向无环图
C.有环图
D.任意图答案与解析:B。拓扑排序仅适用于有向无环图(DAG),若存在环则无法完成。第24题:岛屿数量问题中,将二维网格边界视为水,意味着?
A.边界上不能有陆地
B.边界上的陆地可以向外延伸
C.边界上的陆地仅能向内连接
D.
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026河北兴冀人才资源开发有限公司劳务外包岗招聘1人参考题库(预热题)附答案详解
- 2026四川九洲芯辰微波科技有限公司招聘采购部副部长等岗位7人笔试题库附完整答案详解【夺冠系列】
- 河道碎石采购计划方案范本
- 2026夏季四川成都濛江投资集团有限公司招聘20人笔试题库及答案详解一套
- 2026湖南邵阳市邵东市农业农村局招聘农技推广服务特聘农技员2人参考题库及参考答案详解(精练)
- 2026福建龙岩学院附属幼儿园招聘编外教师若干人备考题库及参考答案详解【综合卷】
- 2026北京化工大学国际教育学院财务管理岗位招聘1人参考题库附答案详解【巩固】
- 医药生物行业深度报告:CXO景气度跟踪专题景气高位运行业绩稳步兑现
- 2026四川雅安市中医医院见习生招录19人参考题库带答案详解(A卷)
- 2026年乌鲁木齐市第126中学招聘模拟试卷及答案详解(各地真题)
- 2025中国南水北调集团新能源投资有限公司社会招聘岗位拟聘人员笔试历年常考点试题专练附带答案详解
- 山东医师定期考核《全科医学》考试题库发布1
- 2026年安徽省高校毕业生三支一扶计划招募试题及答案
- 2026学年浙江省绍兴市一年级语文期末自测专项攻坚题(附答案)详细答案和解析
- 机械通气临床护理
- 电磁污水流量计
- ICU护理中的人文沟通技巧
- 防爆设计施工方案(3篇)
- 运输公司安全生产监督检查制度
- 2026年左心耳封堵术知情同意书
- 警用装备培训制度
评论
0/150
提交评论