剑指offer--数值的整数次方&&重建二叉树&&二维数组元素的查找

题目:

实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。不得使用库函数,同时不需要考虑大数问题。

示例 1:

输入:x = 2.00000, n = 10
输出:1024.00000

思路:既不能使用库函数,也要让时间复杂度降低,还要不需要考虑大数问题

首先第一种思路:直接return x**n,反正也可以通过,但是想考察的肯定不是这个

第二种思路:使用快速幂连上二分法来计算,如果我们要计算x^64,那我们可以第一次计算出x,第二次是x^2,第三次就是x^4,下一次就是x^8,每次把这次计算出来的值作为底数,就不用再计算64次了。也就把题目转变为了(X^2)^(n/2),所以每次计算一次之后幂就变为了n/2,但是还要考虑n是奇数还是偶数的问题,如果是奇数,那最后肯定要多乘上一个x,如果是偶数那就不用乘,所以这里还多引入了一个res

代码:

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

题目二:重建二叉树,也就是利用三种遍历队列中的两种实现二叉树的重建

本题的前提是两个遍历中不会产生重复的数,产生了那这个递归的方法也就不能使用了

思路:

先序中的第一个就是根节点,在中序中找到相对应的根节点位置,那根节点的左侧节点就全部都是左子树,同理右边为右子树,左子树的节点个数同先序列表中左子树的节点个数是相同的,所以也就可以把先序遍历分为三个部分,第一部分就是根节点,第二部分是左子树,个数根据中序列表可以算出,第三个是右子树;同时我们还知道先序中的三部分都是先序,中序中的三部分都是中序,那我们就可以利用这一点,不停的向下递归,产生左子树的左右孩子,右子树的左右孩子。

代码:

# 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:
        #通过边界将前序遍历序列和中序遍历序列分为不同的部分
        #递归方法
        def build(pre_left:int,pre_right:int,in_left:int,in_right:int):
            if pre_left>pre_right:
                return None
            #先序遍历的第一个根节点,在中序遍历中找到该根节点,根节点左侧的就是左子树,右侧的是右子树部分,然后可以用节点的个数将先序遍历的左右子树分别分开
            #由例子来讲解就是先序中3是根节点,那中序中找到3,3左边的9就是左子树部分,3右边的15,20,7就是右子树的部分
            #这样就把先序列表中的9和20,15,7分开,再分别用同样的方法递归3这一部分还有20,15,7这一部分了


            #先找到根节点
            pre_root=pre_left#先序中的第一个节点对应的就是根节点
            pre_root=preorder[pre_root]#找到对应的根节点的值,等下要在中序遍历中找到对应的位置
            in_root=index[pre_root]#这里的index是把中序遍历写成了一个哈希表,这样就不必每次都循环整个列表造成时间的浪费,找到了root在中序中对应的位置,然后先序列表就被分为了三部分,每一个部分都是一个先序遍历的列表
            #先创建一个根节点
            root=TreeNode(pre_root)
            size=in_root-in_left
            root.left=build(pre_left+1,pre_left+size,in_left,in_root-1)#创建左子树,并且把左子树部分的先序和中序序列再进行递归
            root.right=build(pre_left+1+size,pre_right,in_root+1,in_left)
            return root

        #做一个中序遍历的哈希表
        index={value:key for key,value in enumerate(inorder)}
        n=len(preorder)
        return build(0,n-1,0,n-1)

利用哈希表的目的是减少每次查询根节点在哪个位置的时间,提高效率 ,使用了enumerate函数枚举并且将键值反了过来。

题目:

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

示例:

现有矩阵 matrix 如下:

[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]
给定 target = 5,返回 true。

给定 target = 20,返回 false。

思路:二维数组查找的题目,如果不考虑时间的问题的话可以直接使用暴力查找,但是题中给出的升序肯定是有用的,先写出暴力查找的代码,两个for循环

代码1:

class Solution:
    def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
        for i in range(0,len(matrix)):
            for x in range(0,len(matrix[0])):
                if matrix[i][x]==target:
                    return True
                    break
        return False

思路二:我们可以找一个标志位,左下角或者右上角,这里以左下角举例,用i表示某一行,j表示某一列,如果我们要查找一个数,该数比左下角的数大,那第一列肯定是不用看了,j+1,如果比左下角的数小,那最后一行不用看了,直接i-1,如果相等了,那就返回出来,循环条件是i>=0 and j<=len(matrix[0])-1,保证两个都不出界。

代码:

class Solution:
    def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
        #通过标志位来写,把左下角或者右上角作为标志位
        i=len(matrix)-1
        j=0
        while i>=0 and j<=len(matrix[0])-1:
            if matrix[i][j]>target:i-=1
            elif matrix[i][j]<target:j+=1
            else:return True
        return False

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
二叉树查找的基本思路是:将数组中的元素插入到一个二叉查找树中,然后在树中进行查找。 以下是用C语言实现二叉树查找的代码: ```c #include <stdio.h> #include <stdlib.h> typedef struct node { int data; struct node* left; struct node* right; } Node; Node* createNode(int data) { Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = data; newNode->left = NULL; newNode->right = NULL; return newNode; } Node* insert(Node* root, int data) { if (root == NULL) { return createNode(data); } if (data < root->data) { root->left = insert(root->left, data); } else if (data > root->data) { root->right = insert(root->right, data); } return root; } Node* search(Node* root, int data) { if (root == NULL || root->data == data) { return root; } if (data < root->data) { return search(root->left, data); } else { return search(root->right, data); } } int main() { int buffer[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5}; int n = sizeof(buffer) / sizeof(buffer[0]); Node* root = NULL; for (int i = 0; i < n; i++) { root = insert(root, buffer[i]); } int target = 5; Node* result = search(root, target); if (result == NULL) { printf("%d not found\n", target); } else { printf("%d found\n", target); } return 0; } ``` 上述代码中,我们定义了一个结构体`node`表示二叉树的节点,其中包括一个整数`data`和两个向左右子树的针`left`和`right`。函数`createNode`用于创建新的节点,函数`insert`用于将一个元素插入到二叉查找树中,函数`search`用于在二叉查找树中查找一个元素。 在`main`函数中,我们首先定义了一个一维数组`buffer`,然后将数组中的元素插入到一个二叉查找树中。最后,我们以`5`为例,在树中查找元素,并输出查找结果。 注意,二叉查找树的插入和查找操作的时间复杂度都为$O(log n)$,其中$n$为树中节点的数量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值