剑指offer题解笔记
鸟恋旧林XD
无限风光在险峰
展开
-
剑指offer-06:重建BinaryTree
输入二叉树的前序遍历和中序遍历的结果,重建出二叉树。假设输入序列不含重复数字。根据前序遍历和中序遍历结果,可以构建出唯一的二叉树。这是一个基本功。前序序列={根节点,左子树,右子树} 中序序列={左子树,根节点,右子树}二叉树的定义:struct BinaryTreeNode{ int value; BinaryTreeNode * pLeft; BinaryTreeN原创 2017-08-07 11:12:23 · 257 阅读 · 0 评论 -
剑指offer-13:在O(1)时间删除链表结点
给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。4月份找实习时滴滴视频面,就是出的这道题目,当时舍友提示说覆盖即可。分析:一般的单链表中删除节点,遍历该链表,发现下一个是待删点,则删除。从头查找复杂度是O(n),因为我们需要找到待删点的前一个点。题目给定该结点的指针,要删除该结点,直接删则链表就断了。 链表利用指针连接起来,非常灵活。可以把待删节点的下一个节点复制给原创 2017-08-14 22:26:40 · 463 阅读 · 0 评论 -
剑指offer-14:调整数组顺序,奇数位于偶数前面
输入一个整数数组,实现一个函数调整数组的次序。所有奇数位于数组的前半部分,所有偶数位于后半部分。分析:本题思路简单。可维护两个指针,一个从头往后遍历,遇到偶数停下;另一个从后往前遍历,遇到奇数停下;交换顺序。然后继续走,直至两个指针相遇错位。代码:// offer-14-OddEven.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <i原创 2017-08-15 11:19:17 · 250 阅读 · 0 评论 -
剑指offer-15:单链表中倒数第k个结点
输入一个单链表,输出该链表中的倒数第k个结点。链表的尾结点是倒数第1个结点。分析:最简单的思路是遍历链表,得到长度n,则倒数第k个结点就是从头结点开始的第(n-k+1)个结点。从头结点开始走n-k+1步即可找到。上述解法需要遍历链表2次。其实遍历1次也可以。这种题目的套路是设置两个指针。一个指针较快,一个指针较慢。快慢可以有2方面:一是出发的快慢,一个移动的快慢。本题属于两个指针出发的快慢不原创 2017-08-15 14:59:30 · 222 阅读 · 0 评论 -
剑指offer-15:单链表有趣问题-有环-环长度-环入口等(续)
第15题要求找到倒数第k个结点。采用快慢出发不同的指针,卡出k-1的距离,当快指针到尾结点时,慢指针刚好在倒数第k个位置上。还有一些相关题目比较有趣,类似的思路。(1)求链表的中间结点答:设置两个指针,移动快慢不同。快指针每次移动2步,慢指针每次移动1步。两者同时从头结点开始出发。当快指针到达尾结点时,走的路程是n,由于慢指针速度是其一半,则相同时间走的路程就是n/2,恰好位于链表的中间。如果链表中原创 2017-08-15 15:40:10 · 301 阅读 · 0 评论 -
剑指offer-16:反转链表(单链表逆序)
定义一个函数,输入一个单链表的头结点,反转该链表并输出反转后链表的头结点。分析:对当前结点,修改其next指针指向前面结点,则需要有前驱结点的值,同时保存后驱结点的值防止断链。当前结点反转后,当前结点变为前驱结点,后驱结点变为当前结点。循环迭代,直至当前结点为尾结点。代码:// 链表结点定义struct ListNode{ int value; ListNode * pN原创 2017-08-15 16:47:20 · 356 阅读 · 0 评论 -
剑指offer-17:合并两个排序的链表
输入两个递增排序的链表,合并这两个链表,并使得新链表保持增序。分析:此题较为简单。可设置两个指针,分别指向两个链表的头结点。比较值大小,指针分别向后移动比较,直至某个列表为末尾。经看书发现可以用递归思路。第一次比较可得到最小值,此值为合并后链表的尾结点。剩余两段链表继续比较,得到一个次小的结点链上去,依次而下。 代码:// 单链表结点定义struct ListNode{ int原创 2017-08-15 17:07:25 · 226 阅读 · 0 评论 -
剑指offer-19:二叉树的镜像
完成一个函数,输入一个二叉树,该函数输出它的镜像。分析:画图看出,对每个非叶结点,需要交换其左子树和右子树位置。操作相同,可采用递归解决。代码:#include <iostream>using namespace std;struct BinaryTreeNode{ int valuel; BinaryTreeNode * pLeft; BinaryTreeNode原创 2017-08-29 16:48:52 · 286 阅读 · 0 评论 -
剑指offer-23:二叉树的层次遍历
对二叉树进行层次遍历。分析:需要借助队列。将根结点入队。然后当队不空时,弹出队头,并把队头的左右子树入队。队列控制了逐层次序。保证每一层都线入队。代码:/*struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) :原创 2017-09-08 12:33:57 · 376 阅读 · 0 评论 -
剑指offer-24:搜索二叉树的后序遍历
给定一个序列,判断是否是某二叉搜索树的后续遍历序列?分析:二叉搜索树,特点是一棵二叉树,左子树的结点值均小于根结点值,右子树的结点值均大于根结点值。查找时,和根结点比较,从而转向搜索左或右子树,类似于二分查找。后续遍历是左-右-根。则最后一个数字为根结点值。前面小于根的为左子树,大于根的为右子树,递归仍符合该性质。代码:// offer-24-houxubianli.cpp : 定义控制台应原创 2017-09-12 14:31:03 · 363 阅读 · 0 评论 -
剑指offer-31:连续子数组的最大和
一个整形数组,有正数有负数,求所有子数组的和的最大值。复杂度为O(n)。分析:数组中有正数有负数。正数起正作用,负数起副作用。交叉起来亦可能最大子数组的中间包含一个负数,所以判断每个的正负值无意义,需要判断一个序列的和来判断。一个指针往前走,不断加和。当和小于0时说明当前的子数组和为负数,不管谁加上都副作用,可直接抛弃。不用担心从这段中间某位置加起会不会好。我们原则是一负就抛弃,如果负数在前面原创 2017-09-12 15:20:42 · 304 阅读 · 0 评论 -
剑指offer-21:包含min函数的栈
定义栈的数据结构,在该类型中实现一个能够得到栈的最小元素的min函数,该栈中调用min, push, pop的时间复杂度都是O(1)。分析:要保持栈原本性质,就需要一个栈A存放原始数据要得到栈当前最小元素,需要一个辅助栈B,专门存储当前的最小值A中压栈,B中压当前的最小值(要么是新的最小,要么是B栈顶最小)代码:// offer-21-stack_min.cpp : 定义控制台应用程序的入原创 2017-09-08 10:46:44 · 318 阅读 · 0 评论 -
剑指offer-12:打印1到最大的n位数
输入数字n,按顺序打印从1到最大的n位十进制数。 例如:n=3,则打印1,2,3都999。分析:此题并未给出n的范围,若取n=10,则int表示溢出。所以考虑大数问题。用字符串或者数组可以表示大数。本质是全排列问题,即n位每个位从0-9排列,可用递归实现。打印数字时,需要考虑从第一个非0的元素开始打印。// offer-12-print_n.cpp : 定义控制台应用程序的入口点。原创 2017-08-14 21:03:56 · 247 阅读 · 0 评论 -
剑指offer-11:数值的整数次方
实现函数 double Power(double base, int exponent)。不使用库函数,不考虑大数问题。分析:此题难度较小,主要是考虑周全边界情况。数的n次方,n分为0,负数和正数特殊情况:底数为0,指数为负数时,直接返回,否则0作分母底数是否等于0,double型判断时根据差是否在很小范围内计算指数时,可以平方计算,可达到O(logn)O(\log n)开方时除2可右移原创 2017-08-14 21:00:20 · 281 阅读 · 0 评论 -
剑指offer-08:旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组末尾,称为数组旋转。输入一个递增排序的数组的一个旋转,输出该旋转数组的最小元素。如递增数组为[1,2,3,4,5],旋转数组为[3,4,5,1,2]。分析:二分查找。首先设置头尾指针,一般的头元素大于等于尾元素。然后找到中间位置的数字。若中间位置数字比头元素大,说明最小值在后半段。将头指针移动到中间位置二分;若中间位置比尾元素小(肯定也<=头元素),说明最小原创 2017-08-08 11:37:48 · 229 阅读 · 0 评论 -
剑指offer-09:递归和循环,斐波那契数列
当需要重复的计算相同问题时,通常可用递归或者循环迭代两种办法。如计算1+2+…+N问题。// 递归实现int add1toN_recursive(int n){ return n <= 0 ? 0 : (n + add1toN_recursive(n-1));}// 循环实现int add1toN_Iterative(int n){ int result = 0;原创 2017-08-08 11:51:35 · 253 阅读 · 0 评论 -
剑指offer-10:二进制中1的个数
左移、右移运算符// 把m左移n位。最高位丢弃,最右边补0m << n/* * 把m右移n位。最右边丢弃,最左边分情况 * 无符号数:用0填补最左边 * 有符号数:符号位填充最左边 */m >> n 实现一个函数,输入一个整数,输出该整数二进制表示中1的个数。如9二进制为1001,输出2。思路:对于一个int型整数,系统以32位表示。我们可以设置一个无符号型数1,不断左移1和该数与原创 2017-08-08 16:06:51 · 911 阅读 · 0 评论 -
剑指offer-18:判断树的子结构
输入两棵二叉树A和B,判断B是不是A的子结构。分析:在树A中查找与根节点值一样的结点,若找到,继续判断左右子树是否相等;若找不到,则判断以当前根节点的左右子树为根节点的子树。涉及两个递归。一个是根节点遍历的递归。一个是根结点相同时,左右子树是否相同的递归。// 判断根结点是否相同的递归bool HasSubTree(BinaryTreeNode * pRoot1, BinaryTreeNo原创 2017-08-16 17:10:06 · 276 阅读 · 0 评论 -
剑指offer-01:赋值运算符函数
题目:实现一个string类,为该类型添加赋值运算符函数。关注点:返回值的类型应声明为该类型的引用,这样才可连续赋值传入参数的类型应声明为常量引用,提高灵活性释放实例自身已有内存判断传入参数是否为本身mystring & mystring::operator=(const mystring &o){ // 判断是否为本身 if (this == &o)原创 2017-08-04 16:08:31 · 530 阅读 · 0 评论 -
剑指offer-02:设计一个单例模式的类
设计一个类,我们只能生成该类的一个实例。分析:只能生成一个实例的类,实际上是单例模式的类型。为防止用户生成新对象,将构造函数声明为私有或受保护生成一个对象,可以将其用静态成员函数来记录,指向这个对象的指针声明为静态变量,存放在静态存储区,把该类的对象用new来构造放在堆中// vs 2015 #include "stdafx.h"#include <iostream>#include原创 2017-08-05 10:51:11 · 264 阅读 · 0 评论 -
剑指offer-03:二维数组(行列递增)的查找
一个二维数组中,每一行都按照从左到右递增的顺序排列,每一列都按照从上往下递增的顺序排列。完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。初看题目,容易想到既然是有序数组,可按二分的思想查找。选取某个数字刚和和要查数相等时返回;选取数字小于要查找的数字,查找放到当前位置的右方或者下方;若大于要查找的数字,查找放在当前位置的上方或者左方。然而分区域后,情况变得复杂,要查找的区原创 2017-08-06 16:42:04 · 2096 阅读 · 0 评论 -
剑指offer-04:字符串替换空格
题目:实现一个函数,把字符串中的每个空格替换为”%20”。题目背景:网络编程中URL参数中的特殊字符,如空格,#等需要转换为服务器可以识别的字符,转换规则是在%后面加上其ASCII码的两位十六进制表示。空格的ASCII码是32,十六进制为0x20,空格被替换为%20。首先:新字符串还是原字符串?若是新字符串,则分配可容纳空间,然后扫描原字符串,遇见空格特殊处理,其余字符原样复制。这没啥难度。若是原原创 2017-08-06 20:27:49 · 332 阅读 · 0 评论 -
剑指offer-05:从尾到头打印链表
输入一个链表的头结点,从尾到头反过来打印每个结点的值首先复习下链表的基础:struct ListNode{ int m_value; ListNode * p_next;};《数据结构》书上搞了头结点,即new了一个数值为空的结点,指向首结点。而下面代码直接从首结点(左)开始。开始还有些纠结,后来想明白了无论哪种都是可以的,只要搞清楚道理,操作正确即可。实践发现,搞个头结点还是原创 2017-08-06 22:06:04 · 267 阅读 · 0 评论 -
剑指offer-07:两个栈实现队列
用两个栈实现队列。队列声明如下,实现其两个成员函数,分别完成在队尾插入和队头出队。// 队列模版,可实现其中元素自定义template <typename T> class CQueue{public: CQueue(void){}; ~CQueue(void){}; void appendTail(const T& node);// 队尾入队 T delet原创 2017-08-07 12:19:01 · 236 阅读 · 0 评论 -
剑指offer-07(1):两个队列实现栈
用两个队列实现一个栈。姊妹问题:用两个栈实现队列分析:队列插入可直接等同于栈的压栈。弹栈时,需要将队列1前n-1个元素存放到队列2中。将队列1的最后一个元素pop,然后把2中的元素赋值回去。// offer-7-1-QueueToStack.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>#include <queue>原创 2017-08-07 12:58:39 · 285 阅读 · 0 评论 -
剑指offer-22:栈的压入弹出序列
输入两个整数序列,第一个表示压栈顺序,判断第二个序列是否为该栈的弹出序列?分析:此题解法就是人判断时的做法。想想人工判断时的步骤,先设一个辅助栈。大循环:弹出序列完成初始栈为空,按照压栈顺序压入。当栈顶元素不等于弹出序列顶时,继续压栈。直至压栈顺序压完,或者当前栈顶和弹出序列顶相同出小循环,判断哪种情况出来的。如果栈顶和弹出序列顶不同,说明没等到,跳出大循环。否则属于遇到相等的,原创 2017-09-08 11:57:00 · 776 阅读 · 0 评论