剑指offer第二章】的更多相关文章

剑指offer第二章 1.二维数组中的查找 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数 class Solution { public: bool Find(int target, vector<vector<int> > array) { /*二维数组的行数和列数*/ int rows = array.size(); ].size(); int row; in…
旋转数组的最小数字 题目:把一个数组最开始的若干元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如:数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转数组.此时的旋转数组是可以划分为两个排序的子数组.最小值为这两个子数组分界线. 思路:写一个函数minArrary(int*arrary int len),返回值为int.定义三个指针left=mid=0(如果数组是将前面的0个元素放到数组的后面,那么旋转数组即是原数组,最小值即为mi…
算法:排序和查找(二分查找,归并排序,快速排序),位运算等. 查找:顺序查找,哈希查找,二叉排序树查找,哈希表. 二分查找可以解决:"旋转数组中的最小数字","数字在排序数组出现的次数"等问题. 哈希表:优点:O(1)时间内查找一个元素的效率最高. 缺点:需要额外的空间来实现哈希表. 二叉排序树查找:对应二查搜索树查找,可以解决:"二叉收索树的后续遍历","二查搜索树和双向链表" 排序:排序算法要熟练,额外空间消耗,平均时间复…
一.题目大意 输入一颗二叉树,判断该二叉树是否为平衡二叉树(AVL树). 二.题解 <剑指offer>上给出了两种解决方式: 1.第一种是从根节点开始,从上往下遍历每个子节点并计算以子节点为根节点的子树的高度,通过判断左右子树的高度差是否大于1来判断是否为AVL树.其中计算子树的高度,利用了TreeDepth函数(具体可见<剑指offer(第二版)>P272).其中TreeDepth的思想如下: (1)计算一颗二叉树的高度,可以将该问题转化成求子树的高度+1.如果根节点只有左子树的…
一.题目大意 给你一个数n,要求返回第n个丑数.其中,丑数的定义如下: 丑数是指只包含因子2.3和5的数.(数字1也是丑数,不过是个特例)引用<剑指offer>上的话来说,对于一个数M,如果M能被2整除,就连续除以2:若果能被3整除,就连续除以3:如果能被5整除,就连续除以5.如果最终的结果是1的话,那么M就是丑数,否则M不是丑数.以下是判断一个数是否为丑数的代码: bool IsUglyNumber(int num) { while(num % 2 == 0) num /= 2; while…
具体的题目大意和参考思路在此处不详述(见<剑指offer>),实质就是在中序遍历的过程中调整指针的指向,关于中序遍历有递归和非递归两种操作,所以此处也用了两种方法. 方法1(递归法): 代码如下: class Solution { public: TreeNode* Convert(TreeNode* pRootOfTree) { if(pRootOfTree == nullptr) return nullptr; TreeNode * pre = nullptr;//中序遍历中当前节点的前一…
剑指Offer 按题号排序 面试题 3:数组中重复的数字 面试题 4:二维数组中的查找 面试题 5:替换空格 面试题 6:从头到尾打印链表 面试题 7:重建二叉树 面试题 8:二叉树的下一个节点 面试题 9:用两个栈实现队列 面试题 10:斐波那契数列 面试题 11:旋转数组中最小数字 面试题 12:矩阵中的路径 面试题 13:机器人的运动范围 面试题 14:剪绳子 面试题 15:二进制中1的个数 面试题 16:数值的整数次方 面试题 17:打印从1到最大的n位数 面试题 18:删除链表中的节点…
一.题目描述 把n个骰子仍在地上,所有的骰子朝上的一面的点数之和为s,输入n,打印出s所有可能的值出现的概率. 二.题解 <剑指offer>上给出的两种方法,尤其是代码,晦涩难懂且没有注释.而n个骰子的问题实质就是一个动态规划问题,所以文本主要从动态规划的角度来求解这个问题.首先该问题具备DP的两个特征:最优子结构性质和子问题的重叠性.具体的表现在:(1)n个骰子的点数依赖于n-1个骰子的点数,相当于在n-1个骰子点数的基础上再进行投掷.(2)求父问题的同时,需要多次利用子问题.由此定义状态转…
一.题目描述 求1+2+3+...+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字以及条件判断语句 (即三元运算符,A? B : C) 二.题解 虽然求和问题本身很容易,但加上这么多限制条件的话,整个问题似乎就不那么简单了.<剑指offer>虽然给出了四种解决方法,但这四种方法都是基于C++的语言特性求解的,并不是通用的解法.所以,本文旨在给出通用的解法.首先,根据以上的限制条件,可以考虑的角度只有两种(个人看法)一个是递归,另一个是位运算.从位运算…
一.题目大意 给定一个数组A,对于数组A中的两个数字,如果排在前面的一个数字大于(必须大于,等于不算)后面的数字,则这两个数字组成一个逆序对.要求输出数组A中的逆序对的总数.例如,对于数组{7,5,6,4},一共存在5个逆序对,分别是(7,5).(7,6).(7,4).(5,4).(6,4). 注:根据题意可知,必须根据原数组中元素的相对顺序来统计,给定的数组时怎样,那就按照怎样的顺序. 二.思路分析 方法1:暴力破解.双重循环来判断出所有的逆序对数,时间复杂度为O(N^2),空间复杂度为O(1…
题目:请实现一个函数,把字符串中的每个空格替换成“%20”.例如输入“We are happy”,则输出”We%20are%20happy”. 原因:在网络编程中,如果URL参数中含有特殊字符,如:空格.“#”等,可能导致服务器端无法获得正确的参数值.我们需要将这些特殊符号转换成服务器识别的字符.转换规则是在“%”后面跟上ASCII码的两位十六进制的表示.比如:空格的ASCII码是32,即十六进制的0x20,因此空格被替换成“%20”. 时间复杂度为O(n2)不足以拿到Offer 现在我们考虑怎…
面试题10:斐波那契数列 题目要求: 求斐波那契数列的第n项的值.f(0)=0, f(1)=1, f(n)=f(n-1)+f(n-2) n>1 思路:使用循环从下往上计算数列. 考点:考察对递归和循环的选择.使用递归的代码通常比循环简洁,但使用递归时要注意一下几点:1.函数调用的时间和空间消耗:2.递归中的重复计算:3.最严重的栈溢出.根据斐波那契数列递归形式定义很容易直接将代码写成递归,而这种方式有大量重复计算,效率很低. 解法比较: 解法3,4将问题数学化,借助数学工具的推导,从根本上减低时…
描述:使用两个栈实现一个队列.队列中实现尾部插入和头部删除函数. 思路:stack1负责插入,stack2负责弹出,如果stack2为空了,将stack1的元素依次弹出并存放到stack2中,之后对stack2进行弹出操作. 考点:对栈和队列的理解:对泛型的使用等. /** * Copyright(C) 2019 Hangzhou Differsoft Co., Ltd. All rights reserved. * */ package com.java.offer; import java.…
描述:给定一棵二叉树和其中的一个节点,找出中序遍历序列的下一个节点.树中应定义指向左节点.右节点.父节点的三个变量. 思路: 1.如果输入的当前节点有右孩子,则它的下一个节点即为该右孩子为根节点的子树的最左边的节点,比如2->5,1->3 2.如果输入的当前节点没有右孩子,就需要判断其与自身父节点的关系: 2.1如果当前节点没有父节点,那所求的下一个节点不存在,返回null. 2.2如果输入节点是他父节点的左孩子,那他的父节点就是所求的下一个节点,比如4->2 2.3如果输入节点是他父节…
描述:输入某二叉树的前序遍历和中序遍历结果,重建该二叉树.假设前序遍历或中序遍历的结果中无重复的数字. 思路:前序遍历的第一个元素为根节点的值,据此将中序遍历数组拆分为左子树+root+右子树,前序遍历数组拆分为root+左子树+右子树.再对左右子树进行同样的操作. 考点:对二叉树不同遍历方法的掌握. /** * Copyright(C) 2019 Hangzhou Differsoft Co., Ltd. All rights reserved. * */ package com.java.o…
思想:前序(根左右),中序(左根右),后序(左右根) 前序非递归遍历: 首先判断根是否为空,将根节点入栈 1.若栈为空,则退出循环 2.将栈顶元素弹出,访问弹出的节点 3.若弹出的节点的右孩子不为空则将右孩子入栈 4.若弹出的节点的左孩子不为空则将左孩子入栈 5.返回1 后序遍历非递归: 前序:根->左->右 后序:左->右->根 可以把后序当作:根->右->左,然后再反转一下即可 中序遍历非递归: 根据中序遍历的顺序,对于任一结点,优先访问其左孩子,而左孩子结点又可以…
描述:输入一个链表的头节点,从尾到头打印每个节点的值. 思路:从尾到头打印,即为“先进后出”,则可以使用栈来处理:考虑递归的本质也是一个栈结构,可递归输出. 考点:对链表.栈.递归的理解. package com.java.offer; import java.util.Stack; /** * @since 2019年2月14日 下午2:13:20 * @author xuchao * */ public class P6_PrintListInReversedOrder { public s…
面试题5:替换空格 题目要求: 实现一个函数,把字符串中的每个空格都替换成“%20”,已知原位置后面有足够的空余位置,要求改替换过程发生在原来的位置上. 思路: 首先遍历字符串求出串中空格的数量,求出替换之后字符串的总长度(每替换一个空格,长度加2).做法是从字符串的后面向前复制和替换.有2个指针p1.p2,p1指向原字符串的尾,p2指向替换之后的字符串的尾.接下来向前移动指针p1,逐个的将p1指向的字符复制到p2指向的位置,碰到空格时,p1向前移动一格,在p2之前插入字符串"%20"…
面试题3:数组中重复的数 题目要求: 在一个长度为n的数组中,所有数字的取值范围都在[0,n-1],但不知道有几个数字重复或重复几次,找出其中任意一个重复的数字. 解法比较: /** * Copyright(C) 2019 Hangzhou Differsoft Co., Ltd. All rights reserved. * */ package com.java.offer; /** * 一个长度为n的数组,值的范围在0~n-1内,有一个或多个数字重复,求其中任意一个 * * @since…
面试题2:实现单例模式 题目要求: 设计一个类,只能生成该类的一个实例. /** * 单例模式 * 定义:指实现了特殊模式的类,该类仅能被实例化一次,产生唯一的一个对象 * 应用举例:windows的任务管理器,回收站,web应用的配置对象,spring中的bean默认也是单例 * 分类:饿汉式,懒汉式,双检锁,静态内部类,枚举 * 评价指标有:单例(必须),线程安全,延迟加载,防止反序列化产生新对象,防止反射攻击 * 实现方法的选择:一般情况下直接使用饿汉式就好了,要求延迟加载时倾向于用静态内…
题目:输入某二叉树的前序遍历和中序遍历的结果,请重新构造出该二叉树.假设输入的前序遍历和中序遍历的结果中不包含重复的数字.例如输入的前序遍历序列为{1,2,4,7,3,5,6,8}和中序遍历为{4,7,2,1,5,3,6,8},则重建出二叉树并输出它的头结点. 前序遍历:根节点-->左节点-->右节点 中序遍历:左节点-->根节点-->右节点 后序遍历:左节点-->右节点-->根节点 在二叉树的前序遍历序列中,第一个数字总是树的根节点的值.但在中序遍历中,根节点的值在序…
18.二叉树的镜像 操作给定的二叉树,将其变换为源二叉树的镜像. /** public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } } */ public class Solution { public void Mirror(TreeNode root) { if(root != null){ Tre…
1.排序算法比较: 2.java实现 快排: /** * 快排 * * @since 2019年2月26日 下午1:37:34 * @author xuchao */ public class QuickSoft { public static void quickSoft(int[] data,int start,int end) { if(start>=end) { return; } int m = quickSoftPartition(data, start, end); quickSo…
面试题4:二维数组中的查找 题目要求: 一个二维数组中,每一行从左到右递增,每一列从上到下递增.输入一个整数,判断数组中是否含有该整数 /** * @since 2019年2月13日 下午5:08:50 * @author xuchao * 二维数组,从左到右递增,从上到下递增,输入一个整数,判断数组中是否含有 * * 思路: * 从最后一行第一列与目标值比较,若大于目标值,则行下标-1;若小于目标值,则列下标+1 * */ public class P4_FindInPartiallySort…
面试题1:赋值运算符函数题目要求:为自定义类添加赋值运算符函数,考察一些细节点的书写.…
题目描述: 输入一个链表,从尾到头打印链表每个节点的值.返回新链表. import java.util.Stack; //定义链表结构 class ListNode { int value; ListNode next; } public class PrintListReverse { public static void main(String[] args) { ListNode node1 = new ListNode(); ListNode node2 = new ListNode()…
题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1. 解题思路: 1.暴力解法,从头到尾遍历一次,我们就能找出最小的元素,复杂度为O(n),但是没有利用输入的旋转数组的特性,肯定达不到面试官的要求. 2.二分查找,这里的数组可以看成两个有序的子数组,二分查找对有序数组非常有效,复杂度为O(logn). 具体分析: 1.先分析数组的特点…
题目:写一个函数,输入n,求斐波那契数列的第n项.斐波那契数列的定义如下: 1.效率很低效的解法,挑剔的面试官不会喜欢 使用递归实现: public class Fibonacci { public long getNum(int n){ if(n<=0){ return 0; }else if(n==1){ return 1; }else{ return getNum(n-1)+getNum(n-2); } } } 我们不难发现在这颗树中有很多的节点是重复的,而且重复的节点数会随着n的增大而急…
题目:用两个队列实现栈. 分析:通过一系列的栈的压入和弹出操作来分析用队列模拟一个栈的过程,如图所示,我们先往栈内压入一个元素a.由于两个队列现在都是空,我们可以选择把a插入两个队列中的任一个.我们不妨把a插入queue1.接下来继续往栈内压入b,c两个元素.我们把它们都插入queue1.这个时候 queue1包含3个元素a,b,c其中a位于队列的头部,c位于队列的尾部. 现在我们考虑从栈内弹出一个元素.根据栈的后进先出的原则,最后被压入栈的c应该最先被弹出.由于c位于queue1的尾部,而我们…
题目:用两个栈实现一个队列.队列的声明如下,请实现它的两个函数appendTail和deletedHead,分别完成在队列尾部插入节点和在队列头部删除节点的功能. 分析: 我们通过一个具体的例子来分析该队列插入和删除元素的过程.首先插入一个元素a,不妨先把它插入到stack1,此时stack1 中的元素有{a},stack2为空.再压入两个元素b和c,还是插入到stack1中,此时stack1中的元素有{a,b,c},其中c位于栈顶,而stack2仍然为空. 这个时候,我们试着从队列中删除一个元…