- 博客(65)
- 问答 (1)
- 收藏
- 关注
原创 求数组中第K大的数
本题的的数组是可以包含重复元素的,且要求时间复杂度控制在O(n)解题思路:数组中第k大的数等价于排序数组中第n-k个数,直观的想法是将数组排序后取第n-k个数即可,但是最快的排序算法时间复杂度也是O(logn), 可以参考快速排序一次划分的思想,将时间复杂度降低为O(n);一次划分可以讲数组分为三部分,比支点元素小或者与支点元素相等的部分,支点元素,比支点元素的部分。一次partition之后
2017-09-11 15:17:20
3304
原创 剑指offer面试题28 字符串的全排列
有重复全排列解题思路:整体思路:可以把一个字符串看成两部分组成,第一部分为第一个字符,第二部分是后面的所有字符。这是典型的分治思想,可以用递归实现。具体来说:第一步首先求所有可能出现在第一个位置上的字符,即把第一个字符和后面的所有的字符(包括第一个字符)进行交换。因字符串中可能有重复的字符,因此在交换前,需要判断从当前字符串的开始位置start到待交换位置end之前,是否有字符和end指向
2017-09-07 11:20:07
520
原创 剑指offer面试题25 二叉树中和为某一值的路径
解题思路:首先需要理解路径的概念:路径总是从根节点到叶节点,由于路径是从根节点开始,所以可以考虑用先序遍历的方式。每遍历完一个节点进入节点的左子树时,需要将当前节点保存起来,作为路径中的一个节点,之所以需要保存路径上的节点,是因为需要计算路径的和,是否和待查找元素相同。因此考虑用栈来保存路径。注意:当从子节点返回父节点时,需要将当前元素出栈。用于更新路径。import java.util.
2017-09-06 15:12:31
388
原创 剑指offer面试题24 二叉搜索树的后序遍历序列
解题思路:1.判定一个序列是不是某二叉搜索树的后续遍历序列,可以结合二叉树的后续序列和二叉搜索树的特点来判断。二叉树的后续遍历序列,其最后一个数字是树的根节点的值,根节点的前面部分可以分为左子树的序列和右子树的序列。而这颗二叉树需要是一颗二叉搜索树,又必须满足左子树上的所有节点小于根节点的值,右子树上的所有节点大于根节点的值。接下来,针对左子树和右子树,分别需要满足上述条件,显然这是一个递归的
2017-09-06 10:20:37
294
原创 剑指offer面试题23 从上往下打印二叉树
解题思路:考察层次遍历二叉树,可以利用一个队列来实现。当一个节点从队列头部移除时,若其存在左子节点,则左子节点入队列;若存在右子节点,则右子节点入队列,如此循环下去,直到队列为空,结束循环。import java.util.ArrayList;import java.util.LinkedList;import java.util.Queue;class TreeNode {
2017-09-04 17:03:26
276
原创 剑指offer面试题22 栈的压入、弹出序列
解题思路:遍历出栈序列,看栈中是否存在当前元素,若不存在,则在入栈序列中一直入栈,直到当前元素入栈为止。若存在,且是栈顶元素,则直接出栈;若存在,但不是栈顶元素,则证明此时的出栈序列是错误的。import java.util.Stack;public class Solution { public static boolean IsPopOrder(int [] pushA,
2017-09-04 16:38:30
279
原创 剑指offer面试题21 包含min函数的栈
解题思路:常见的思路可能会有:(1)每入栈一个元素,对栈内元素进行排序,让最小的元素位于栈顶,但是这样不能保证栈的先进后出的特性,不符合题意 (2)设置一个成员变量始终代表最小的元素,每入栈一个元素,若比最小元素小,则更新。但当当前栈顶元素为最小的元素,其出栈后,栈中剩下元素的最小
2017-09-04 14:53:01
261
原创 剑指offer面试题20 顺时针打印矩阵
解题思路:1.首先画出几个矩阵进行分析,可以将顺时针打印矩阵的过程分为一次打印一个圈,打印圈又可以分为四个步骤:(1)从左到右打印一行;(2)从上到下打印一列 (3)从右到左打印一行,(4)从下到上打印一列2.通过画图,可以发现一个很重要的隐藏条件,也是顺时针打印圈的结束条件,即每个圈的起始坐标都是(start,start) 因此圈的起始条件必须满足 start * 2 3
2017-09-04 10:40:13
244
原创 剑指offer面试题19 二叉树的镜像
解题思路:(1)递归实现:利用中序遍历的思想,在遍历到每一个节点的同时,如果这个节点不为空或者这个节点不为叶子节点,将其看做根节点,交换其左右子树的指针的位置。直到递归返回到根节点为止,形成二叉树的镜像。(2)循环实现:可以借鉴层次遍历的思想,在某个节点出队列的时候,先交换这个节点的左右子树,在将交换后的左右子节点入队列,如此循环下去。有兴趣的可以自己实现下。class TreeNod
2017-09-02 11:46:23
259
原创 剑指offer面试题18 树的子结构
解题思路:整个过程大体可以分为两步:我们可以这样假设,两棵二叉树分别是T1和T2,二叉树中的每个节点都是根节点(1)如果T1中某棵子树的根节点与T2的根节点相同,则比较这棵子树与T2是否相同,如果相同,则查找成功,如果不同,需要进入步骤(2);(2)递归地在这颗子树的左子树中查找是否包含与T2相同的子树;若找到,则查找成功,若未找到,递归地在右子树中查找。class TreeNode { i
2017-09-02 10:42:17
223
原创 剑指offer面试题17 合并两个排序的链表
解题思路:1.非递归解法:类似于归并排序第二步合并的步骤,设置三个指针p1、p2、p3。p1指向第一个链表的头结点,p2指向第二个链表的头结点,p3指向第三个链表的头结点。首先确定第三个链表的表头指针list3Head。然后比较p1和p2所指向的值哪个小,就选择小的那个加入到第三个链表中,同时将指向较小元素的指针后移,p3也后移,重复上述操作,直到遍历完某一个链表为止。若另一个链表中此时还剩元
2017-09-01 12:47:08
303
原创 Java中HashMap的常用操作
前期准备:首先给hashMap里面put一些键值对,代码如下: HashMap hashMap = new HashMap<>(); hashMap.put(5, 2); hashMap.put(9, 2); hashMap.put(8, 1); hashMap.put(7, 3); hashMap.put(16, 1); hashM
2017-08-29 16:41:23
26926
原创 剑指offer面试题16 反转链表
解题思路:1.非递归:设置两个指针,一个指针p指向当前节点,一个指针after指向当前节点的下一个节点,从头结点开始遍历链表,交换指针的位置,在交换之前,需要保存下一次after节点的位置,因此需要一个临时变量来存储。最后将原来头部的指针的next设为null。2.递归:递归的终止条件是当到达原来元链表的尾部时,返回尾指针,也就是新链表的头结点,将head的后一个指针的next域置为hea
2017-08-22 15:57:36
303
原创 判断一个单项链表中是否有环
解题思路:设置两个指针,同时从链表的头结点出发,一个指针一次走一步,另一个指针一次走两步。如果走的快的能够追上走的慢的,证明链表中又环class ListNode { int val; ListNode next; public ListNode(int val) { this.val = val; }}public class Solution { /** *
2017-08-18 17:04:02
273
原创 求链表的中间节点
解题思路:1.常规思路:先从头到尾遍历一次链表,求出链表长度N,随后在遍历链表一次,找出链表中的中间结点。需要遍历链表2次。2.令面试官满意的解法:只需遍历链表一次,即设置两个指针p1和p2,开始两个指针都指向链表的头部,同时移动两个指针,一个每次移动一步,一个每次移动两步,循环的结束条件将链表个数是奇数还是偶数都包含进来,详细见代码。public class Solution {
2017-08-18 15:33:30
647
原创 剑指offer面试题15 链表中倒数第k个结点
解题思路:思路1:求链表中倒数第k个节点,也就是正数第n-k+1个结点(假设从1开始计数),此时最直观的做法就是从头开始遍历链表定位到这个第n-k+1个结点即可。但是这种做法需要遍历链表2次,第1次遍历需要求得链表中结点总数,第2次从表头开始找第n-k+1个结点。因此不是最佳解法。思路2:比较好的做法就是利用双指针,只需遍历链表1次。可以这样考虑,让两个指针p1和p2一开始都指向链表表头,
2017-08-18 14:21:04
276
原创 排序算法之堆排序
解题思路:要实现一个堆排序,需要三步操作:(1)堆调整heapify;(2)构建大顶堆build_max_heap;(3)利用前两部的操作一次次建堆,完成堆排序的操作。1.堆调整heapify:给定数组中某个节点i,需要将其子树调整为父节点大于子节点。可以很明显的看出一个数组和一棵完全二叉树一一对应,索引值为i的节点,左子节点的索引为2*i+1,右子节点的索引为2*i+2。接下来需要找出三
2017-08-18 09:27:21
179
原创 剑指offer面试题14 调整数组顺序使奇数位于偶数前面
解题思路:1.当遇到让将一个数组、字符串、字符数组划分成两部分的时候,可以考虑使用两个索引,i从数组的前面开始,j从数组的末尾开始,例如快排也是基于这种思想。针对本题,i从左边开始向右寻找到一个偶数,j从右边开始向左寻找到一个奇数,交换这两个索引对应的元素。继续重复上述操作,直到两个索引错开,则表明所有的奇数已经排在偶数的前面了。2.当题目要求奇数和奇数的相对位置不变,偶数和偶数的相对位置
2017-08-16 20:05:37
281
原创 剑指offer面试题13 在O(1)时间删除链表节点
解题思路:1.在链表中删除某个节点的常规思路是从链表的头结点开始,顺序遍历查找要删除的节点,找到待删除节点的前一个节点,进行删除操作,但是这种思路需要顺序查找,因此时间复杂度为O(n)。现在可以这样考虑,已知待删除节点toBeDeleted,那么可以很容易地在O(1)时间内找到待删除节点的下一个节点later,将later节点中的元素赋值给toBeDeleted节点中的元素,那么此时toBeD
2017-08-16 16:09:13
253
原创 排序算法之归并排序
归并排序的主要思路分为两个部分:1.分治,2.归并。算法的平均时间复杂度为O(nlogn),需要辅助空间O(n)。1.分治需要将数组分为两个部分,针对每个部分进行归并排序,待两个子数组都有序后(归并的条件),进行归并。2.归并的函数需要三个数组位置索引,数组的起始位置L,右子数组的开始位置M(作为左子数组和右子数组的分界线),数组的结束位置R。首先需要将原数组根据三个索引拆分成左子数组和右
2017-08-16 14:53:48
196
原创 剑指offer面试12 打印1到最大的n位数
解题思路:这题乍一看看上去还是比较容易,我们很自然的就想到先求出那个最大的n位数,然后在从1开始打印出来即可。这种解法存在一个致命的缺点,当n较大是,所需打印的数有很大部分超过了整形所能表示的范围。在java中,整形用4字节表示,所能表示的整数范围是-2147483648~2147483647。所能表示的数字也顶多是10位,因此当n较大时,我们需要转换思路。既然不能用整形来表示数字,那么可以想
2017-08-15 10:49:15
250
原创 剑指offer面试题11 数值的整数次方 java实现
解题思路:这道题看起来很简单,但还是有些地方还要仔细观察才能发现陷阱。1.当指数大于等于0的时候,底数可以取任意double类型的值,这里暂不考虑0的0次方是1还是0。2.当指数小于0时:(1)如果底数为0,则在取倒数的时候会出现分母为0的情况,这是计算机不允许的,这里让函数返回0.0,然而函数返回0.0可能还有另一种情况,即当指数>0,底数为0时,结果也为0.0。因此为了区分这种
2017-08-14 20:59:48
254
原创 剑指offer面试题10 二进制中1的个数 java实现
解题思路:常规的思路可能是将一个数n和1做按位与(&)运算,若结果为1,则证明n的二进制表示中末位为1,计此时符合题目条件,计数器加1,然后将n用n/2赋值,继续上述过程。但该方法有个问题,针对负数,由于负数在计算机中是以补码的形式存储,所以对于负数不能用这种方法。可以换个思路。保持n不变,设置一个flag,flag从1开始,令n与flag做按位与运算,若为1则计数器加1。然后另flag左移一
2017-08-14 19:21:39
375
原创 剑指offer附加题 将二十六进制数转换成十进制
解题思路:与二进制转换成十进制的做法差不多。假设一个二进制数1100,那么这个二进制代表的十进制可以这样计算:0*Math.pow(2,0) + 0*Math.pow(2,1) + 1*Math.pow(2,2) + 1*Math.pow(2,3) = 12。只需要注意二十六进制数A代表十进制的1,B代表十进制的2...,并将底数变为26即可。import java.util.Scanne
2017-08-14 15:58:24
1037
原创 青蛙跳台阶问题 java实现
解题思路:一只青蛙一次可以跳上1级台阶,也可以跳上两级。现在需要求跳上n级台阶总共有多少种跳法。把n级台阶的跳的次数看成是n的函数,即为f(n),当n>2时,第一次跳有两种跳法,若第一次跳1级,则该次跳法数目为后面剩下的n-1级台阶的跳法数目f(n-1)。若第一次跳2级,则该次跳法数目为后面剩下的n-2级台阶的跳法数目f(n-2)。所以f(n)=f(n-1) + f(n-2),即相当于斐波那契
2017-08-11 20:54:59
761
原创 剑指offer面试题9 斐波那契数列
解题思路:传统的利用递归求斐波那契数列的第n项,遇到挑剔的面试官,可能他们不会喜欢,因为这种方法中存在比较多的重复计算,当n较大时,会严重影响算法的效率,因此采用其他思路。更简单的方法是从下往上计算,首先根据f(0)和f(1)算出f(2),设计三个局部变量first和last和sum,每一次将first+last的值赋给sum,然后将last的值作为下次计算的first,sum的值作为下次计算的l
2017-08-11 19:36:49
268
原创 剑指offer面试题38 数字在排序数组中出现的次数
解题思路:如果用顺序查找,这道题的时间复杂度是O(n),肯定不符合面试官的要求。看到排序数组,并且在里面查找一个数出现的次数,很自然的可以想到利用二分查找,因此这道题是二分查找的一个应用。假设待查找元素为k,如果要是能找到第一个k出现的位置和最后一个k出现的位置,两者相减在加上1即为k出现的次数。具体来说,现在可以先对整个数组进行一次二分查找,记中间元素的索引为midIndex,对应的元素
2017-08-11 16:03:06
199
原创 剑指offe面试题8 旋转数组的最小数字 (java实现)
解题思路:针对旋转数组的特点,即旋转后,数组的前半部分是有序的,后半部分是有序的。1.先考虑一般情况:可以参考二分查找的思想,在数组中设置两个指针,一个指向数组的起始位置,一个指向数组的结束位置。随后依据这两个位置求出数组的中间位置mid。如果mid指向元素大于等于start指向元素,则证明mid肯定在数组的前半部分,而旋转数组的最小值在mid的后面,因此可以缩小查找范围,令start =
2017-08-10 16:33:34
398
原创 排序算法之快速排序
解题思路:快速排序的基本思想是:先对数组进行一次划分partition。划分的目的是在数组中选择一个数,作为支点pivot,数组中所有比pivot小的元素放置在数组的左边,数组中所有比pivot大的元素放置在数组的右边。这个分界索引是在索引的移动过程中所确定。具体来说,设置两个索引分别为start和end分别指向数组待排序范围的起始位置和结束位置,在支点的左边找到一个比支点元素大的,在支点的右
2017-08-09 13:09:36
380
原创 二分查找(折半查找)的思路与实现 java实现
解题思路:1.迭代方式:方法内包含四个参数,分别是已排好序的数组(二分查找的前提是数组已经有序),待查找的起始索引start,待查找的结束索引end,目标元素target。首先找到数组中的中间元素的索引,即mid = (start + end)/2;比较mid指向元素与target是否相等,若相等则查找成功;若target比mid指向元素小,则target在mid的左边,则下次查找的结束位置为
2017-08-09 11:17:54
841
原创 剑指offer面试题6 重建二叉树(java实现)
解题思路:已知二叉树的前序序列和中序序列,那么前序序列的第一个元素,就是根节点,此时在中序序列中遍历根节点对应的值,记下该值的索引,此时该索引左边元素属于左子树,可以确定左子树的长度以及左子树的前序、中序范围,索引的右边元素属于右子树,可以确定右子树的长度以及右子树的前序、中序范围。接下来可以用递归地方式不断地在左子树、右子树中进行上述操作。递归的终止条件是当前序和中序范围重叠,并且指向元素也相同
2017-08-08 12:51:33
504
原创 剑指offer面试题5 从尾到头打印链表(java实现)
解题思路:在不改变链表本身结构的情况下,正常情况下遍历链表肯定是从头结点开始,直到最后一个结点。而现在需要从尾到头输出这个链表,这样满足后访问的结点先打印,类似于栈的后进先出特点,因此考虑利用栈这种数据结构,在遍历的同时将结点入栈。遍历结束后,将栈顶元素出栈,保存到arraylist中,直到栈空。class ListNode { int val; ListNode next = null;
2017-08-04 21:43:25
296
原创 剑指offer面试题4 替换空格
解题思路:具体见代码注释/**这是一个双指针问题,依照传统的解法从前向后遇到空格就将之后的字符后移, * 会有字符做多次移动,时间效率比较低。而利用两个指针,一个指向新字符串的末尾,一个指向原字符串的末尾 * 两个同时前移,遇到空格进行插入,直到两个指针相遇为止,这种方法保证每个字符只被移动一次 * @author wuxinkai * */public class Solutio
2017-08-04 20:59:31
306
原创 剑指offer面试题3 二维数组的查找(java实现)
解题思路:首先选取数组中右上角的数字。如果该数字等于要查找的数字,查找过程结束;如果该数字大于要查找的数字,剔除这个数字所在的列;如果该数字小于要查找的数字,剔除这个数字所在的行。也就是说如果要查找的数字不在数组的右上角,则每一次都在数组的查找范围中剔除一行或者一列,这样每一步都可以缩小查找的范围,直到找到要查找的数字,或者查找范围为空。public class Solution { /*
2017-08-04 20:53:03
251
原创 剑指offer面试题64 数据流中的中位数(Java实现)
解题思路:具体见注释import java.util.Comparator;import java.util.PriorityQueue;public class Solution { //记录数据容器中元素个数 private int count = 0; //利用优先级队列实现小顶堆,PriorityQueue默认会对入队的元素进行排序,所以在队列顶端的总是最小的元素 p
2017-07-25 12:43:51
482
原创 剑指offer面试题63 二叉搜索树的第k个结点
class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; }}public class Solution { private int inde
2017-07-24 15:54:43
208
原创 剑指offer面试题63 序列化二叉树(java实现)
class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; }}public class Solution { private int index = -1; String Serializ
2017-07-24 12:42:37
238
原创 剑指offer面试题61 按之字形顺序打印二叉树(java实现)
解题思路:利用两个栈stack1和stack2,stack1暂存奇数层的节点,stack2暂存偶数层的节点。当stack1中节点即奇数层节点出栈时,存入一个当前层次的arraylist中,与此同时,判断该节点是否有左、右子节点,若有,则在stack2中先压入左子节点,后压入右子节点,这样做是为了满足之字形顺序这个条件。当stack1中所有节点都出栈时,将当前层的arraylist加入到一个存放
2017-07-23 20:33:31
392
原创 剑指offer面试题60 把二叉树打印成多行(Java实现)
import java.util.ArrayList;import java.util.LinkedList;import java.util.Queue;class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val
2017-07-21 16:56:42
302
原创 剑指offer面试题59 对称的二叉树(java实现)
解题思路:可以定义一种遍历算法,先访问根节点,再遍历右子树后遍历左子树,可以将这种遍历方法称为对称的前序遍历。现在可以通过比较二叉树的前序遍历序列和对称前序遍历序列来判断二叉树是否对称。如果两个序列是一样的,那么二叉树是对称的。class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; pu
2017-07-21 15:42:44
383
空空如也
怎样在MAC上读写NTFS格式的U盘
2015-11-25
TA创建的收藏夹 TA关注的收藏夹
TA关注的人