剑指offer题目系列一

Posted 白杨树丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指offer题目系列一相关的知识,希望对你有一定的参考价值。

        本篇介绍《剑指offer》第二版中的四个题目:找出数组中重复的数字、二维数组中的查找、替换字符串中的空格、计算斐波那契数列第n项。

        这些题目并非严格按照书中的顺序展示的,而是按自己学习的顺序,每个题目包含了分析和代码,代码都是用Java语言编写的。

        1、找出数组中重复的数字

        题目:
        在一个长度为n的数组里,所有数字都在0~n-1的范围内。数组中某些数字是重复的,但不知道有几个数字重复,也不知道每个数字重复了几次,请找出数组中任意一个重复的数字。例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3。
        解答:
        这里提供两种方式。
        第一种方式:本题所有数字都在0~n-1的范围内,如果数组中没有重复的数字,那么数组排序之后数字i与其下标i的值是一一对应的,即0-0、1-1、2-2……由于有重复数字,则排序后有些位置可能有多个数字,有些位置可能没有数字。
        这种方式的思路就是将数字i放到其下标i处,如果存在两个下标对应的数字相等,则说明有重复,该数字就是一个重复的数字。
        代码:

      

        代码中尽管有两重循环,但每个数字最多只要交换两次就能找到它自己的位置,因此总的时间复杂度为O(n),同时空间复杂度为O(1),因此推荐此方法。
        第二种方式:用HashMap或ArrayList,都是先从第一个元素开始遍历数组,如果HashMap或ArrayList中不存在该元素,则将其放入,如果存在,则说明有重复。这种方式需要额外的空间,时间复杂度和空间复杂度都为O(n)。
        代码:

      

        这里仅仅以HashMap为例,ArrayList与其类似,不再赘述。

      2、二维数组中的查找

        题目:
        在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
        解答:
        这里提供4种类似的方式:可以先从二维数组右上角(第一行最后一列)的数字开始比较,如果它比要查找的数字小,则第一行所有数字都比它小,说明该数字不在第一行。然后比较第二行最后一列数字,如果比要查找的数字大,则说明在第二行,然后将第二行的数组按倒序的顺序逐个与其比较,直到找到为止。这种方式是从第一行往下逐行排除,找到目标数字所在的行以后,按倒序逐列排除。另外三种方式分别是从最后一行往上逐行排除,找到目标数字所在的行以后,按正序逐列排除;从最后一列往左逐列排除,找到目标数字所在的列以后,按正序逐行排除;从第一列往右逐列排除,找到目标数字所在的列以后,按倒序逐行排除。
        下面代码仅说明其中的两种按行排除的方式。
        代码:

     

     

      3、替换字符串中的空格

        题目:
        请实现一个函数,把字符串中的每个空格替换成“%20”。例如,输入“We are happy.”,则输出“We%20are%20happy.”。
        解答:
        这里提供2种方式。
        第一种方式:先统计出原字符串中空格个数,并计算出替换之后字符串的长度,然后新建一个数组,使其长度等于替换之后字符串的长度,用于存放替换之后字符串。
        如果从前往后遍历字符串,碰到空格就替换,那么后面的字符可能会多次移动,总的时间复杂度为O(n²),效率不高。因此这里从后往前遍历原字符串,如果是非空格字符,就直接复制到新数组中(注意新数组也是从后往前放入字符);如果是空格,则按0、2、%的顺序放入新数组……直到遍历完字符串为止,这样就能保证每个元素只会移动一次,时间复杂度为O(n)。
        代码:

      

        第二种方式:因为Java语言中String类型字符串是无法改变的,而StringBuilder和StringBuffer类型字符串是可以改变的,因此可以用这两个类型,通过append()方法拼接字符串。如果对线程安全有要求,则可以用StringBuffer,没要求可以用StringBuilder。以下以StringBuilder为例,StringBuffer与其类似。

     

       4、计算斐波那契数列第n项

        题目:
        求斐波那契数列的第n项。写一个函数,输入n,求斐波那契数列的第n项。
        斐波那契数列定义如下:第1项F(1)=1,第2项F(2)=1,从第3项开始,每一项都等于前两项之和。前几项数字为:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377……
        解答:
        这里提供两种方式:非递归方式和递归方式。
        第一种方式,非递归方式(优先选择)。定义三个变量,分别存放前两项和第三项(当前项)的值,逐个计算斐波那契数列的每一项,直到第n项停止并返回。只有一个循环,时间复杂度为O(n)。
        代码:

      

        第二种方式,递归方式。递归方式的代码很简洁,但仔细分析就会发现,递归方式计算的过程中会产生大量重复计算。比如想求f(10),得先计算出f(9)和f(8);同样想求出f(9),得先计算出f(8)和f(7);想求出f(8),得先计算出f(7)和f(6)……可以看到f(8)、f(7)等项都求了两次值。当n很大时,重复计算量会非常大,效率会很低,因此这种方式当n很小时还可以,很大时就不太适用了。所以优先推荐第一种方式。
        代码:

     

        转载请注明出处 http://www.cnblogs.com/Y-oung/p/8858960.html

        工作、学习、交流或有任何疑问,请联系邮箱:yy1340128046@163.com  微信:yy1340128046

 

以上是关于剑指offer题目系列一的主要内容,如果未能解决你的问题,请参考以下文章

剑指offer系列刷题第一篇——寻找单身狗

剑指offer系列43---判断平衡二叉树

剑指offer系列42---二叉树深度

剑指offer系列56---连续子数组的最大和

剑指offer系列29-----链表中环的入口节点-

剑指offer系列刷题第二篇——从尾到头打印链表和反转链表