剑指offer详解python实现

面试题3:二维数组的查找

Q:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
A1:遍历整个二位数组(时间复杂度O(n2))
A2:首先选取数组中右上角的数字。如果该数字等于要查找的数字,查找过程结束;如果该数字大于要查找的数字,剔除这个数字所在的列;如果该数字小于要查找的数字,剔除这个数字所在的行。也就是说如果要查找的数字不在数组的右上角,则每一次都在数组的查找范围中剔除一行或者一列,这样每一步都可以缩小查找的范围,直到找到要查找的数字,或者查找范围为空。(左下角同理)(时间复杂度O(n))

class Solution:
    def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
        if matrix==[]:
            return False
        else:                       #左上角元素值最小,右下角最大
            i=0
            j=len(matrix[0])-1
            while i<=len(matrix)-1 and j>=0:
                if matrix[i][j]!=target:
                    if matrix[i][j]>target:
                        j-=1
                    else:
                        i+=1
                else:
                    return True
                    break
            else:
                return False

面试题4:替换空格

Q:请实现一个函数,把字符串中的每个空格替换成"%20"。例如输入“We arehappy.”,则输出“We%20are%20happy.”。
A1:先遍历一次字符串,这样就能统计出字符串中空格的总数,并可以由此计算出替换之后的字符串的总长度。
首先准备两个指针,P1 和 P2。P1 指向原始字符串的末尾,而 P2 指向替换之后的字符串的末尾。接着向前移动指针 P1,逐个把它指向的字符复制到 P2指向的位置,直到碰到第一个空格为止。碰到第一个空格之后,把P1向前移动1格,在P2之前插入字符串"%20"。由于"%20"的长度为3,同时也要把P2向前移动3格。接着向前复制,直到碰到第二个空格。和上一次一样,再把P1向前移动1格,并把P2向前移动3格插入"%20"。此时P1和P2指向同一位置,表明所有空格都已经替换完毕。

class Solution:
    def replaceSpace(self, s: str) -> str:
        if s==None or len(s)<=0:
            return ''

        sumSpace=0
        for i in s:
            if i==' ':
                sumSpace+=1
        
        newLen=len(s)+2*sumSpace
        newStr=newLen*[None]
        indexOfOriginal,indexOfNew=len(s)-1,newLen-1

        while indexOfNew>=0 and indexOfNew>=indexOfOriginal:
            if s[indexOfOriginal] == ' ':
                newStr[indexOfNew - 2: indexOfNew + 1] = ['%', '2', '0']
                indexOfNew -= 3
                indexOfOriginal -= 1
            else: 
                newStr[indexOfNew] = s[indexOfOriginal]
                indexOfNew -= 1
                indexOfOriginal -= 1

        return "".join(newStr)
            
        

A2:直接使用python内置函数replace
语法:
str.replace(old, new[, max])
参数
•old – 将被替换的子字符串。
•new – 新字符串,用于替换old子字符串。
•max – 可选字符串, 替换不超过 max 次。

class Solution:
    def replaceSpace(self, s: str) -> str:
        return s.replace(" ","%20")

面试题5:从尾到头打印链表

Q:输入一个链表的头结点,从尾到头反过来打印出每个结点的值。
A:先将链表的结点元素储存进列表,再将列表倒序

class Solution:
    def reversePrint(self, head: ListNode) -> List[int]:
        res=[]
        while head:
            res.append(head.val)
            head=head.next
        return res[::-1]

面试题6:重建二叉树

Q:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
A:前序遍历列表:第一个元素永远是 【根节点 (root)】
中序遍历列表:根节点 (root)【左边】的所有元素都在根节点的【左分支】,【右边】的所有元素都在根节点的【右分支】
通过【前序遍历列表】确定【根节点 (root)】
将【中序遍历列表】的节点分割成【左分支节点】和【右分支节点】
递归寻找【左分支节点】中的【根节点 (left child)】和 【右分支节点】中的【根节点 (right child)】

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        if not preorder:
            return None
        loc=inorder.index(preorder[0])
        root=TreeNode(preorder[0])
        root.left=self.buildTree(preorder[1:loc+1],inorder[:loc])
        root.right=self.buildTree(preorder[loc+1:],inorder[loc+1:])
        return root

面试题7:用两个栈实现队列

Q:用两个栈实现一个队列。队列的声明如下,请实现它的两个函数appendTail和deleteHead,分别完成在队列尾部插入结点和在队列头部删除结点的功能。
A:操作两个“先进后出”的栈实现一个“先进先出”的队列。当 stackout 中不为空时,在stackout中的栈顶元素是最先进入队列的元素,可以弹出。如果stackout为空时,我们把stackin中的元素逐个弹出并压入stackout。由于先进入队列的元素被压到stackin的底端,经过弹出和压入之后就处于stackout的顶端了,又可以直接弹出。

class CQueue:

    def __init__(self):
        self.stackin=[]
        self.stackout=[]

    def appendTail(self, value: int) -> None:
        self.stackin.append(value)

    def deleteHead(self) -> int:
        if self.stackout:
            return self.stackout.pop()
        elif not self.stackin:
            return -1
        else:
            while self.stackin:
                self.stackout.append(self.stackin.pop())
            return self.stackout.pop()

面试题8:旋转数组的最小数字

Q:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
A:旋转之后的数组实际上可以划分为两个排序的子数组,而且前面的子数组的元素都大于或者等于后面子数组的元素。最小的元素刚好是这两个子数组的分界线。在排序的数组中可以用二分查找法实现O(logn)的查找。
若中点比末尾元素大,则最小数字出现在后半部分;若中点比末尾元素小,则出现在前半部分。

class Solution:
    def minArray(self, numbers: List[int]) -> int:
        if len(numbers)==1:
            return numbers[0]
        mid=(len(numbers)-1)//2
        if numbers[mid]>numbers[-1]:
            return self.minArray(numbers[mid+1:])
        elif numbers[mid]<numbers[-1]:
            return self.minArray(numbers[:mid+1])
        else:
            if len(numbers)>1:
                numbers.pop(mid)
            return self.minArray(numbers)

面试题9:斐波那契数列

Q1:写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项。
A:用递归方法计算的时间复杂度是以 n 的指数的方式递增的。改进的方法并不复杂。递归代码之所以慢是因为重复的计算太多,只要想办法避免重复计算就行了。比如可以把已经得到的数列中间项保存起来,如果下次需要计算的时候先查找一下,如果前面已经计算过就不用再重复计算了。

class Solution:
    def Fibonacci(self, n):
        # write code here
        num1 = 0
        num2 = 1
        target = 0
        for i in range(1, n+1):
            num1 = num2
            num2 = target
            target = num1 + num2
        return target

Q2:一只青蛙一次可以跳上1 级台阶,也可以跳上2 级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
A:跳第n阶有两种情况,由倒数第二阶直接跳到第n阶,倒数第一阶直接跳到第n阶。

class Solution:
    def numWays(self, n: int) -> int:
        if n==0 :
            return 1
        elif n<=2:
            return n
        else:
            a=1
            b=2
            res=0      #a保存f(n-2),b保存f(n-1),res保存f(n-1)+f(n-2)
            for i in range(3,n+1):
                res=a+b
                a=b
                b=res
            return res

面试题10:二进制中1的个数

Q:请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如把9表示成二进制是1001,有2位是1。因此如果输入9,该函数输出2。
A1:如果一个整数不等于0,那么该整数的二进制表示中至少有一位是1。先假设这个数的最右边一位是1,那么减去1时,最后一位变成0而其他所有位都保持不变。也就是最后一位相当于做了取反操作,由1变成了0。接下来假设最后一位不是1 而是0 的情况。如果该整数的二进制表示中最右边1位于第m位,那么减去1时,第m位由1变成0,而第m位之后的所有0都变成1,整数中第m位之前的所有位都保持不变。举个例子:一个二进制数 1100,它的第二位是从最右边数起的一个 1。减去 1 后,第二位变成0,它后面的两位0变成1,而前面的1保持不变,因此得到的结果是1011。在前面两种情况中,我们发现把一个整数减去1,都是把最右边的1变成0。如果它的右边还有0的话,所有的0都变成1,而它左边所有位都保持不变。接下来我们把一个整数和它减去 1 的结果做位与运算,相当于把它最右边的1变成0。还是以前面的1100为例,它减去1的结果是1011。我们再把1100和1011做位与运算,得到的结果是1000。我们把1100最右边的1变成了0,结果刚好就是1000。
把一个整数减去1(都是把最右边的1变成0),再和原整数做与运算,会把该整数最右边一个1变成0。那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作。

class Solution:
    def hammingWeight(self, n: int) -> int:
        count=0
        if n < 0:
            n = n & 0xffffffff
        while n!= 0:
            count += 1
            n = (n-1)& n
        return count

A2:python内置函数可以直接计算1的个数。

class Solution:
    def hammingWeight(self, n: int) -> int:
        return bin(n).count('1')

面试题11:数值的整数次方

Q:实现函数 double Power(double base, int exponent),求 base 的exponent次方。不得使用库函数,同时不需要考虑大数问题。
A:快速幂的思想。
向下整除 n // 2 等价于 右移一位 n >> 1 ;
取余数 n % 2 等价于 判断二进制最右一位值 n&1 。

class Solution:
    def myPow(self, x: float, n: int) -> float:
        if x == 0:
            return 0
        res = 1
        if n < 0:
            x, n = 1 / x, -n
        while n:
            if n & 1: 
                res *= x
            x *= x
            n >>= 1
        return res

面试题12:打印1到最大的n位数

Q:输入数字n,按顺序打印出从1最大的n位十进制数。比如输入3,则打印出1、2、3一直到最大的3位数即999。
A1:先求出最大的n位数,然后循环打印输出。

class Solution:
    def printNumbers(self, n: int) -> List[int]:
        ret=[]
        m=pow(10,n)-1
        for i in range(1,m+1):
            ret.append

你可能感兴趣的:(python学习笔记,剑指offer实现,leetcode,python)