1 二维数组中的查找

1.1 题目描述

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

1.2 解题思路

按行开始遍历,假设target大于第一行的最后一个数,那么我们就在第二行查找;如果target小于一行的最后一个数,那么我们检查下倒数第二列是否等于target。

1.3 解题代码

# -*- coding:utf-8 -*-
class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        rows,cols=len(array),len(array[0])-1
        row=0
        while row<rows and cols>=0:
            if array[row][cols]==target:
                return True
            elif array[row][cols]>target:
                cols=cols-1
            else:
                row=row+1
        return False

2 替换空格

2.1 题目描述

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

2.2 解题思路

  • replace
  • 遍历字符串,然后遇到空格就替换成“%20”

2.3 解题代码

  • 思路1
# -*- coding:utf-8 -*-
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        return s.replace(" ","%20")
  • 思路2
# -*- coding:utf-8 -*-
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        news=""
        for c in s:
            if c==' ':
                news+="%20"
            else:
                news+=c
        return news

3 从尾到头打印链表

3.1 题目描述

输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。

3.2 解题思路

遍历列表,每次遍历一个节点,然后将当前节点的值添加到列表,然后更新节点为下一个节点,最后将列表反转。

3.3 解题代码

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        # write code here
        data=[]
        while listNode:
            data.append(listNode.val)
            listNode=listNode.next
        return data[::-1]

4 重建二叉树

4.1 题目描述

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

4.2 解题思路

首先我们先回顾下前中后三种遍历顺序:

  • 前序遍历:根结点 ---> 左子树 ---> 右子树
  • 中序遍历:左子树---> 根结点 ---> 右子树
  • 后序遍历:左子树 ---> 右子树 ---> 根结点

然后发现前序的第一个节点肯定为根节点,在中序遍历中,在根节点左边的为左子树的中序遍历,在根节点右边的为右子树的中序遍历;那么在左子树的节点中,我们可以在前序遍历中找到左子树的根节点,右子树同理。

4.3 解题代码

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回构造的TreeNode根节点
    def reConstructBinaryTree(self, pre, tin):
        # write code here
        if not pre or not tin:
            return None
        root=TreeNode(pre[0])
        val=tin.index(pre[0])
        root.left=self.reConstructBinaryTree(pre[1:val+1],tin[:val])
        root.right=self.reConstructBinaryTree(pre[val+1:],tin[val+1:])
        return root

5 用两个栈实现队列

5.1 题目描述

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

5.2 解题思路

我感觉这个题的主要考查的是:栈的出入站栈顺序是先进后出,队列的出入队列顺序是先进新出,那么元素压入一个栈(负责入栈),然后再弹入到另一个栈(负责出栈),那么就可以实现队列了。

5.3 解题代码

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stackA=[]
        self.stackB=[]
    def push(self, node):
        # write code here
        self.stackA.append(node)
    def pop(self):
        # return xx
        if self.stackB:
            return self.stackB.pop()
        if not self.stackA:
            return None
        else:
            while self.stackA:
                self.stackB.append(self.stackA.pop())
            return self.stackB.pop()

6 旋转数组的最小数字

6.1 题目描述

6.2 解题思路

我们注意到旋转之后的数组实际上可以划分为两个排序的子数组,而且前面的子数组的元素都是大于或者等于后面子数组的元素。我们还注意到最小的元素刚好是这两个子数组的分界线。在排序的数组中我们可以利用二分查找来实现O(logn)的查找。本题给出的数组在一定程度上是排序的,因此我们可以试着用二分查找的思路来寻找这个最小的元素。

以前面的例子为例,我们先把第一个指针指向第0个元素,把第二个指针指向第4个元素,如图所示。位于两个指针中间(在数组的下标是2)的数字是5,它大于第一个指针指向的数字。因此中间数字5一定位于第一个递增字数组中,并且最小的数字一定位于它的后面。因此我们可以移动第一个指针让它指向数组的中间。

此时位于这两个指针中间的数字为1,它小于第二个指针指向的数字。因此这个中间数字为1一定位于第二个递增子数组中,并且最小的数字一定位于它的前面或者它自己就是最小的数字。因此我们可以移动第二个指针指向两个指针中间的元素即下标为3的元素。

此时两个指针的距离为1,表明第一个指针已经指向了第一个递增子数组的末尾,而第二个指针指向第二个递增子数组的开头。第二个子数组的第一个数字就是最小的数字,因此第二个指针指向的数字就是我们查找的结果。

上述方法是否就一定够完美了呢?面试官会告诉你其实不然。他将提示我们再仔细分析小标leftIndex和rightIndex分别和途中P1和P2相对应)的两个数相同的情况。在前面,当着两个数相同,并且它们中间的数相同的也相同时,我们把IndexMid赋给了leftIndex,也就是认为此时最小的数字位于中间数字的后面。是不是一定一样?

我们再来看一个例子。数组{1,0,1,1,1}和数组{1,1,1,0,1}都可以堪称递增排序数组{0,1,1,1,1}的旋转,图2分别画出它们由最小数字分隔开的两个子数组。

这两种情况中,第一个指针和第二个指针指向的数字都是1,并且两个指针中间的数字也是1,这3个数字相同。在第一种情况中,中间数字(下标为2)位于后面是子数组;在第二种情况中,中间数字(下标为2)位于前面的子数组中。因此,当两个指针指向的数字及它们中间的数字三者相同的时候,我们无法判断中间的数字是位于前面的子数组中还是后面的子数组中国,也无法移动两个指针来缩小查找的范围。此时,我们不得不采用顺序查找的方法。

原文:javascript:void(0)

6.3 解题代码

# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        if not rotateArray:
            return 0

        front, rear = 0, len(rotateArray) - 1
        midIndex = 0
        while rotateArray[front] >= rotateArray[rear]:
            if rear - front == 1:
                midIndex = rear
                break
            midIndex = (front + rear) // 2
            if rotateArray[front] == rotateArray[midIndex] and rotateArray[front] == rotateArray[rear]:
                return self.minOrder(rotateArray, front, rear)

            if rotateArray[front] <= rotateArray[midIndex]:
                front = midIndex
            elif rotateArray[rear] >= rotateArray[midIndex]:
                rear = midIndex
        return rotateArray[midIndex]

    def minOrder(self, array, front, end):
        result = array[0]
        for i in array[front:end + 1]:
            if i < result:
                result = i
        return result

7 斐波那契数列

7.1 题目描述

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。
n<=39

7.2 解题思路

在数学上,费波那契数列是以递归的方法来定义:

理解原理后,我们直接遍历即可

7.3 解题代码

# -*- coding:utf-8 -*-
class Solution:
    def Fibonacci(self, n):
        # write code here
        res=[0,1]
        while len(res)<=n:
            res.append(res[-1]+res[-2])
        return res[n]

8 跳台阶

8.1 题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

8.2 解题思路

利用动态规划,dp[n]为我们存放结果的列表。
假设n=1,那么只有一种跳法,dp[1]=1
假设n=2,可以跳2级或者跳两个1级,dp[2]=2
假设n=3,可以跳三个1级,一个2级一个1级或者一个1级一个2级,dp[3]=3
....
那么假设n=9,我们可以发现只要我们我们知道n=7和n=8时,就可以确定到第九级的跳法。因为我们可以从第7级直接跳到第9级,或者从第8级直接跳到第9级。
所以状态转移公式如下:
dp[n]=dp[n-1]+dp[n-2]

8.3 解题代码

# -*- coding:utf-8 -*-
class Solution:
    def jumpFloor(self, number):
        # write code here
        dp=[1,2]
        while len(dp)<=number:
            dp.append(dp[-1]+dp[-2])
        return dp[number-1]

9 变态跳台阶

9.1 题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

9.2 解题思路

分析:用Fib(n)表示青蛙跳上n阶台阶的跳法数,青蛙一次性跳上n阶台阶的跳法数1(n阶跳),设定Fib(0) = 1;
当n = 1 时, 只有一种跳法,即1阶跳:Fib(1) = 1;
当n = 2 时, 有两种跳的方式,一阶跳和二阶跳:Fib(2) = Fib(1) + Fib(0) = 2;
当n = 3 时,有三种跳的方式,第一次跳出一阶后,后面还有Fib(3-1)中跳法; 第一次跳出二阶后,后面还有Fib(3-2)中跳法;第一次跳出三阶后,后面还有Fib(3-3)中跳法
Fib(3) = Fib(2) + Fib(1)+Fib(0)=4;
当n = n 时,共有n种跳的方式,第一次跳出一阶后,后面还有Fib(n-1)中跳法; 第一次跳出二阶后,后面还有Fib(n-2)中跳法..........................第一次跳出n阶后,后面还有 Fib(n-n)中跳法.
Fib(n) = Fib(n-1)+Fib(n-2)+Fib(n-3)+..........+Fib(n-n)=Fib(0)+Fib(1)+Fib(2)+.......+Fib(n-1)
又因为Fib(n-1)=Fib(0)+Fib(1)+Fib(2)+.......+Fib(n-2)
两式相减得:Fib(n)-Fib(n-1)=Fib(n-1) =====》 Fib(n) = 2*Fib(n-1) n >= 2
递归等式如下:

原文:javascript:void(0)

9.3 解题代码

# -*- coding:utf-8 -*-
class Solution:
    def jumpFloorII(self, number):
        # write code here
        dp=[1,1]
        if number>1:
            while len(dp)<=number:
                dp.append(dp[-1]*2)
        return dp[number]

10 矩形覆盖

10.1 题目描述

我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

10.2 解题思路

n=1 - 只有横放一个矩形一种解决办法
n=2 - 有横放一个矩形,竖放两个矩形两种解决办法
n=3 - n=2的基础上加1个横向,n=1的基础上加2个竖向
n=4 - n=3的基础上加1个横向,n=2的基础上加2个竖向
...
n=n - n = f(n-1) + f(n-2)

10.3 解题代码

# -*- coding:utf-8 -*-
class Solution:
    def rectCover(self, number):
        # write code here
        # if number==0:
            # return 0
        # elif number==1:
            # return 1
        # elif number==2:
            # return 2
        # return self.rectCover(number-1)+self.rectCover(number-2)
        dp=[0,1,2]
        if number>2:
            while len(dp)<=number:
                dp.append(dp[-1]+dp[-2])
        return dp[number]