剑指offer/Leecode思路及代码汇总(python)

文章目录

剑指offer

以牛客网题号为准

JZ01 二维数组的查找

题目: 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
[
[1,2,8,9],
[2,4,9,12],
[4,7,10,13],
[6,8,11,15]
]
给定 target = 7,返回 true。
给定 target = 3,返回 false。

思路: 利用二维数组的特点。采用二分的思想,从数组的左下角开始遍历。

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

JZ02 替换空格

题目: 请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
思路: 把字符串中的每个字符一个个添加到新字符串中,如果遇到空格就把他换成%20。

class Solution:
    def replaceSpace(self , s ):
        # write code here
        res=[]
        for i in range(len(s)):
            if s[i]==' ':
                res.append('%20')
            else:
                res.append(s[i])
        ss=''.join(res)
        return ss

JZ03 从尾到头打印链表

**题目:**输入一个链表的头节点,按链表从尾到头的顺序返回每个节点的值(用数组返回)。
思路:利用insert函数。

# -*- 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
        pTempt=listNode
        res=[]
        while pTempt:
            res.insert(0,pTempt.val)
            pTempt=pTempt.next
        return res

JZ04 重建二叉树

题目: 给定某二叉树的前序遍历和中序遍历,请重建出该二叉树并返回它的头结点。
例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。
在这里插入图片描述
思路:

  1. 首先根据前序遍历得到根节点
  2. 找到中序遍历中根节点的索引,即可分出左子树和右子树。
  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 len(pre)==0 or len(tin)==0:
            return None
        root=TreeNode(pre[0])
        ind=tin.index(pre[0])
        root.left=self.reConstructBinaryTree(pre[1:ind+1], tin[0:ind])
        root.right=self.reConstructBinaryTree(pre[ind+1:len(pre)], tin[ind+1:len(tin)])
        return root

JZ05:用两个栈实现队列

题目: 用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
思路: 入栈时数据存入栈stackIn, 出栈时数据从stackOut弹出。执行入栈操作时,将数据源源不断的压入栈stackIn;执行出栈操作时,将stackIn的数据一次性全部弹出,存入到stackOut中。当stackOut栈非空时,不断弹出stackOut栈中的数据顺序即为队列的Pop顺序;当stackOut中的数据为空后,再将新入栈stackIn的数据一次性存入stackOut中即可。相比于上一种方式,这种方式极大降低了数据在栈stackIn和栈stackOut中来回无意义的腾挪操作,占据更低的存储空间,消耗更低的运算时间。

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stackIn = []
        self.stackOut = []

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

    def pop(self):
        if self.stackOut:
            return self.stackOut.pop()
        elif not self.stackIn:
            return None
        else:
            while self.stackIn:
                self.stackOut.append(self.stackIn.pop())
            return self.stackOut.pop()

JZ06 旋转数组的最小数字

题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        if len(rotateArray)==0:
            return 0
        left=0
        right=len(rotateArray)-1
        
        while left<right:
            mid=(left+right)//2
            if rotateArray[mid]>rotateArray[right]:
                left=mid+1
            elif rotateArray[mid]<rotateArray[right]:
                right=mid
            else:
                right-=1
        return rotateArray[left]

JZ7 斐波那契数列

题目: 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)。
思路: 递归法时间复杂度过高。因此采用递推法,时间复杂度为O(n)。

# -*- coding:utf-8 -*-
class Solution:
    def Fibonacci(self, n):
        a,b=0,1
        for i in range(n):
            a,b=b,a+b
        return a

JZ08:跳台阶

递归

def numWays(self, n: int) -> int:
        if n == 0:
            return 1
        elif n == 1:
            return 1
        elif n == 2:
            return 2
        else:
            return (self.numWays(n - 1) + self.numWays(n-2)) 

非递归:

class Solution:
    def jumpFloor(self, number):
        # write code here
        if number<1:
            return 0
        a=1
        b=2
        for i in range(number-1):
            a,b=b,a+b
        return a

JZ9 跳台阶扩展问题

**题目:**一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶(n为正整数)总共有多少种跳法。
思路:
f [ n ] = f [ n − 1 ] + f [ n − 2 ] + . . . + f [ 0 ] f[n] = f[n-1] + f[n-2] + ... + f[0] f[n]=f[n1]+f[n2]+...+f[0]
f [ n − 1 ] = f [ n − 2 ] + f [ n − 3 ] + . . . + f [ 0 ] f[n-1] = f[n-2] + f[n-3] + ... + f[0] f[n1]=f[n2]+f[n3]+...+f[0]
所以一合并, f [ n ] = 2 ∗ f [ n − 1 ] = 2 n − 1 f[n] = 2*f[n-1]=2^{n-1} f[n]=2f[n1]=2n1,初始条件f[0] = f[1] = 1

# -*- coding:utf-8 -*-
class Solution:
    def jumpFloorII(self, number):
        # write code here
        return pow(2,number-1)

JZ10-矩阵覆盖

题目: 我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2n的大矩形,总共有多少种方法?
比如n=3时,2
3的矩形块有3种覆盖方法:
在这里插入图片描述思路: 假设2*n的第一个矩形竖着放,则剩下的就是f(n-1).假设第一个横着放,那么第二个必须在下面横着放,剩下的就是f(n-2)
则递推公式为f(n)=f(n-1)+f(n-2),且f(1)=1,f(2)=2.
(注意n<=1的情况)

class Solution:
    def rectCover(self, number):
        # write code here
        if number<=1:
            return number
        a=1
        b=2
        for i in range(number-1):
            a,b=b,a+b
        return a

JZ11-二进制中1的个数

题目: 输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。

思路: 1100&1011=1000。也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0。那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。
但python当超出int的32位时会自动转化为long型,上述代码“n = n &(n - 1)”在执行时,当执行到倒数第二步,即原来的整数变成 1(31个0)时,该整数减一,在c++中结果为0(31个1),相与之后结果为0,终止循环。但是python在计算该整数减一时,会得到1(32个0),陷入无限循环。因此通过“n & 0xffffffff”实现python只取32位的功能,相与之后32位之前不会再有值。

class Solution:
    def NumberOf1(self, n):
        # write code here
        cou = 0
        if n < 0:
            n = n & 0xffffffff
        while n:
            cou = cou + 1
            n = n &(n - 1)
        return cou

JZ12-数值的整数次方

题目: 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
保证base和exponent不同时为0
思路: 如果base为0,直接返回0。如果exponent为0,返回1.
采用递推公式,如果exponent为正数:Power(base, exponent)=base*Power(base, exponent-1)。
如果exponent为负数:Power(base, exponent)=(1/base)*Power(base, exponent+1)

class Solution:
    def Power(self, base, exponent):
        # write code here
        if base==0:
            return 0
        if exponent==0:
            return 1
        if exponent>0:
            return base*self.Power(base, exponent-1)
        else:
            return (1/base)*self.Power(base, exponent+1)
# -*- coding:utf-8 -*-
class Solution:
    def Power(self, base, exponent):
        # write code here
        if base==0:
            return 0
        if exponent>0:
            if exponent%2==0:
                result=self.Power(base, exponent//2)
                result=result**2
                return result
            elif exponent%2==1:
                result=self.Power(base, exponent//2)**2
                result=result*base
                return result
        elif exponent<0:
            result=self.Power(1/base, abs(exponent))
            return result
        else:
            return 1

JZ13-调整数组顺序使奇数位于偶数前面

**题目:**输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
思路: 遍历,若余数为1,append到奇数数组,反之append到偶数数组。最后讲奇数和偶数数组加起来即可。

class Solution:
    def reOrderArray(self , array ):
        # write code here
        oddarray=[]
        evenarray=[]
        for i in array:
            if i%2==0:
                evenarray.append(i)
            else:
                oddarray.append(i)
        return oddarray+evenarray

JZ14-链表中倒数第k个结点

题目: 输入一个链表,输出该链表中倒数第k个结点。
思路: 在链表中:倒数的+顺数的长度等于链表总长度,所以可以设置两个指针,一个先走K步,剩下的到链表的末尾要走的步数就是倒数第k个节点需要从头开始走的步数。
注意在先移动k步快指针时,需要先判断k是否为空再挪指针,因为当快指针第一次为空时,慢指针不是None。否则,若第k步正好快指针指向None时慢指针也会返回None,是不对的。

class Solution:
    def FindKthToTail(self , pHead , k ):
        # write code here
        fast=pHead
        slow=pHead
        for i in range(k):
            if not fast:
                return None
            fast=fast.next
        while fast:
            fast=fast.next
            slow=slow.next
        return slow

JZ15-反转链表

题目: 输入一个链表,反转链表后,输出新链表的表头。
思路: 先保留现有链表的第二个节点,将现有链表的头指向已反转的链表。从现有链表第二个节点开始为新的链表,更新已反转的链表。迭代至尾结点。

class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        # write code here
        if pHead==None:
            return None
        last=None
        while pHead:
            tmp=pHead.next
            pHead.next=last 
            last=pHead
            pHead=tmp
        return last

JZ16-合并有序链表

题目: 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
思路: 利用递归,首先如果有一个链表为空,则直接返回另一个链表。比较两个链表的值,将表头小的链表指向下一个,并递归调用。

class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        # write code here
        if pHead1==None:
            return pHead2
        if pHead2==None: 
            return pHead1
        if pHead1.val<pHead2.val:
            rec=pHead1
            rec.next=self.Merge(pHead1.next,pHead2)
        else:
            rec=pHead2
            rec.next=self.Merge(pHead1,pHead2.next)
        return rec

JZ17-树的子结构

题目: 输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
思路: 使用函数嵌套递归判断是否匹配到起始节点;另写一个递归,判断左子树和右子树是否为子结构的函数。

1、 判断A当前节点开始,B是否为子结构,如果不是,看下A的左子树节点,如果也不是再看下A的右子树。
2、如果是某节点开始A与B的起始节点重合:
①判断B是否匹配完了,如果匹配完了说明为子结构
②如果A匹配完了,或者A的值和B和值不等,直接返回False
③如果当前点相同,那同时看一下左子树和右子树的情况。

class Solution:
    def HasSubtree(self, pRoot1, pRoot2):
        # write code here
        if not pRoot1 or not pRoot2:
            return None
        return self.isSubtree(pRoot1,pRoot2) or self.HasSubtree(pRoot1.left, pRoot2) or self.HasSubtree(pRoot1.right, pRoot2)
    def isSubtree(self, A, B):
        if not B:
            return True
        if not A or A.val!=B.val:
            return False
        else:
            return self.isSubtree(A.left,B.left) and self.isSubtree(A.right,B.right)

JZ18-二叉树的镜像

题目: 操作给定的二叉树,将其变换为源二叉树的镜像。
思路:

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值