剑指offer题目整理

依据解题方法划分:

一、根据数据结构划分
1.链表
题18,O(1)时间内删除链表的某个节点:将要删除链表的下一个节点复制到本节点,本节点指针与下一个节点的指针指向的内容互换。头节点直接删除,尾节点扔需遍历。
题24,反转链表:增加一个pre,一个cur,一个next
题18-2,删除排序链表中重复节点,增加一个pre,一个cur,一个next
题52.两个链表的公共节点。通用分析,链表相交,为Y字型。(1)法1,两个辅助栈,全量压栈,倒着比较。(2)法2,需注意长度不同时,遍历1次获得长度,然后长的链表先走差异的步数,再共同走,直至相同。
2.树
题8,二叉树的下一个节点,找规律,一个节点右子树一直沿左侧遍历,或一个节点无右子树,则父节点为下一个节点。
题54.二叉搜索树的第k大节点。实际为中序遍历二叉树。左,判断,右的顺序编写代码。
题55.1.二叉树的深度,递归遍历左子树,右子树深度,较大的+1
题55.2.判断二叉树是否为平衡二叉树。法1:递归遍历左右子树深度,判断。缺点:重复遍历了子节点。法2:(1)采用后序遍历,先遍历左和右,最后判断父节点是否为平衡二叉树,即差在1以内。(2)由下向上,每个节点只1次。
题68.寻找二叉树最低的公共祖先(1)遍历回溯寻找路径,前序(2)路径存放至链表,避免多次遍历,提高效率(3)比较链表相同节点,一直比,求最低(4)递归的话,最后一次子树中同时存在2节点,下一次子树不同时存在两节点,即找到。
3.栈
题6,从尾到头打印链表:元素插入栈,判断栈不为空则打印
题9,两个栈实现队列:尾插,直接插入即可。头删,栈1数据转栈2,删除栈2顶部
题30,包含min函数的栈:定义两个栈,一个存数据,一个存该数据对应的最小值。
题31,栈的压入弹出序列:构造辅助栈,压入元素,与pop相同则弹出。注意边界条件,待压入为空时,辅助栈为空时,不相等时。true的条件为待pop的队列为空,辅助栈为空,即待push的队列也为空。
题33.二叉树的后序遍历:取后序遍历的倒序,根,右,左。单调栈压入根节点,应依次增大。出现小则都小于原根节点,不满足则false。
4.队列
题32,层序遍历二叉树:弹出一个根节点,压入其左右子节点至队列的末尾,即可实现层序遍历。
题59.1.队列最大值,滑动窗口内部数据的最大值。(1)双端队列(2)队列头存储当前窗口最大值(3)队列末尾存储可能的最大值(4)不断替换队列尾(5)窗口滑过以后替换队列头(6)代码中第一段先生成第一个窗口(7)不断向后滑动
题59.2.队列最大值,队列实现max,push_back,pop_front(1)内置2个双端队列,一个存最大,一个存数据(2)最大队列,末尾存可能的最大值(3)最大队列头存当前最大(4)弹出时比较当前最大是否是弹出元素
5.字符串
题20.表示数值的字符串:(1)空格(2)判断int(3)判断uint,即+和-
题45.数组排成最小数,转为字符串,定义字符串比较规则。strcpy和strcat函数,判断字符串大小,即为拼接后数字大小。
题58.1.翻转字符串,翻转句子中的单词顺序,每个单词内容不变(1)原串->整体翻转(2)空格分割子串(3)翻转单个子串
题58.2.左旋字符串,部分字符移动到字符串后方。(1)原串分割(2)翻转分割后每个子串(3)整体翻转(4)注意:2和3步可颠倒,但是必须分割。
题67.字符串转数字,边界条件判断。最大正数0x7FFFFFFF,最小负数,(signed int)0x8000000
6.数组
题4,二维数组中的查找:根据题目特点划定范围,自边角查找到中心
题43,1-n整数中1出现的次数,找规律,法1:取最高位,计算其他位数,剩余散位,法2:对每位分别计算可能性。该位的前1位为1,大于1,为0三种情况。
题44,数字序列中的某一位,找规律,1位数字为10,2位数字一共90 * 2,三位一共900 * 3
题49.丑数(1)及时更新t2,t3,t5,其中t2表示乘2刚好大于前一个丑数的数。(2)及时比较m2,m3,m5,m2表示t2乘2后得到的数。将3个数最小值存起来。(3)分配数组来存储
题56.1.数组中数字出现的次数,只出现1次的两个数。(1)异或获取保留数字(2)从保留数字中寻找最后1位为1的数字,并记录位数(3)根据2的结果对数据分组(4)分别异或,获得剩余的2个数
题56.2.数组中唯一只出现一次的数字。数组中除了1个数字只出现1次,其他3次。法1:哈希表,空间O(n),法2:排序,时间O(nlogn),法3:(1)32位数组,计算每位出现的次数,可被3整除(2)剩余的不可整除的即为数字。空间o(1)时间o(n)
题57.1.和为s的数字,递增数组,输出和为s的数字对。(1)双指针,一前一后(2)求和,大则移动右指针往左走,小则移动左指针往右走。时间o(n)
题57.2.和为s的连续正数序列,(1)small和big,和为sum。(2)求和满足则输出,不满足。大于则减去small,小于则增加big。
题61,扑克牌顺子(1)优先排序(2)大小王指定为0,统计0的个数(3)统计是否重复(4)统计中断个数(5)比较中断个数和大小王个数
题63,股票的最大利润。法1:双重遍历,每个值都计算一次卖出,求最大。法2:(1)记录前面最小值(2)记录当前i与最小值差,即最大利润(3)遍历一次。
题64,求1~n的和,不使用四则运算。法1:构造函数,法2:虚函数,双重!!,非0,则为true,负责累加,0则为false,可结束循环。法3:c语言,函数指针。法4:模板,显示具体化,用于结束递归。模板函数,用于累加。
题66.构建乘积数组,0~n-1,b[i]=a[i]*…*a[i-1]*a[i+1]a[n-1],不用除法。(1)分解为c[i] = a[0]a[i-1]和d[i] = a[i+1]…*a[n-1](2)c[i] = c[i-1]a[i-1],d[i]=d[i+1]a[i+1],d为倒序
7.vector
题29,顺时针打印矩阵:画图分解,分治思想,判断循环起始和结束条件。判断1234步四种压数据的条件。
8.map
题3,数组中重复的数字:法1:利用map,法2:利用下标
题35,复杂链表的复制:map<node
, node
>
题50,第一个只出现一次的字符,最简单的哈希表,数组,字符上限为255个。出现即+1,最后遍历输出次数为1的数据(2)字符流中只出现一次的字符,需实时更新,出现多次记录为-2,初始化为-1。定义类方法插入和查找。
题48.最长不含重复字符的子字符串,(1)记录每个字符上次出现的位置(2)计算最大长度
9.set
题40,数组中最小的k个数。(1)寻找存放k个数的容器(2)插入k个数直到满(3)k个数中找到最大值(4)有可能删除并替换
10.堆
题41,数组中的中位数,左侧最大堆,右侧最小堆,合理利用push_heap,pop_heap,less,greater函数
11.list
题62.圆圈中最后剩下的数字,约瑟夫环问题。从0开始删除第m个数字。法1:list模拟环形链表,指向最后时移动至开头。(2)注意需保存cur和next,且都为迭代器操作(3)list.erase(cur)删除元素后自动指向下一个,需赋值cut=next
法2:数学分析,算公式,f(n,m) = [f(n-1, m)+m] % n,n>1

二、根据算法划分:
1.双指针
题5,替换空格:尾部双指针向前复制
题21,奇数位于偶数前面:双指针一前一后,前偶后奇,交换
题22,链表中倒数第k个节点:双指针从前遍历
题23,环的入口节点:(1)快慢指针判断环是否存在,存在返回节点必为环内节点(2)计数环节点数目(3)快慢指针重走链表
题57.1.和为s的数字,递增数组,输出和为s的数字对。(1)双指针,一前一后(2)求和,大则移动右指针往左走,小则移动左指针往右走。时间o(n)
题57.2.和为s的连续正数序列,(1)small和big,和为sum。(2)求和满足则输出,不满足。大于则减去small,小于则增加big。
2.递归
题10,斐波那契数列,青蛙跳台阶
题6.从尾到头打印链表:递归到尾部
题7,重建二叉树:利用树的特性,前序遍历为根节点,中序遍历中寻找根节点,左侧为左子树,右侧为右子树
题17,打印从1到最大的n位数:数字转为字符串防止越界,递归遍历至最低位再打印
题16,数值的整数次方:0次方,负数次方,正数次方,结合递归,负数最终蜕化为-1
题19,正则表达式匹配:结合分治思想,分为(1)直接忽略下一个*(2)当前匹配,字符+1,跳过下一个*(3)当前匹配,仅字符+1(4)顺序比较下一个,其中方式3通过第二次递归来实现,省略代码。
题25,合并两个排序链表:递归比较
题26,树的子结构:递归比较左子树,右子树
题27,树的镜像:递归寻找叶节点
题28,判断树是否对称:判断前序遍历和对称前序遍历,即右中左,是否对称,对称则二叉树是对称的。1树左对2树右,1树右对2树左
题33,二叉树的后序遍历:注意划分mid,左右根,判断右子树存在情况下,若出现小于根节点的值,直接返回报错。
题34,二叉树中和为某一值的路径:判断叶节点,判断和,push后需pop
题37,序列化和反序列化二叉树:前序遍历,输入字符串处理,list存放,反序递归
题60,n个骰子的点数,公共逻辑(1)和为n~6n(2)数组长度为6n-n+1。法1:(1)次数存放为[s-n](2)分为1个骰子和其他所有的,求和
法2:双数组,(1)下一轮循环的和n,为上一轮的n-1…n-6。(2)注意起始次数为6个1,都有可能(3)注意和为k-nk(4)注意清空数组,0-k以及k-nk都需要清空。因为可能出现1+1+1+1+1+1=6这种情况,即每次都很非,导致和很小。
(1)dfs
题36,二叉搜索树与双向链表:dfs寻找最左,pre记录,然后找右节点

3.函数调用
题6.从尾到头打印链表:压入vector,然后调用reverse函数
4.分治思想
(1)全排列思想:
题38.1,字符串的全排列:判定条件为前后元素相同则不换,分为1和其后的部分
题38.2字符串的全组合:
遍历从1到n所有的子串,当求长度为m(1≤m≤n)的组合时,可以把那个字符分成两部分:第一个字符和其余所有的字符。
(1)组合包含第一个字符,则下一步在剩余字符里选取m-1个字符。
(2)组合不包含第一个字符,则下一步在剩余的n-1个字符中选取m个字符。
皇后棋盘:全排列思想,判定条件为对角线
正方体三面和相同:判定条件修改为三面和相同
5.查找方法
(1)二分
题11,旋转数组的最小数字:首尾指针判断数字大小,不断取中点
题39,数组中出现次数超过一半的数字,分组查找中位数。法2,根据数字次数,重复+1不重复-1,最后一个+1的数字,即为要求的数字。
题40,数组中最小的k个数,比数组第k个数小的数组位于数组左侧即可。
题53.1,排序数组中查找一个数字出现的次数。二分法查找第一次出现,查找最后一次出现,相减。
题53.2,0~n-1中缺失的数字。注意也为递增数组,法1:n*(n-1)/2求和,与目前的和sum相减。法2:(1)转换问题为下标不同的第一个数字。m缺失,则m+1的下标为m。(2)二分法判断该数字的下标是否与该数字相同,不同则处理。
题53.3,递增数组中数字与下标相同的数字。法1:遍历。法2:二分查找,比对数字与下标。数字大于下标,后续都大于,找左边。
6.排序
题51.数组中的逆序对,(1)采用归并排序的思路,先分组,比较大小。(2)通过排序来去重,并不断移动指针位置。(3)前->后,多少个temp[i]>temp[j],后->前,多少个temp[j]小于temp[i]。默认i为前段,j为后段。
7.位运算
题15,二进制整数中多少个1:
int count = 0;
while (n)
{
count++;
n = (n - 1) & n;
}
题65.1.不用加减乘除做加法。(1)普通10进制找规律,相加,进位,相加(2)二进制看,相加,进位,相加(3)位运算,异或,位与,左移,相加(4)进位需与相加结果一直相加,有进位则循环
题65.2.不使用新变量,交换a和b的值。法1:加减法,a=a+b,b=a-b,a=a-b。法2:基于异或运算,a=ab,b=ab,a=a^b
8.回溯法
题12,矩阵中的路径:二维vector,判断是否已访问过,是否存在路径
题13,机器人的运动范围:(x,y)坐标采用pair来组合,二维vector判断是否已访问过,判断和
9.动态规划
题14.1,剪绳子:temp=result2[j] * result2[i -j],整理公式,j最大为i的一半
题42,连续子数组的最大和,dp[i] = max((dp[i - 1] + nums[i]), nums[i]);注意和滑窗的区别,此题用滑窗,边界范围不好确定,并不是负数直接停止。法2:sum和为负数,直接舍弃从当前元素开始重新计算。
题46.数字翻译为字符串(1)从右往左,消除重复子问题(2)公式为f(i) = f(i + 1) + g(i,i+1)f(i+2),g(i,i+1)为取值为0和1取决于,生成的数字是否为两位数。
题47.礼物的最大值(1)二维数组,f(i,j) = max(f(i-1,j),f(i,j-1))+gift[i,j](2)一维数组,f(i,j)中,f(i,1),f(i,2)…f(i,j-1)为当前行,f(i,j)实际为f(i-1,j),f(i-1,j+1)…f(i-1,n-1)最大值,求max
题48.最长不含重复字符的子字符串,f(i)表示的是以i字符结尾的,不包含重复字符的子字符串的最长长度。遍历一次后,还需记录所有中最大值。
10.贪心
题14.2,剪绳子2:采用贪心,优先3,其次2,因为4=2
2
11.dfs
12.摩尔投票法
题39,,不同相消,相同保留
13.滑动窗口
题48.最长不含重复字符的子字符串,(1)每次滑动右侧窗口,将新进字符与原有的比较(2)每次都需遍历一次字符(3)更新最大值

题1,赋值运算符函数

错误:
p233页,可向右或者向下移动
p212页,setIterator iterGreatest = leastNumbers.begin()应为end(),end是最大的,需删除
p270页,第k大,题解为第k小

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值