首页 > 其他分享 >【剑指Offer刷题系列】数值的整数次方

【剑指Offer刷题系列】数值的整数次方

时间:2025-01-06 15:29:35浏览次数:11  
标签:10 exponent Offer 复杂度 示例 current 次方 self 刷题


目录


问题描述

实现 pow(x, n),即计算 xn 次幂函数(即,x^n)。

注意

  • x 是一个双精度浮点数。
  • n 是一个整数,可以是正数、负数或零。
  • 结果需要保证在 [-10^4, 10^4] 范围内。

提示

  • -100.0 < x < 100.0
  • -2^{31} <= n <= 2^{31} - 1
  • -10^4 <= x^n <= 10^4

原题链接:https://leetcode-cn.com/problems/powx-n/https://leetcode.cn/problems/shu-zhi-de-zheng-shu-ci-fang-lcof/description/


示例

示例 1:

输入:

x = 2.00000, n = 10

输出:

1024.00000

解释:
2^10 = 1024

示例 2:

输入:

x = 2.10000, n = 3

输出:

9.26100

解释:
2.1^3 = 9.261

示例 3:

输入:

x = 2.00000, n = -2

输出:

0.25000

解释:
2^-2 = 1/(2^2) = 0.25


思路解析

本题要求实现一个函数 pow(x, n),计算 xn 次幂。由于 n 可以是正数、负数或零,且 x 是一个浮点数,因此需要考虑多种情况。为了高效地计算 x^n,可以采用 快速幂算法(也称为 二分幂),其时间复杂度为 O(log n)

核心思路:

  1. 快速幂算法

    • 利用二分思想,将幂运算拆分为更小的部分。
    • 例如,x^10 可以分解为 (x^5)^2x^5 又可以分解为 x * (x^2)^2
  2. 处理负指数

    • 如果 n 为负数,则 x^n = 1 / x^{-n}
    • 需要特别处理 n-2^{31} 的情况,因为 -n 会超出 32 位整数的范围。
  3. 递归与迭代实现

    • 递归:通过函数调用实现快速幂的分解。
    • 迭代:通过循环实现快速幂,避免递归带来的额外空间开销。
  4. 边界条件

    • n0 时,x^0 = 1
    • x0 时,0^n 取决于 n 的值,但根据题目限制,x 不会为 0

具体步骤:

  1. 初始化

    • 如果 n0,直接返回 1
    • 如果 n 为负数,转换为计算 1 / x^{-n}。需要注意处理 n = -2^{31} 的情况。
  2. 快速幂计算

    • 通过快速幂算法,迭代地将问题规模减半。
    • 如果当前指数为奇数,将结果乘以当前的基数。
    • 每次迭代将基数平方,并将指数右移一位(即除以 2)。
  3. 返回结果

    • 根据 n 的正负返回最终的结果。

复杂度分析:

  • 时间复杂度O(log n),其中 n 是指数的绝对值。快速幂算法通过每次将问题规模减半,实现了对数级别的时间复杂度。

  • 空间复杂度O(1),使用常数级别的额外空间。若采用递归实现,则空间复杂度为 O(log n),由于递归调用栈的深度为 log n


代码实现

Python 实现

class Solution:
    def myPow(self, x: float, n: int) -> float:
        """
        计算 x 的 n 次幂(x^n)。
        :param x: float - 基数
        :param n: int - 指数
        :return: float - 结果
        """
        if n == 0:
            return 1.0
        
        # 如果 n 是负数,转换为计算 1 / x^{-n}
        if n < 0:
            x = 1 / x
            # 处理 n = -2^31 的情况
            n = -n if n != -2147483648 else 2147483647
        
        result = 1.0
        current_product = x
        current_exponent = n
        
        while current_exponent > 0:
            if current_exponent % 2 == 1:
                result *= current_product
            current_product *= current_product
            current_exponent //= 2
        
        return result

测试代码

以下是针对上述方法的测试代码,使用 unittest 框架进行验证。

import unittest

class Solution:
    def myPow(self, x: float, n: int) -> float:
        """
        计算 x 的 n 次幂(x^n)。
        :param x: float - 基数
        :param n: int - 指数
        :return: float - 结果
        """
        if n == 0:
            return 1.0
        
        # 如果 n 是负数,转换为计算 1 / x^{-n}
        if n < 0:
            x = 1 / x
            # 处理 n = -2^31 的情况
            n = -n if n != -2147483648 else 2147483647
        
        result = 1.0
        current_product = x
        current_exponent = n
        
        while current_exponent > 0:
            if current_exponent % 2 == 1:
                result *= current_product
            current_product *= current_product
            current_exponent //= 2
        
        return result

class TestMyPow(unittest.TestCase):
    def setUp(self):
        self.solution = Solution()

    def test_example1(self):
        x = 2.00000
        n = 10
        expected = 1024.00000
        self.assertAlmostEqual(self.solution.myPow(x, n), expected, places=5, msg="示例1失败")

    def test_example2(self):
        x = 2.10000
        n = 3
        expected = 9.26100
        self.assertAlmostEqual(self.solution.myPow(x, n), expected, places=5, msg="示例2失败")

    def test_example3(self):
        x = 2.00000
        n = -2
        expected = 0.25000
        self.assertAlmostEqual(self.solution.myPow(x, n), expected, places=5, msg="示例3失败")

    def test_zero_exponent(self):
        x = 2.0
        n = 0
        expected = 1.0
        self.assertAlmostEqual(self.solution.myPow(x, n), expected, places=5, msg="零指数测试失败")

    def test_negative_exponent_large(self):
        x = 2.0
        n = -2147483648
        # 由于 n = -2147483648 时,-n 会超出 32 位整数范围,这里仅验证不抛出异常
        result = self.solution.myPow(x, n)
        self.assertTrue(0.0 <= result <= 1.0, "负指数极大测试失败")

    def test_one_base_zero_exponent(self):
        x = 1.0
        n = 0
        expected = 1.0
        self.assertAlmostEqual(self.solution.myPow(x, n), expected, places=5, msg="基数为1且指数为0测试失败")

    def test_one_base_positive_exponent(self):
        x = 1.0
        n = 100
        expected = 1.0
        self.assertAlmostEqual(self.solution.myPow(x, n), expected, places=5, msg="基数为1且正指数测试失败")

    def test_one_base_negative_exponent(self):
        x = 1.0
        n = -100
        expected = 1.0
        self.assertAlmostEqual(self.solution.myPow(x, n), expected, places=5, msg="基数为1且负指数测试失败")

    def test_negative_base_even_exponent(self):
        x = -2.0
        n = 4
        expected = 16.0
        self.assertAlmostEqual(self.solution.myPow(x, n), expected, places=5, msg="负基数偶数指数测试失败")

    def test_negative_base_odd_exponent(self):
        x = -2.0
        n = 3
        expected = -8.0
        self.assertAlmostEqual(self.solution.myPow(x, n), expected, places=5, msg="负基数奇数指数测试失败")

if __name__ == "__main__":
    unittest.main(argv=[''], exit=False)

输出:

..........
----------------------------------------------------------------------
Ran 10 tests in 0.XXXs

OK

复杂度分析

时间复杂度

  • 总体复杂度O(log n),其中 n 是指数的绝对值。
    • 采用快速幂算法,每次将问题规模减半,因此时间复杂度为对数级别。

空间复杂度

  • 总体复杂度O(1)
    • 使用常数级别的额外空间。
    • 若采用递归实现,空间复杂度为 O(log n),由于递归调用栈的深度为对数级别。

结论

通过采用 快速幂算法,我们能够高效地计算一个浮点数 x 的整数次幂 n。该方法利用了幂运算的二分性质,将计算过程中的时间复杂度降低至 O(log n),同时保持了空间复杂度的最小化。无论 n 是正数、负数还是零,快速幂算法都能准确地计算出结果。

掌握此类快速幂的实现技巧,对于解决各种需要高效幂运算的编程问题具有重要的指导意义,能够在实际编程和算法设计中灵活应用,提高代码的性能和效率。

标签:10,exponent,Offer,复杂度,示例,current,次方,self,刷题
From: https://blog.csdn.net/weixin_44329069/article/details/144964353

相关文章

  • AtCoder备赛刷题 ABC 361 | x = a^b
    学习C++从娃娃抓起!记录下AtCoder(日本算法竞技网站)备赛学习过程中的题目,记录每一个瞬间。附上汇总贴:AtCoder备赛刷题|汇总【ProblemStatement】Howmanyintegersxx......
  • AtCoder备赛刷题 ABC 361 | Go Territory
    学习C++从娃娃抓起!记录下AtCoder(日本算法竞技网站)备赛学习过程中的题目,记录每一个瞬间。附上汇总贴:AtCoder备赛刷题|汇总【ProblemStatement】ThereareNNNston......
  • 英文翻译(10的10次方以内的数字翻译)
    #include<bits/stdc++.h>usingnamespacestd;stringn;stringa[]={"","one","two","three","four","five","six","seven","eight","nine","ten&quo......
  • 打卡信奥刷题(540)用C++信奥P7060[普及组/提高]P7060 [NWRRC2014] Alarm Clock
    [NWRRC2014]AlarmClock题面翻译Alice梦见了一个时间,但她只记得了这个时间在电子钟上显现出来的段数,现在给出这个段数,让你反推Alice梦见的时间(若有多个答案,输出任意一个均可)段数:想必大家都听说过用火柴拼数字的游戏,比如1要用两个火柴,2要用5根火柴,8要用7根火柴等等(如题目......
  • 力扣刷题:栈和队列OJ篇(下)
    大家好,这里是小编的博客频道小编的博客:就爱学编程很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!!目录1.括号匹配问题(1)题目描述(2)解题思路2.循环队列(1)题目描述(2)解题思路快乐的时光总是短暂,咱们下篇博文再见啦!!!如果小编的文章会对......
  • 已拿offer|西安华为 Java 面经
    西安华为Java面经​ 写在前面,推荐这个ai面试产品,多面鹅ai,真的很好用。在面试前已经模拟面试准备过很多次,多亏了多面鹅帮我模拟面试还复盘,给了我很大的帮助!还有线上面试同步ai辅助提醒的功能,但是我没用,有用过的小伙伴可以分享一下经验!OfferGoose多面鹅官网- AI面试模......
  • day2算法刷题
    螺旋矩阵2模拟题,但边界条件真的要理清,不然很容易死循环。tle不用慌,多打断点调试即可。坚持左开右闭思想,控制变量也能解决,而且不容易乱。区间和前缀和板子题开发商购买土地前缀和的应用,不算难。链表移除链表元素递归做最简便但难想,直接写注意分情况讨论头节点和......
  • Leetcode刷题第三天-二分查找
    162.寻找峰值-力扣(LeetCode)没二分,数组头尾分别插入最小值和最大值,比较num[i-1]<num[i]>num[i+1]classSolution:deffindPeakElement(self,nums:List[int])->int:ifnotnums:returnNonemax_num,min_num=min(nums)-1,min(nums)-1......
  • 打卡信奥刷题(523)用C++信奥P6861[普及组/提高] [RC-03] 难题
    [RC-03]难题题目描述求两个整数a,ba,ba,b(......
  • 力扣刷题:栈和队列OJ篇(上)
    大家好,这里是小编的博客频道小编的博客:就爱学编程很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!!目录1.用队列实现栈(1)题目描述(2)解题思路2.用两个栈实现队列(1)题目描述(2)解题思路快乐的时光总是短暂,咱们下篇博文再见啦!!!如果小编的......