注解·剑指Offer
文章平均质量分 60
对《剑指Offer》(第二版)上的算法题进行注解、错误修正。
大桔骑士v
微软程序员,B站账号:大桔骑士v
展开
-
【算法】把字符串转换成整数,树中两个结点的最低公共祖先
本书最后的两道题,作者拿了两个面试案例来呈现,主要是要弄清面试官的意图、考虑周全,有些算法虽然容易,不要轻易下手。在此之上最好写出具有鲁棒性的和好的扩展性的代码,遵循编码规范。面试题67:把字符串转换成整数请你写一个函数StrToInt,实现把字符串转换成整数这个功能。当然,不能使用atoi或者其他类似的库函数。#include<bits/stdc++.h>using na...原创 2018-10-24 20:27:01 · 414 阅读 · 0 评论 -
【位运算,递推】不用加减乘除做加法,构建乘积数组
面试题65:不用加减乘除做加法写一个函数,求两个整数之和,要求在函数体内不得使用+、-、×、÷四则运算符号。加法本质是先各位相加不考虑进位,再把进位和前一步结果各位相加,如此反复直到不产生进位。第①步各位相加不考虑进位在二进制情形下和异或一样;第二步进位仅当二进制是1和1时向高位产生一个进位,故可以作与运算后左移一位,如此反复直到不产生进位。#include<bits/stdc+...原创 2018-10-24 18:57:41 · 243 阅读 · 0 评论 -
【语言特性】带限制地求1+2+...+n
就是一个利用语言特性的题,四种都是C++实现,第三个也可以用纯C实现。面试题64:带限制地求1+2+…+n求1+2+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。解法一(构造函数)创建对象数组即可多次调用构造函数,在调用时操作静态成员。#include<bits/stdc++.h>using ...原创 2018-10-24 17:53:50 · 309 阅读 · 0 评论 -
【算法】扑克牌中的顺子,约瑟夫问题,股票的最大利润
面试题61:扑克牌中的顺子从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王可以看成任意数字。大小王当成0,对其进行排序,统计相邻数字间的空缺总数能否被数组中的0填充。非0数字重复出现,数组一定不连续。#include<bits/stdc++.h>using namespace std;...原创 2018-10-24 15:40:38 · 637 阅读 · 0 评论 -
【交替数组】n个骰子的点数
选择合理的数据结构表述问题;分析模型中的内在规律,并用编程语言表述这种规律。面试题60:n个骰子的点数解法一用递归的方式,每次拿出一个骰子,对1~6点再调用下一层,递归到底更新总数的频数。基本就是一个排列树穷举,有大量的重复计算。作者递归出口是1,而且在第一步时没有减1,感觉非常难理解。我这里改成了递归出口是0,表示剩下0个骰子没判断过,在第一步时就减1,表示把第一个骰子判断了。#inc...原创 2018-10-24 12:17:41 · 491 阅读 · 0 评论 -
【队列】滑动窗口的最大值序列,带max函数的队列
窗口即队列,本质是一样的。面试题59-1:滑动窗口的最大值序列给定一个数组和滑动窗口的大小,请找出所有滑动窗口里的最大值。例如,如果输入数组{2, 3, 4, 2, 6, 2, 5, 1}及滑动窗口的大小3,那么一共存在6个滑动窗口,它们的最大值分别为{4, 4, 6, 6, 6, 5}。用双端队列存储最大值的下标,双端队列在窗口滑动过程中变化更新,其队头元素表示当前窗口中最大值的下标。...原创 2018-10-23 20:51:05 · 757 阅读 · 0 评论 -
【字符串】翻转单词顺序,左旋转字符串
面试题58-1:翻转单词顺序输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串&quot;I am a student. “,则输出&quot;student. a am I”。先对整个字符串翻转,再对字符串中的每个单词做翻转。#include&amp;lt;bits/stdc++.h&amp;gt;using namespace std;//翻原创 2018-10-23 17:00:34 · 573 阅读 · 0 评论 -
【贪心法】和为s的两个数字,和为s的连续正整数序列
面试题57-1:和为s的两个数字输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,输出任意一对即可。两个游标一个在数组最左一个在最右,分别指示最小和最大的数。在循环里每次检查他们的加和,如果小了就把左边游标向右移,因为此时左边游标及其左边的所有数都不可能和当前右边游标及其左边的所有数组成符合条件的数对:而左边游标以左与右边游标以右能...原创 2018-10-23 14:08:33 · 404 阅读 · 0 评论 -
【位运算】复制数组中数字出现的次数
数组中大部分数字都重复出现了k次,这里不妨叫k复制数组。面试题56-1:二复制数组中只出现一次的两个数字一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。用按位异或运算,一个数字按位异或它自己就是0,然后0异或某个只出现一次的数字还是那个数字。按位异或运算具有交换性,所以数组里所有数字按位异或最后得...原创 2018-10-23 10:44:04 · 482 阅读 · 0 评论 -
【二叉树】BST的第k大结点,二叉树的深度,平衡二叉树
面试题54:二叉搜索树的第k个结点给定一棵二叉搜索树,请找出其中的第k大的结点。左边都比中间小,右边都比中间大,所以用中序遍历(左中右)就可以实现按结点的值从小到大遍历,遍历时候进行计数即可。#include&lt;bits/stdc++.h&gt;#include "../Utilities/BinaryTree.h"using namespace std;//递归函数:输入...原创 2018-10-23 08:58:37 · 1116 阅读 · 0 评论 -
【二分查找】在排序数组中查找数字
排序数组里很多二分查找的题目,不能把排序这个性质浪费了。面试题53-1:数字在排序数组中出现的次数统计一个数字在排序数组中出现的次数。例如输入排序数组{1, 2, 3, 3, 3, 3, 4, 5}和数字3,由于3在这个数组中出现了4次,因此输出4。二分查找第一个k和最后一个k,计算它们的距离再+1。#include<bits/stdc++.h>using namespa...原创 2018-10-19 20:46:54 · 1568 阅读 · 0 评论 -
【归并排序,同步指针】数组中的逆序对,两个链表的第一个公共结点
面试题51:数组中的逆序对在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。分成长度1的子数组,在合并之前统计相邻子数组之间的逆序对个数,然后让它们升序合并,升序的最大的一定在最后面,然后再如此反复即可。具体图解见书上。#include<bits/stdc++.h>using namespace std...原创 2018-10-19 19:20:33 · 315 阅读 · 0 评论 -
【打表】第一个只出现一次的字符与字符流内实现
面试题50:第一个只出现一次的字符在字符串中找出第一个只出现一次的字符。如输入"abaccdeff",则输出’b’。输入一共就256种ASCII字符,第一遍扫描把出现次数记到数组里,第二遍边扫描边到数组里去找。#include<bits/stdc++.h>using namespace std;//输入字符数组地址,输出寻找到的第一个只出现一次的字符 char Fir...原创 2018-10-19 16:24:16 · 286 阅读 · 0 评论 -
【DP,记忆化】最长不含重复字符的子字符串,丑数
面试题48:最长不含重复字符的子字符串请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。假设字符串中只包含从’a’到’z’的字符。用f(i)表示以i位置字符结尾的最长不含重复字符的子字符串的长度,则所求的就是i从0~n-1中最大的一个f(i)。在遍历数组时,记录每个字符最后一次出现的位置。①当i号字符之前没有出现过时,f(i)=f(i-1)+1。②当之前出...原创 2018-10-19 14:52:02 · 713 阅读 · 0 评论 -
【DP】礼物的最大价值
面试题47:礼物的最大价值 在一个m×n的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向左或者向下移动一格直到到达棋盘的右下角。给定一个棋盘及其上面的礼物,请计算你最多能拿到多少价值的礼物?之前Python课也做过这题,因为f(i,j)只依赖左边的一个礼物和上边的一个礼物,可以仅用一个数组将路径堵死向下刮,而不需要保...原创 2018-09-28 21:47:59 · 491 阅读 · 0 评论 -
【DP】把数字翻译成字符串
面试题46:把数字翻译成字符串 给定一个数字,我们按照如下规则把它翻译为字符串:0翻译成”a”,1翻译成”b”,……,11翻译成”l”,……,25翻译成”z”。一个数字可能有多个翻译。例如12258有5种不同的翻译,它们分别是”bccfi”、”bwfi”、”bczi”、”mcfi”和”mzi”。请编程实现一个函数用来计算一个数字有多少种不同的翻译方法。DP问题,从上而下思考,从下而上...原创 2018-09-13 20:40:20 · 613 阅读 · 0 评论 -
【算法】数字序列中某一位的数字,把数组排成最小的数
面试题44:数字序列中某一位的数字 数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从0开始计数)是5,第13位是1,第19位是4,等等。请写一个函数求任意位对应的数字。每次跳过一片数字海,每个数字海都是位数一样的数字组成的,这些数字有多少可以算出来。跳不出去时就在这片海里,因为位数都一样,也可以很容易的跳过一些数,确定在某个数...原创 2018-09-13 20:08:40 · 541 阅读 · 0 评论 -
【递归】从1到n整数中1出现的次数
面试题43:从1到n整数中1出现的次数 输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。例如输入12,从1到12这些整数中包含1 的数字有1,10,11和12,1一共出现了5次。给定一个数字,如1~21345,可以从最高位拆开分成1~1345和1346~21345这两部分。前者可以通过递归来解决,而后者注意到后4位能全排列2次,可以单独统计第一位出现的次数,和除了第一...原创 2018-09-13 16:01:14 · 582 阅读 · 0 评论 -
【DP】连续子数组的最大和
面试题42:连续子数组的最大和 输入一个整型数组,数组里有正数也有负数。数组中一个或连续的多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为O(n)。...原创 2018-09-12 09:54:35 · 477 阅读 · 0 评论 -
【大小堆】数据流中的中位数
面试题41:数据流中的中位数 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。书上214~216页的分析非常精彩,感觉再总结些什么都是东施效颦了。215页中间作者有一处笔误,”P2指向的数据是左边部分最小的数”,此处应该是”右边”。#inclu...原创 2018-09-11 21:19:31 · 648 阅读 · 2 评论 -
【算法】最小的k个数
面试题40:最小的k个数 输入n个整数,找出其中最小的k个数。例如输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。解法1还是用Partition函数,存在这样的划分,正好取到第k小的数字为基准数,能够使比其小的数字都在其左边,就找到了最小的k个数。#include<bits/stdc++.h>#include "../Utilit...原创 2018-09-11 20:05:34 · 791 阅读 · 0 评论 -
【算法】数组中出现次数超过一半的数字
面试题39:数组中超过一半的数字 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1, 2, 3, 2, 2, 2, 5, 4, 2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。解法1数字超出一半,随机选中该数字的概率就很大。可以随机选一个数字,然后用快排的Partition划分一下...原创 2018-09-11 19:11:27 · 2069 阅读 · 1 评论 -
【分治法】字符串的排列与其变式题
面试题38:字符串的排列 输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。把第一个字符和后面所有字符交换,则第一个位置可以出现所有种字符。其中又将该字符固定,重复这个过程,即将第二个字符与后面所有字符交换。可见是一个递归问题。#include&lt;bits/...原创 2018-09-11 14:41:22 · 395 阅读 · 0 评论 -
【DLR】序列化二叉树
面试题37:序列化二叉树 请实现两个函数,分别用来序列化和反序列化二叉树。前序、中序、后序三种遍历,任意一个都不能唯一确定一颗二叉树。可以用中序遍历序列和另外两个里的任意一个来确定(用前和后不能唯一确定),但是这样也必须要所有数据都读出来。如果序列化从根开始,那么反序列化在根节点从磁盘读出来的时候也就可以开始了,可以用前序遍历+记录空的方式,只要nullptr也被记录下来,一个前...原创 2018-09-11 10:17:58 · 506 阅读 · 0 评论 -
【LDR】BST转双向链表
这题书上讲的思路很清楚,不过代码里细节太多了。理解完感觉还是和书上讲的有差距的。面试题36:二叉搜索树转排序双向链表 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。中序遍历BST,就是从小到大遍历BST的每个结点。遍历时把左子树(比根小的)最大结点、根节点、右子树(比根大的)最小结点链接起来,如此递归。 #...原创 2018-09-10 15:14:55 · 547 阅读 · 0 评论 -
【复杂链表】复杂链表的复制
面试题35:复杂链表的复制书上有图,不再画了。 请实现函数ComplexListNode* Clone(ComplexListNode* pHead),复制一个复杂链表。在复杂链表中,每个结点除了有一个m_pNext指针指向下一个结点外,还有一个m_pSibling 指向链表中的任意结点或者nullptr。复杂链表比普通的单链表多了一个Sibling域,可以指向任意的一个结点。如...原创 2018-09-10 13:18:53 · 306 阅读 · 0 评论 -
【LRD,DLR】BST的后续遍历序列,二叉树中和为某一值的路径
D是Degree,后续遍历就是LRD,前序遍历就是DLR。面试题33:BST的后序遍历序列 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。后序遍历是左右中,而根据BST的特性,这个序列中的数字大小情况是小大中,以最后一个结点根节点为基准,可以判断这一层是不是符合要求,同时也划分...原创 2018-09-10 10:45:55 · 429 阅读 · 0 评论 -
【BFS】分行层序打印二叉树,分行层序之字形打印二叉树
面试题32-2:分行层序打印二叉树 从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层打印到一行。分行打印,用两个变量一个指示当前行结点数,一个指示下一行结点数。在队列里入栈和出栈时就能维护了。当前行走到0就打完了一行,换行把下一行拿上来。#include&amp;lt;bits/stdc++.h&amp;gt;#include &quot;..\Utilities\BinaryTree....原创 2018-09-10 08:59:59 · 392 阅读 · 0 评论 -
【算法】栈的压入、弹出序列,从上到下打印二叉树
面试题31:栈的压入、弹出序列 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1、2、3、4、5是某栈的压栈序列,序列4、5、3、2、1是该压栈序列对应的一个弹出序列,但4、3、5、1、2就不可能是该压栈序列的弹出序列。用一个栈模拟一下压入和弹出的过程,两个序列不同步地向前走,当压入后栈顶出现要弹出的元素时就...原创 2018-09-09 19:31:56 · 284 阅读 · 0 评论 -
【同步栈】包含min函数的栈
面试题30:包含min函数的栈 定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min函数。在该栈中,调用min、push及pop的时间复杂度都是O(1)。为数据栈设置一个同push同pop的同步栈,记录当前状态下栈中的最小元素。插入新的元素时,只要用O(1)时间取得同步栈中的最小元素,比较一下就知道当前元素是不是最小元素了,如果不是就再插一个和之前一样的。Stack...原创 2018-09-09 18:37:52 · 193 阅读 · 0 评论 -
【算法】顺时针打印矩阵
面试题29:顺时针打印矩阵 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。要想到能一圈一圈的打印,每一圈就是从左到右,再从上到下,再从右到左,再从下到上。每次打印完更新圈的左上角点。剩下的就是找规律,确定边界条件,画图分析起来方便。最后就是整个矩阵打印完的标识,左上角点超出行或列的一半就结束了,因为这个每一圈左右上下都是对称的,到矩阵边缘的距离是一样的,超出一半势...原创 2018-09-09 16:23:34 · 459 阅读 · 0 评论 -
【二叉树】二叉树的镜像,对称的二叉树
继续注解《剑指Offer》算法代码,现在是第四章。面试题27:二叉树的镜像 请完成一个函数,输入一个二叉树,该函数输出它的镜像。书上这章节的意图在画图理解并解决问题,本题就是所有结点的左右子树交换一下。#include<bits/stdc++.h>#include "../Utilities/BinaryTree.h"using namespace std;...原创 2018-09-09 15:40:35 · 772 阅读 · 0 评论 -
【二叉树】二叉树的子结构
面试题26:二叉树的子结构 输入两棵二叉树A和B,判断B是不是A的子结构。树的结点里存的是double类型的值。如果树A根和树B根相同,只要判断树B是不是树A的残疾子树,这个可以单独拿到一个递归函数里。如果不相同,再递归地调用解决问题的函数,判断树A的左子树和树A的右子树。在外层的这个递归函数里,树B是不用取子的,一直往里传,只要判断出了true就不需要树A其它位置的判断了,一直...原创 2018-09-06 15:06:02 · 332 阅读 · 0 评论 -
【链表】反转链表,合并两个排序的链表
面试题24:反转链表 定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。遍历时将结点的next指向前一个结点即可,注意把没反转的子链的头结点记录下来,防止内存泄露。#include&lt;bits/stdc++.h&gt;#include "../Utilities/List.h"using namespace std;//输入链表,输出反转后的链表...原创 2018-09-06 14:15:26 · 347 阅读 · 0 评论 -
【快慢指针】链表中环的入口结点
面试题23:链表中环的入口结点 一个单向链表中包含环,如何找出环的入口结点?包含环的链表,在进入环以后就会一直在环里循环。注意,因为单向链表是只有一个next的,所以链表的环一定是下图左边的形状,而不会像右边这样有走出去的可能: [1]判断有没有环因为进了环就出不来,使用快慢指针,如果走得快的指针追上了走得慢的指针,那么链表就包含环。[2]寻找入口结点只要让...原创 2018-09-06 11:14:29 · 622 阅读 · 1 评论 -
【双指针法】链表中倒数第k个结点
这部分开始,书上讲的是关于编程时鲁棒性(Robust)的问题,提高Robust的有效途径就是进行防御性编程,在编程时就把所有可能出现的操作和误操作都考虑进去,做合适的处理。面试题22:链表中倒数第k个结点 输入一个链表,输出该链表中倒数第k个结点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾结点是倒数第1个结点。例如一个链表有6个结点,从头结点开始它们的值依次是1、2、3、4、...原创 2018-09-06 10:18:56 · 255 阅读 · 0 评论 -
【条件解耦】调整数组顺序使奇数位于偶数前面
面试题21:调整数组顺序使奇数位于偶数前面 调整数组顺序使奇数位于偶数前面题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。可以使用两个指针,一个从左往右,一个从右往左。左边发现偶数后停下,待右边发现奇数后,交换这两个数,如此往复。#include<bits/stdc++.h>using nam...原创 2018-09-06 09:48:05 · 217 阅读 · 0 评论 -
【模式匹配】正则表达式匹配,表示数值的字符串
面试题19:正则表达式匹配 请实现一个函数用来匹配包含’.’和’*’的正则表达式。模式中的字符’.’表示任意一个字符,而’*’表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串”aaa”与模式”a.a”和”ab*ac*a”匹配,但与”aa.a”及”ab*a”均不匹配。基本可以看成编译原理的parser问题,但是找出文法不容易,也没必...原创 2018-09-05 17:03:39 · 1091 阅读 · 0 评论 -
【算法】删除链表的结点
面试题18:删除链表的结点在O(1)时间内删除链表结点 给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。如果从表头开始找到这个结点(指针一样就是找到),需要O(n)的时间,但能确保这个结点就是在这个链表里。可以考虑将下一结点复制到该结点,再将下一结点删除,除了删除末尾结点不能这样做之外,其他情况都是O(1),平均也是O(1),不过需要调用者能确保这个...原创 2018-09-05 15:36:37 · 678 阅读 · 1 评论 -
【大数问题】打印从1到最大的n位数
面试题17:打印从1到最大的n位数 输入数字n,按顺序打印出从1最大的n位十进制数。比如输入3,则打印出1、2、3一直到最大的3位数即999。因为题目没有指定范围,所以是大数问题,要用字符串表示数。书上给了两种做法,一种是实现了自增1的操作,每次自增1并输出;另一种是用全排列来直接实现打印。第一种是有整数自增1的性质的,第二种完全没有数的运算性质,但很适合解决这个问题。#incl...原创 2018-09-05 13:58:29 · 703 阅读 · 0 评论