剑指offer

一、二维数组的查找

思路1、从二维数组的右上角的元素开始判断,因为此元素是它所在行的最大数,是它所在的列的最小数。如果它等于要查找的数字,则查找过程结束。如果它大于要查找的数字,则可以排除它所在的列。如果它小于要查找的数字,则可排除它所在的行。这样如果要查找的数字不在数组的右上角,则每次判断都可以排除一行或一列以缩小查找范围,直到找到要查找的数字,或者查找范围为空。


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

#339ms 5840k

思路2:遍历一遍

class Solution:
    # array 二维列表
    def Find(self,num,array):
        for  row in array:
            for j in row:
                if num==j:
                    return True
        return False

#331ms 5708k


参考:https://blog.csdn.net/jackmcgradylee/article/details/77871569 

二、重建二叉树

递归思路:前序遍历=“根左右”,中序遍历=“左根右”。 
由前序遍历序列获得根节点及其位置——>由根节点和对应位置,分别获得:左子树的前序遍历序列和中序遍历序列,以及右子树的前序遍历序列和中序遍历序列——>分别递归左子树的前中序列,右子树的前中序列

# -*- 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:
            return None
        if len(pre)==1:
            return TreeNode(pre[0])
        else:
            root=TreeNode(pre[0])
            root.left=self.reConstructBinaryTree(pre[1:tin.index(pre[0])+1],tin[:tin.index(pre[0])])
            root.right=self.reConstructBinaryTree(pre[tin.index(pre[0])+1:],tin[tin.index(pre[0])+1:])
        return root



#56ms 5632k

三、用两个栈实现队列

思路一、stack1用于push,再判断stack2是否为空,如果为空,则将stack1的所有的数据pop出来,压入stack2中,pop sack2,否则直接pop  stack2

#29ms 5624k
# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack1=[]
        self.stack2=[]
    def push(self, node):
        # write code here
        self.stack1.append(node)
    def pop(self):
        # return xx
        if self.stack2==[]:
            while self.stack1:
                self.stack2.append(self.stack1.pop())
            return self.stack2.pop()
        return self.stack2.pop()

参考:https://www.cnblogs.com/wanghui9072229/archive/2011/11/22/2259391.html

四、二叉树的下一个节点

思路1:

1.二叉树为空,则返回空;

2.如果一个节点有右子树,那么它的下一个节点就是它的右子树中的最左子节点

3.如果一个节点没有右子树:如果节点是它的父节点的左节点,那么它的下一个节点就是它的父节点,如果节点是它的父节点的右节点,沿着父节点的指针一直向上遍历,直到找到一个是它父节点的左子节点的节点。

# -*- coding:utf-8 -*-
# class TreeLinkNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
#         self.next = None
class Solution:
    
    def GetNext(self, pNode):
        if not pNode:
            return None
        if pNode.right:
            pNode=pNode.right
            while pNode.left:
                pNode=pNode.left
            return pNode
        else:
            while pNode.next:
                if pNode==pNode.next.left:
                    return pNode.next
                pNode=pNode.next
        return None

五、链表中倒数第K个节点

思路1:遍历一次链表获得链表长度,再次遍历链表,至n-k+1个输出

#这是我写的代码,很垃圾
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def FindKthToTail(self, head, k):
        if head==None or k<=0:
            return None

        node=head
        num1=1
        while node.next!=None:
            node=node.next
            num1=num1+1
            
        if k>num1:
            return None
        num2=0
        node2=head
        while num2<num1-k:
            num2=num2+1
            node2=node2.next
        return node2
#网上找的代码,写的还不错
class Solution:
    def FindKthToTail(self, head, k):
        # write code here
        if head == None or k <= 0:
            return None
        p = head
        n = 1
        while p.next != None:
            p = p.next
            n = n+1
        if k > n:
            return None
        for i in range(n-k):
            head = head.next
        return head

思路2:设置2个指针,第一个指针走K-1步之后,第二个指针开始从头走,这样两个指针之间始终相隔K,当指针2走到链表结尾时,指针1的位置即倒数K个节点
思路推广:寻找中间节点, 两个指针一起, 第一个指针每次走两步, 第二个指针每次走一步, 快指针指到尾部, 慢指针正好指到中间

class Solution:
    def FindKthToTail(self, head, k):
        # write code here
        if head == None or k <= 0:
            return None
        p1 = head
        p2 = head
        for i in range(k-1):
            if p1.next == None:
                return None
            p1 = p1.next
        while p1.next != None:
            p1 = p1.next
            p2 = p2.next
        return p2
--------------------- 
作者:slibra_L 
来源:CSDN 
原文:https://blog.csdn.net/slibra_L/article/details/78176540 
版权声明:本文为博主原创文章,转载请附上博文链接!

六、反转链表

思路:建立三个变量,L、M、R互相赋值迭代,并建立指向关系,从而实现单链表的反转。这里为什么要设置三个变量,是因为只设置两个变量的话,会出现断开的情况

class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        if pHead==None:
            return None
        L,M,R=None,None,pHead
        
        while R!=None:
            L=M
            M=R
            R=R.next
            M.next=L
        M.next=L
        return M

七、合并两个排序的链表

思路1:

#递归
class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        if not pHead1:
            return pHead2
        if not pHead2:
            return pHead1
        
        if pHead1.val<pHead2.val:
            pHead1.next=self.Merge(pHead1.next,pHead2)
            return pHead1
        else:
            pHead2.next=self.Merge(pHead1,pHead2.next)
            return pHead2

思路2:非递归,Low)
找到两个链表中头节点值相对更小的链表,将其作为主链表,第二个链表中的元素则不断加入到主链表中。具体策略是:主链表定义两个指针,指向两个相邻的元素。当第二个链表中的元素值小于主链表中第二个指针时,将第二个链表的当前元素插入到主链表两个指针指向的元素中间,并调整指针指向。

def Merge(self, pHead1, pHead2):
    if not pHead1:
        return pHead2
    if not pHead2:
        return  pHead1
    mainHead = pHead1 if pHead1.val <= pHead2.val else pHead2
    secHead = pHead2 if mainHead == pHead1 else pHead1
    mergeHead = mainHead
    mainNext = mainHead.next
    while mainNext and secHead:
        if secHead.val <= mainNext.val:
            mainHead.next = secHead
            secHead = secHead.next
            mainHead.next.next = mainNext
            mainHead = mainHead.next
        else:
            mainHead = mainNext
            mainNext = mainNext.next
    if not mainNext:
        mainHead.next = secHead
    return mergeHead

八、矩形覆盖问题

思路1:我们采用从能够简单到复杂的思路思考这个问题,当n=1的时候,只有一个2*1的矩形,所以只有一种方法,记为f(1)=1;当n=2的时候,是两个2*1的矩形,这时候具有两种方式去覆盖这个矩形了(这时候应该是一个正方形),一种是竖着放,一种是横着放,所以有两种方法,记为f(2)=2;

当n=3的时候,仍然只能采用横着放或者竖着放的方式去覆盖这个矩形,我们仍首先考虑使用竖着放的方式,当竖着放的时候,由于已经覆盖了左边(假设是从左边开始覆盖的,从右边的覆盖的效果是一样的)一个2*1的矩形,所以还有2个2*1的矩形,而这种情况我们已经在n=2的时候计算出来了,就是f(2);接下来我们考虑横着放的情况,由于是横着放,在水平方向已经覆盖了一个2*1的矩形,所以要想覆盖这由3个2*1组成的矩形,只能在水平方向的覆盖的那个矩形下面继续覆盖一个,那么只剩下一个2*1的矩形了,这也通过前面的分析计算出来了,就是f(1)。综合以上分析,当n=3的时候,覆盖的方法是f(3)=f(1)+f(2)。

其他以此类推,我们发现这仍然是一个斐波那契数列,所以我们写出如下代码(已被牛客AC):

或者:n=1 - 只有横放一个矩形一种解决办法 
n=2 - 有横放一个矩形,竖放两个矩形两种解决办法 
n=3 - n=2的基础上加1个横向,n=1的基础上加2个竖向 
n=4 - n=3的基础上加1个横向,n=2的基础上加2个竖向

#动态规划
class Solution:
    def rectCover(self, number):
        if number<=0:
            return 0
        res=[1,2]
        if number>=3:
            for i in range(3,number+1):
                res.append(res[-1]+res[-2])
        return res[number-1]

九、旋转数组的最小数字

思路:这道题最直观的解法并不难,从头到尾遍历数组一次,我们就能找出最小的元素。这种思路的时间复杂度显然是O(n)。但是这个思路没有利用输入的旋转数组的特性,肯定达不到面试官的要求

  我们注意到旋转之后的数组实际上可以划分为两个排序的子数组,而且前面的子数组的元素都大于或者等于后面子数组的元素。我们还注意到最小的元素刚好是这两个子数组的分界线。在排序的数组中我们可以用二分查找法实现O(logn)的查找

  Step1.和二分查找法一样,我们用两个指针分别指向数组的第一个元素和最后一个元素。

  Step2.接着我们可以找到数组中间的元素:

  如果该中间元素位于前面的递增子数组,那么它应该大于或者等于第一个指针指向的元素。此时数组中最小的元素应该位于该中间元素的后面。我们可以把第一个指针指向该中间元素,这样可以缩小寻找的范围。移动之后的第一个指针仍然位于前面的递增子数组之中。如果中间元素位于后面的递增子数组,那么它应该小于或者等于第二个指针指向的元素。此时该数组中最小的元素应该位于该中间元素的前面。

  Step3.接下来我们再用更新之后的两个指针,重复做新一轮的查找。

按照上述的思路,第一个指针总是指向前面递增数组的元素,而第二个指针总是指向后面递增数组的元素。最终第一个指针将指向前面子数组的最后一个元素,而第二个指针会指向后面子数组的第一个元素。也就是它们最终会指向两个相邻的元素,而第二个指针指向的刚好是最小的元素。这就是循环结束的条件。

class Solution:
    def minNumberInRotateArray(self, rotateArray):
        if len(rotateArray)<=0:
            return 0
        low=0
        high=len(rotateArray)-1
        while low<high:
            if rotateArray[low]<rotateArray[high]:
                return rotateArray[low]

            mid=(high-low)//2+low

            if rotateArray[mid]>rotateArray[high]:
                low=mid+1
            else:
                high=mid
        return rotateArray[low]

10 树的子结构

思路1:需要两个函数,一个用来判断是不是子结构,另外一个是用来进行初始化。

判断是否是子结构的时候,如果当前值相等,需要进行左右值是否相等的判断;如果当前值不等,则判断Root1的左右子树是否包含Root2.

class Solution:
    def HasSubtree(self, pRoot1, pRoot2):
        if pRoot1==None or pRoot2==None:
            return False
        return self.issubtree(pRoot1,pRoot2)
    def issubtree(self,p1,p2):
        res=False
        if p2==None:
            return True
        if p1==None:
            return p1==p2
        if p1.val==p2.val:
            res= self.issubtree(p1.left,p2.left) and self.issubtree(p1.right,p2.right)
        return res or self.issubtree(p1.left,p2) or self.issubtree(p1.right,p2)

思路2:https://www.cnblogs.com/GF66/p/9785465.html

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值