python代码题(算法与数据结构:前缀和、滑动窗口;二分查找;字符串;遍历;二叉树;栈和队列;斐波那契数列))

41.题目描述

找出所有和为S的连续正数序列

输出描述:

输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序。

思路:

知识点:数学,前缀和,滑动窗口。
先指定高低两个指针分别等于1和2,若总和<S,则高指针+1;若总和>S,则低指针+1。

滑动窗口方法
时间复杂度:O(N)
空间复杂度:O(1)
class Solution:
    def FindContinuousSequence(self, tsum):
        lowIndex = 1
        highIndex = 2

        res = []
        while highIndex > lowIndex:
            sum = int((highIndex + lowIndex) * (highIndex - lowIndex + 1) / 2)  # 求和公式
            if sum == tsum:
                curSqr = range(lowIndex, highIndex+1)
                res.append(curSqr)
                lowIndex += 1

            elif sum < tsum:
                highIndex += 1
            else:
                lowIndex += 1
        return res


s = Solution()
t = s.FindContinuousSequence(60) # tsum=60
print (t)
枚举法
时间复杂度:O(N^3)
空间复杂度:O(1)
class Solution:
    def FindContinuousSequence(self, tsum):
        if tsum<3:   
            return []      # tsum小于3的直接不用考虑
        result = []
        for i in range(1,(tsum+1)/2): # 穷举的话遍历到1/2即可
            tem = []
            count = 0
            while count <tsum:
                tem.append(i)
                count+=i
                i+=1
            if count ==tsum:
                result.append(tem)
        # 使用内置函数进行排序
        result.sort()
        return result

1.题目描述:

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

思路:

考察点:数组,二分查找
简要说明:这是一道对二维数组进行二分查找的算法,考察对二分查找的灵活运用。把二分值定在右上角或者左下角,就可以进行二分。
从左下角元素往上查找,右边元素是比这个元素大,上边是的元素比这个元素小。于是,target比这个元素小就往上找,比这个元素大就往右找。如果出了边界,则说明二维数组中不存在target元素。

二分法
复杂度分析
时间复杂度:O(m+n) ,其中m为行数,n为列数,最坏情况下,需要遍历m+n次。
空间复杂度:O(1)
class Solution:
    def Find(self, target, array):
        rows = len(array) - 1
        cols= len(array[0]) - 1
        i = rows
        j = 0
        while j<=cols and i>=0:
            if target<array[i][j]:
                i -= 1
            elif target>array[i][j]:
                j += 1
            else:
                return True
        return False
array = [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 10, 7]]
target =10
solution = Solution()
print (solution.Find(target, array))

2.题目描述

请实现一个函数,将一个字符串中的每个空格替换成“%20”
考察点:字符串

join()函数:
复杂度分析
时间复杂度:O(length) 只遍历了一遍字符串
空间复杂度:O(1) 没有开辟空间
class Solution:
    def replaceSpace(self, s):
        return "%20".join(list(s.split(" ")))  # 返回值:返回一个以分隔符sep连接各个元素后生成的字符串
s = 'We Are Happy.'
solution =Solution()
print (solution.replaceSpace(s))
直接替换,replace()函数
def replaceSpace(self, s):
    return s.replace(" ","%20")
正则表达式
import re
class Solution:
    def replaceSpace(self, s):
        s=re.sub(r" ","%20",s)   # 三个必选参数, 用20%替换空格,s为将要被更改的语句
        return s

3.题目描述

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

思路:

这是一道对单链表遍历的入门算法题。
考察点:单链表,递归,反转链表

方法一:遍历并使用insert()函数
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None


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


solution = Solution()
node1 = ListNode(1)
node2 = ListNode(2)
node3 = ListNode(3)
node4 = ListNode(4)
node1.next = node2
node2.next = node3
node3.next = node4

print (solution.printListFromTailToHead(node1))
方法二  使用栈
class ListNode:
     def __init__(self, x):  # 初始化实例的值,self为实例
         self.val = x
         self.next = None
class Solution:
    def printListFromTailToHead(self, listNode):
        if not listNode:
            return []
        temp = []
        result = []
        while listNode: 
            temp.append(listNode.val) # 进栈
            listNode = listNode.next   # 将listNode后移一个节点
        while temp:
            result.append(temp.pop()) # 出栈
        return result
方法三 使用从头到尾遍历,逆序输出
class ListNode:
     def __init__(self, x):  # 初始化实例的值,self为实例
            self.val = x
            self.next = None
class Solution:
        def printListFromTailToHead(self, listNode):
            result = []
            while listNode:
                result.append(listNode.val)
                listNode = listNode.next
            return result[::-1]           
solution = Solution()
node1 = ListNode(1)
node2 = ListNode(2)
node3 = ListNode(3)
node4 = ListNode(4)
node1.next = node2
node2.next = node3
node3.next = node4

print (solution.printListFromTailToHead(node1))

4.题目描述

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
这道题综合考察了对二叉树的前序,中序遍历算法的理解,和根据数组建立二叉树的代码考察以及对递归代码的理解与运用。
考察知识:树,递归。
二叉树的前序遍历:根左右
二叉树的中序遍历:左根右
二叉树的的后序遍历:左右根

思路

首先从前序遍历中拿出第一个,其一定是根节点对应的值,然后以其为分界点将中序遍历分为left和right两部分对应其左子树和右子树,然后将left和right当做新的中序遍历的结果,从前序遍历中拿出前len(left)个当做新的左子树的前序遍历结果,拿出后len(right)当做新的右子树的前序遍历结果,递归求解其left和right对应的二叉树,这样最终即可恢复整棵树。

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:
   def reConstructBinaryTree(self, pre, tin):
        root = []
        if len(pre)==0:
            return None    # 递归终止条件
        elif len(pre)==1:
            return TreeNode(pre[0])    # 递归终止条件
        else: 
            root=TreeNode(pre[0])
            tinL=tin[:tin.index(pre[0])]  # 左子树的中序
            tinR=tin[tin.index(pre[0])+1:]  # 右子树的中序
            root.left=self.reConstructBinaryTree(pre[1:tin.index(pre[0])+1],tinL)  # 左子树的前序,中序
            root.right=self.reConstructBinaryTree(pre[tin.index(pre[0])+1:],tinR)  # 右子树的前序,中序
        return root
solution = Solution()

pre = [1, 2, 4, 3, 5, 6]  # 前序
tin = [4, 2, 1, 5, 3, 6]  # 中序

headNode = solution.reConstructBinaryTree(pre, tin)
print (headNode)

5.题目描述

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
这是一道对栈和队列之间灵活转化的题目。
考察知识:队列,栈

解题思路

首先明确栈和数值的特点:
栈:先入后出
人数:先入先出
所以这道题本质上就是使用两个先入后出实现一个先入先出,就是简单的负负得正的道理。

class Solution:
    def __init__(self):
        self.stack1 = []  
        self.stack2 = []

    def push(self, node):
        self.stack1.append(node)

    def pop(self):
        self.stack2 = []

        while len(self.stack1) != 1:
            self.stack2.append(self.stack1.pop())  # self.stack2 = [4,3,2]

        node = self.stack1.pop()   # node = [1]

        while self.stack2:
            self.stack1.append(self.stack2.pop()) #self.stack1 = [2,3,4]

        return node


solution = Solution()
solution.push(1)
solution.push(2)
solution.push(3)
solution.push(4)

print (solution.pop())  # node = [1]
print (solution.pop())  # 第二次调用函数,node = [2]
print (solution.pop())
print (solution.pop())

6.题目描述

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组[3,4,5,1,2]为[1,2,3,4,5]的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

描述

这是一道对二分查找算法灵活运用的一道题目。
二分查找算法不限于运用在有序数组上。如果能够明确二分之后,答案存在于二分的某一侧,就可以使用二分。本题就是如此。
考察知识:数组,二分查找

思路

保证rotateArray[left]为全场最小,当rotateArray[left]<rotateArray[right]时,证明进入了有序数组,直接输出

class Solution:
    def minNumberInRotateArray(self, rotateArray):
        if len(rotateArray)==0:
            return 0
        left=0
        right=len(rotateArray)-1
        while left<right:
            if rotateArray[left]<rotateArray[right]:
                return rotateArray[left]   # 进入了有序数组,直接输出
            mid=left+(right-left)//2  # 向下取整
            #左边有序取另一半
            if rotateArray[left]<rotateArray[mid]:
                left=mid+1
            #右边有序右边取最小
            elif rotateArray[mid]<rotateArray[right]:
                right=mid
            #前面两个相等的时候,left进一继续
            else :
                left+=1
        return rotateArray[left]
solution = Solution()
print (solution.minNumberInRotateArray([4,5,6,7,1,2,3,4]))

7.题目描述

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)。n<=39。
考察知识:递归,记忆化搜索,动态规划和动态规划的空间优化。

题目分析

斐波那契数列公式为:f[n] = f[n-1] + f[n-2], 初始值f[0]=0, f[1]=1,目标求f[n]。

方法一 递归函数方式
时间复杂度:O(2^n)
空间复杂度:递归栈的空间
class Solution:
    def Fibonacci(self, n):
        if n == 0:
            return 0
        elif n == 1 or n == 2:
            return 1
        else:
            return self.Fibonacci(n-1)+self.Fibonacci(n-2)
n=20
solution = Solution()
print (solution.Fibonacci(n))
方法二 采用三个变量,动态规划。不用递归的过程,直接从子树求得答案。过程是从下往上。
时间复杂度:O(n), 没有重复的计算
空间复杂度:O(n)
class Solution:
    def Fibonacci(self, n):
        if n < 2:
            return n
        first = 0
        second = 1
        result = 1
        for i in range(2,n):
            first = second
            second = result
            result = first + second
        return result   # 当n=2时不执行for循环,result=1
n=20
solution = Solution()
print (solution.Fibonacci(n))

8.题目描述(同7,斐波那契数列)

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
考察知识:递归,记忆化搜索,动态规划和动态规划的空间优化。

解释:

我们把n级台阶时的跳法看成n的函数,记为f(n)。
当n>=2时,第一次跳的时候有两种不同的选择:

第一次跳1级,此时跳法的数目等于后面剩下的n-1级台阶的跳法数目,即为f(n-1);
第一次跳2级,此时跳法数目等于后面剩下的n-2级台阶的跳法数目,即为f(n-2)。
因此,n级台阶的不同跳法总数为f(n) = f(n-1) + f(n-2)

class Solution:
    def jumpFloor(self, number):
        #此题与菲波那切数列的本质一致
        if number == 1:
            return 1
        if number == 2:
            return 2
        fOne = 1
        fTwo = 2
        for i in range(3,number+1):
            fN = fTwo + fOne
            fOne = fTwo
            fTwo = fN
        return fN
solution = Solution()
print (solution. jumpFloor(3))

9.题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
这是一道可以递归,记忆化递归,动态规划,递推思想的题目。

分析:

f[n] = f[n-1] + f[n-2] + … + f[0]

f[n-1] = f[n-2] + f[n-3] + … + f[0]

f[n] = 2*f[n-1]

初始条件f[0] = f[1] = 1

f[2] = 2 = 2**1

f[3] = 4 = 2**2

f[4] = 8 = 2**3

f[n] = 2**n-1

class Solution:
    def jumpFloorII(self, number):
        if number == 0:
            return 1
        else:
            return 2**(number-1)
solution = Solution()
print (solution.jumpFloorII(4))

10.题目描述(同7,斐波那契数列)

我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2n的大矩形,总共有多少种方法?比如n=3时,23的矩形块有3种覆盖方法。
描述:这是一道规律题。
知识点:递归,记忆递归,动态规划,递推。

分析

从n=3到n=4,怎么来的呢?
这里有2种情况:
直接在n=3的情况下,再后面中添加一个竖着的。这个很显然成立,有3种情况。
然后横着的显然能添加到n-2的情况上,也就是在n=2后面,添加2个横着的,有2种情况。
通过以上分析,发现f [4]=5
所以总结:f [n]表示2*n大矩阵 的方法数。
可以得出:f[n] = f[n-1] + f[n-2],初始条件f[1] = 1, f[2] =2,此题与菲波那切数列的本质一致。

class Solution:
    def rectCover(self, number):
     #此题与菲波那切数列的本质一致
        if number == 0:
            return 0
        if number == 1:
            return 1
        if number == 2:
            return 2
 
        fOne = 1
        fTwo = 2
        for i in range(3,number+1):  # 确定循环次数
            fN = fTwo + fOne
            fOne = fTwo
            fTwo = fN
        return  fN
solution = Solution()
print (solution.rectCover(4))

猜你喜欢

转载自blog.csdn.net/xiaokeaiuiya/article/details/109014204