![](https://img-blog.csdnimg.cn/20201014180756754.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
剑指offer系列
文章平均质量分 67
Number_0_0
努力的从小菜鸡变成战斗机!!!
展开
-
实现1+2+3...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句(A?B:C)
通常求1+2+…+n除了用公式n(n+1)/2之外,无外乎循环和递归两种思路。由于已经明确限制for和while的使用,循环已经不能再用了。同样,递归函数也需要用if语句或者条件判断语句来判断是继续递归下去还是终止递归,但现在题目已经不允许使用这两种语句了。 我们仍然围绕循环做文章。循环只是让相同的代码执行n遍而已,我们完全可以不用for和while达到这个效果。比如定义一个类,我们new一含有原创 2017-07-14 10:17:38 · 922 阅读 · 0 评论 -
查找一个字符串中第一个只出现两次的字符。
题目:查找一个字符串中第一个只出现两次的字符。比如:“abcdefabcdefabc”中第一个只出现两次为‘d’,要求时间复杂度为O(N),空间复杂度为O(1)。由于本体的特殊性,我们可以定义一个非常简单的哈希表。。字符(char)是一个长度为8的数据类型,因此总共有256中可能。于是我们创建一个长度为256的数组,每个字母根据其ASC码值作为数组的下标对应数组的一个数字,而数组中存储的是原创 2017-07-19 10:51:10 · 730 阅读 · 0 评论 -
输入两棵二叉树A,B,判断B是不是A的子结构。
要查找树A中是否存在和树B结构一样的子树。我们可以分为两步: 第一步在树A中找到和B的根节点一样的值一样的结点R,第二步在判断树A中以R为根节点的子树是不是包含和树B一样的结构。 树的结点:struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x原创 2017-07-19 13:52:10 · 964 阅读 · 0 评论 -
链表逆置(给出一个链表和数k)
题目: 给出一个链表和一个数k,比如链表1→2→3→4→5→6,k=2,翻转后2→1→4→3→6→5,若k=3,翻转后3→2→1→6→5→4,若k=4,翻转后4→3→2→1→5→6,用程序实现Node* RotateList(Node* list, size_t k).思路分析: 将链表中长度为K的一段翻转后再拼接回去,形成新链表。ListNode* ReverseList(ListNo原创 2017-07-23 12:37:39 · 569 阅读 · 0 评论 -
二进制中1的个数
解法一: 首先把i和1做与运算,判断I的最低位是不是为1。接着把1左移一位得到2,在和i做与运算,就能判断i的此地为是不是1…这样反复左移,每次都能判断i的其中一位是不是1。代码如下:int NumberOf1(int n){ int count = 0; unsigned int flag = 1; while (flag) { if (原创 2017-07-20 09:33:12 · 324 阅读 · 0 评论 -
判断一棵二叉树是否是平衡二叉树/求一颗二叉树的镜像
根据平衡二叉树的定义,如果任意节点的左右子树的深度相差不超过1,那这棵树就是平衡二叉树。 首先编写一个计算二叉树深度的函数,利用递归实现。int Depth(TreeNode*pRoot){ if (pRoot == NULL) return 0; else { int ld = Depth(pRoot->left); in原创 2017-07-24 11:54:33 · 402 阅读 · 0 评论 -
求解两个集合的差集,集合是以单向链表存储
题目: 已知集合A和B的元素分别用不含头结点的单链表存储,函数difference()用于求解集合A与B的差集,并将结果保存在集合A的单链表中。例如,若集合A={5,10,20,15,25,30},集合B={5,15,35,25},完成计算后A={10,20,30}。 链表结点的结构类型定义如下: struct node { int elem; node* next; };原创 2017-07-25 11:12:45 · 621 阅读 · 0 评论 -
判断一颗树是否是完全二叉树
一.问题描述 有一棵树判断该树是否是完全二叉树?二.问题分析1.完全二叉树的定义? 判断一棵树是否是完全二叉树,首先要知道什仫是完全二叉树?完全二叉树就是除最后一层外,每一层上的结点数均达到最大值;在最后一层上只缺少右边的若干结点。 [html] view plain copy若设二叉树的深度为h,除第转载 2017-07-27 11:19:51 · 4829 阅读 · 2 评论 -
要求对数组a进行排序,要求时间复杂度为O(N)
题目: int a[] = {12,13,12,13,19,18,15,12,15,16,17},要求对数组a进行排序,要求时间复杂度为O(N) 。void sort(int *arr, int size){ if (arr == NULL || size <= 0) exit(1); int data[20]; memset(data, 0, S原创 2017-08-04 23:04:20 · 1593 阅读 · 0 评论 -
无序数组的中位数
题目:求出一个无需数组的中位数。例:{2,5,4,9,3,6,8,7,1}的中位数为5,{2,5,4,9,3,6,8,7,1,0}的中位数为4和5。 要求: 不能使用排序。 思路1:将数据平均分配到最大堆和最小堆中,并且保证最小堆中的数据存放的数据都比最大堆中是数据大,那么此时最小堆堆顶的元素一定是中位数。 那么如何保证最小堆中的元素,都比大堆中的元素大 (1)遍历数组,将第i个数插入堆原创 2017-08-05 10:05:40 · 1373 阅读 · 1 评论 -
将N个字符的数组,循环右移K位。
要求:时间复杂度为O(N) 思路: 将一个字符串分成两部分,X 和Y 两个部分,在字符串上定义反转的操作X^T,即把X 的所有字符反转(如,X=”abc”,那么X^T=”cba”),那么我们可以得到下面的结论: (X^TY^T)^T=YX。显然我们这就可以转化为字符串的反转的问题了。 就拿abcdef 这个例子来说,若要让def 翻转到abc 的前头,那 么只要按下述3 个步骤操作即可:原创 2017-08-05 10:28:58 · 841 阅读 · 0 评论 -
删除字符串中重复字符。
题目:删除字符串中重复字符。如果可以,优先删除重复字符中排在比他小字符前面的字符。 比如,输入:bbcacdww;输出:bacdw 分析:如果根本不允许开设数组,则只能就地进行字符串去重,那么可以依次访问字符串中的字符,并删除从该字符串开始到结尾的所有相同字符。时间复杂度为O(n^2 )。void removeDuplicate(char s[]){ int i = 0; whil原创 2017-08-05 11:51:40 · 11708 阅读 · 0 评论 -
由前序遍历和中序遍历重建二叉树
题目: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含有重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出所示的二叉树并输出他的头结点。struct BinaryTreeNode{ int m_nValue; BinaryTreeNode *m_pLef原创 2017-07-28 14:36:44 · 556 阅读 · 0 评论 -
C语言模式实现C++继承和多态
继承与多态的概念 继承:是面向对象最显著的一个特性。继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力,已有类被称为父类/基类,新增加的类被称作子类/派生类。 多态:按字面的意思就是“多种状态”。在面向对象语言中,接口的多种不同现方式即为多态。同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。简单说就是允许基类的指针指向子类的对象原创 2017-07-28 15:07:48 · 353 阅读 · 0 评论 -
一个数组中有一个数字的次数超过了数组的一半,求出这个字符
题目: 一个数组中有一个数字的次数超过了数组的一半,求出这个字符。 如:int a[]={2,3,2,2,2,2,2,5,4,1,2,3},求出超过一半的数字是2。解法一: 可以借用排序算法的思想,因为其中的一个数字超过了数组的一半,所以不论该数字是大还是小,数组中间的元素即为所求。解法二: 思想是:如果一个数出现的次数超过数组一半的长度,那么就是说出现的次数比其他所有数字出现的次数还要多。原创 2017-07-22 11:37:00 · 401 阅读 · 0 评论 -
替换空格
题目:-替换字符串中的空格为$$$。要求时间复杂度为O(N) 方法 我们可以先遍历一次字符串,这样就能统计出字符串中空格的总数,并可以由此计算出替换之后的字符串的总长度。每替换一个空格,长度增加2,因此替换以后的字符串的长度等于原来的长度加上3乘以空格数目。 我们从字符串的后面开始复制和替换。首先准备两个指针,P1和P2. P1指向原始字符串的末尾,而P2指向替换之后的原创 2017-07-18 13:30:44 · 550 阅读 · 0 评论 -
合并两个有序链表,合并以后的链表依旧有序。
解法一:Node *ListMerge1(Node *head1,Node *head2)//采用递归的方法实现 { if(head1==NULL) return head2; if(head2==NULL) return head1; Node *head=NULL; if(head1->value < h原创 2017-07-14 10:42:16 · 497 阅读 · 0 评论 -
逆置/反转单链表+查找单链表的倒数第k个节点,要求只能遍历一次链表
链表中的一个很常见的操作是:链表的逆置,也叫链表的反转。 如:1->3->5->7->9 反转后是 9->7->5->3->1 红色的箭头是新的变换,明白了操作原理就很好写代码了。 使用了三个指针:pre(前驱) cur(当前) rear(后继),经过以上的四步变换,目地是,使cur指向的节点成功逆置(反转)指向pre所指向的节点。后面的节点的逆置,是同样的。struct ListNode原创 2017-07-15 11:09:26 · 523 阅读 · 0 评论 -
查找单链表的倒数第k个节点,要求只能遍历一次链表
为了得到倒数第k个结点,很自然的想法是先走到链表的尾端,再从尾端回溯k步。可是输入的是单向链表,只有从前往后的指针而没有从后往前的指针。因此我们需要打开我们的思路。既然不能从尾结点开始遍历这个链表,我们还是把思路回到头结点上来。假设整个链表有n个结点,那么倒数第k个结点是从头结点开始的第n-k-1个结点(从0开始计数)。如果我们能够得到链表中结点的个数n,那我们只要从头结点开始往后走n-k-1步就可原创 2017-07-15 11:17:06 · 1195 阅读 · 0 评论 -
实现一个Add函数,让两个数相加,但是不能使用+、-、*、/等四则运算符。ps:也不能用++、--等等
分析:这又是一道考察发散思维的很有意思的题目。当我们习以为常的东西被限制使用的时候,如何突破常规去思考,就是解决这个问题的关键所在。看到的这个题目,首先我们可以分析人们是如何做十进制的加法的,比如是如何得出5+17=22这个结果的。实际上,我们可以分成三步的:第一步只做各位相加不进位,此时相加的结果是12(个位数5和7相加不要进位是2,十位数0和1相加结果是1);第二步做进位,5+转载 2017-07-15 12:39:19 · 1190 阅读 · 0 评论 -
判断链表是否带环?若带环求环的长度?若带环求环的入口点?
1.判断链表是否带环用快慢指针求,快指针一次两步,慢指针一次走一步,如果带环的话那么快指针最终会与慢指针相遇,如果快指针fast或者fast->next走到NULL的话,则说明链表不带环。pair*, bool> IsExitsLoop(Node* head){ assert(head); Node* fast = head; Node* slow = head;原创 2017-07-15 13:11:20 · 322 阅读 · 0 评论 -
-设计一个类不能被继承 2.设计一个类只能在堆上创建对象。 3.设计一个类只能在栈上创建对象。
设计一个类不能被继承常规解法:将构造函数设为私有函数在C++中,子类的构造函数会自动调用父类的构造函数,子类的析构函数也会调用父类的析构函数。要想一个类不能被继承,只要把它的构造函数和析构函数都设置为私有函数。那么当一个类试图从那里继承时,势必会因为调用构造函数和析构函数而导致编译错误。可是这个类型的构造函数和析构函数都是私有函数,我们怎样才能得到该类型的实例呢?我们可以通过定义共有的原创 2017-07-15 13:49:51 · 594 阅读 · 0 评论 -
判断两个链表是否相交,若相交,求交点。(假设链表带环、不带环)
问题1: 给出两个链表的头指针,判断这两个链表是否相交。假设两个链表均不带环。 解法一: 如果两个链表都无环,则可以把第二个链表接在第一个链表后面,如果得到的链表有环,则说明这两个链表相交。这里如果有环,则第二个链表的表头一定在环上,只需要从第二个链表开始遍历,看是否会回到起点即可判断。假设两个链表长度分别为m和n,则时间复杂度为O(m+n)。 解法二: 先分别统计出两条链表中的结原创 2017-07-16 16:59:59 · 1101 阅读 · 0 评论 -
元素出栈、入栈顺序的合法性。
题目: 判断元素出栈、入栈顺序的合法性。如:入栈的序列(1,2,3,4,5),出栈序列为(4,5,3,2,1),则合法。入栈的序列(1,2,3,4,5),出栈序列为(4,5,2,3,1),则不合法。 我们可以定义一个辅助栈,来帮助我们做这样的题。我们把第一个序列中的数字一次压入栈中,压入的过程中按照第二个序列的顺序依次从栈中弹出数字。 使用vector来存放两个序列,原创 2017-07-20 09:52:16 · 373 阅读 · 0 评论 -
将二叉搜索树转化为一个排序的双向链表
题目: 输入一颗二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,职能调整树中结点指针的指向。如下图所示: 由于要求转换之后的链表是排好序的,我们可以中序遍历树中的每一个结点,这回死因为中序遍历算法的特点是按照从小到大的顺序遍历二叉树的每一个节点。当遍历到根结点时,我们可以把书=树看成三部分:值为10的结点,根结点值为6的左子树,根结点值为14的右子树。根据排序链表的原创 2017-07-29 16:28:26 · 449 阅读 · 0 评论 -
C++实现一个线程安全且高效单例类。(懒汉与饿汉)
在某些应用环境下面,一个类只允许有一个实例,这就是著名的单例模式。单例模式分为懒汉模式,跟饿汉模式两种。首先给出饿汉模式的实现template class singleton{protected: singleton(){};private: singleton(const singleton&){};//禁止拷贝 singleton& operat转载 2017-07-29 16:39:02 · 566 阅读 · 0 评论 -
给定一个整数N,那么N的阶乘N!末尾有多少个0呢?求N!的二进制表示中最低位1的位置。
题目1:给定一个整数N,那么N的阶乘N!末尾有多少个0呢?例如:N=10,N!=3 628 800,N!的末尾有两个0。初看这样的题目可能会想到直接求出N!的阶乘,然后再计算出0的个数。显然用这种方法如果N很大的情况下,非常容易溢出。所以我们可以换个角度来分析这个问题。N=1×2×3×4×5×6×··· ×N我们可以对N!进行分解质因数 即N!=2x ×3y ×5z ·····原创 2017-07-21 12:16:33 · 1012 阅读 · 0 评论 -
笔试/面试:删除一个无头单链表的非尾节点 ,从尾到头打印单链表
删除一个无头单链表的非尾结点struct ListNode{ int _value; ListNode*_next; ListNode(int value = 0, ListNode*pnext = NULL) :_value(value) , _next(pnext) {}};//节点的后一个节点赋值给要删除的节点,再删除这个后原创 2017-07-18 10:00:26 · 390 阅读 · 0 评论 -
复杂链表的复制
题目:请实现函数,复制一个复杂链表。在复杂链表中,每一个节点除了有一个m_pNext指针指向下一个节点外,还有一个m_pSibling只想链表中的任意节点或者NULL。节点定义如下:struct ComplexNode{ int m_nValue; ComplexNode* m_pNext; ComplexNode* m_pSibling;}; 方法: 第一步,根据原原创 2017-07-18 11:17:41 · 283 阅读 · 0 评论 -
位图的简易实现及相关面试题
概述 位图(bitmap)是一种非常常用的结构,在索引,数据压缩等方面有广泛应用。本文介绍了位图的实现方法及其应用场景。位图的简易实现。#pragma once#include<iostream>#include<vector>using namespace std;class BitMap{public: BitMap(int size) { _tabl原创 2017-08-06 10:57:40 · 514 阅读 · 0 评论