Leetcode 50.Pow(x,n)

news2024/11/26 15:46:19

 

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

示例 1:

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

示例 2:

输入:x = 2.10000, n = 3
输出:9.26100

示例 3:

输入:x = 2.00000, n = -2
输出:0.25000
解释:2-2 = 1/22 = 1/4 = 0.25

提示:

  • -100.0 < x < 100.0
  • -231 <= n <= 231-1
  • n 是一个整数
  • 要么 x 不为零,要么 n > 0 。
  • -104 <= xn <= 104

一、信息

1.实现数学中的幂函数。

2.三个示例

二、分析

条件1:告诉我此次的目的

条件2:告诉我这个函数结果保留小数点后五位

三、步骤

第一步 接收x和n

第二步 n赋值给循环的次数,x赋给每次要乘的数

第三步 循环相乘

第三步 return 即可

流程图:

四、遇到问题

1.由于n如果时负数那么我们显然累乘将失效,因为此时的x已经是它的倒数的累乘了而计算机其实根本不认识负幂数,所以我们得分类讨论。

分类讨论——四种情况:

分析:

1.情况1和情况2都不需要对x进行操作直接累乘就行了

2.情况3和情况4则首先需要判断n是否为负数如果是负数那么我们就先对x取倒数然后再进行累乘。

3.其次这样的话就不能直接把n赋给x了

五、实现

错误代码:

第一次错误——应该把num赋给i而不是原始的n:

double myPow(double x, int n){
	int i,num=n;
	double factor,answer=1;
	factor=x;
	if(num<0){
		num=-num;
		factor=1/x;
	}
	for(i=1;i<=n;i++){
		answer=answer*factor;
	}
	return answer;
}

n 是负数时,你已经将 num 转换为了正数,并且相应地调整了 factor。但是在循环中,你使用的是原始的 n,而不是调整后的 num。这会导致在 n 为负数时循环不执行。 

第二次错误——超时了+溢出:

double myPow(double x, int n){
	int i,num=n;
	double factor,answer=1;
	factor=x;
	if(num<0){
		num=-num;
		factor=1/x;
	}
	for(i=1;i<=num;i++){
		answer=answer*factor;
	}
	return answer;
}

n 是负数时,由于 int 类型的范围是 −2,147,483,648 到 2,147,483,647,所以当 n 等于 -2,147,483,648 时,转换为正数会导致溢出。为了避免这个问题,我应该使用 long long 类型来存储 num。 

运行结果:

六、更正后我的答案 

### 题目描述:
计算 `x` 的 `n` 次幂,即求 `x^n`。

### 思考过程:
1. **基本情况:** 
    - 如果 `n` 等于 0,对于任何 `x`(除了0),`x^0` 都是 1。
    - 如果 `x` 等于 1 或 -1,并且 `n` 是负数,我们要计算的是 `1/x` 的正 `n` 次幂。

2. **负指数处理:**
    - 如果 `n` 是负数,我们可以计算 `1/x` 的正 `n` 次幂。

3. **快速幂算法:**
    - 快速幂算法的基本思想是将问题分解为更小的部分。例如,`x^8` 可以分解为 `(x^4)^2`。
    - 我们可以利用这个性质,将 `n` 进行二进制分解,从而将原问题分解为若干个子问题,并利用已解决的子问题来解决更大的问题。
    - 对于每一个二进制位,如果该位是1,我们就将当前的 `x` 乘到结果中。

### C语言实现:

#include <stdio.h>

double myPow(double x, int n) {
    // 使用 long long 避免整数溢出
    long long N = n;
    double ans = 1.0;
    
    // 处理负指数的情况
    if(N < 0) {
        x = 1 / x;
        N = -N;
    }
    
    // 快速幂算法
    while(N > 0) {
        if(N % 2 == 1) {
            ans *= x; // 如果当前位是1,乘到结果中
        }
        x *= x; // 计算下一位
        N /= 2; // 移动到下一位
    }
    return ans;
}

int main() {
    double x = 2.0;
    int n = -2;
    printf("%lf\n", myPow(x, n)); // 输出:0.25
    return 0;
}

### C++ 实现:

#include <iostream>
using namespace std;

class Solution {
public:
    double myPow(double x, long long n) {
        if(n < 0) {
            x = 1 / x;
            n = -n;
        }
        
        double ans = 1.0;
        while(n > 0) {
            if(n & 1) {
                ans *= x;
            }
            x *= x;
            n >>= 1;
        }
        return ans;
    }
};

int main() {
    Solution s;
    double x = 2.0;
    int n = -2;
    cout << s.myPow(x, n) << endl;  // 输出:0.25
    return 0;
}

### Java 实现:

public class Solution {
    public double myPow(double x, int n) {
        long N = n; // 使用 long 避免整数溢出
        if (N < 0) {
            x = 1 / x;
            N = -N;
        }

        double ans = 1.0;
        while (N > 0) {
            if ((N & 1) == 1) {
                ans *= x;
            }
            x *= x;
            N >>= 1;
        }
        return ans;
    }

    public static void main(String[] args) {
        Solution s = new Solution();
        double x = 2.0;
        int n = -2;
        System.out.println(s.myPow(x, n));  // 输出:0.25
    }
}

这两个实现基本上是相同的,主要的区别在于语法。注意在Java实现中,我们使用了`long`来避免`int`溢出的问题,因为`int`在Java中是有固定大小的(32位)。在C++实现中,我们使用了`long long`来确保足够的位数,因为`int`和`long`在C++中的大小可能会因编译器和平台而异。

 

### 分析过程:
1. **时间复杂度:**
   - 由于每次循环 `n` 都会除以 2,所以循环的次数是 `O(log n)`。
   - 因此,这个算法的时间复杂度是 `O(log n)`。

2. **空间复杂度:**
   - 这个算法只使用了几个变量来存储中间结果,因此空间复杂度是 `O(1)`。

### 结论:
这个快速幂算法是求幂问题的一种高效解决方案,它通过减少所需的乘法次数来提高效率,并具有较低的时间和空间复杂度。

Leetcode官方题解:

方法1:

​
class Solution {
public:
    double quickMul(double x, long long N) {
        if (N == 0) {
            return 1.0;
        }
        double y = quickMul(x, N / 2);
        return N % 2 == 0 ? y * y : y * y * x;
    }

    double myPow(double x, int n) {
        long long N = n;
        return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N);
    }
};


​

JAVA题解:

class Solution {
    public double myPow(double x, int n) {
        long N = n;
        return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N);
    }

    public double quickMul(double x, long N) {
        if (N == 0) {
            return 1.0;
        }
        double y = quickMul(x, N / 2);
        return N % 2 == 0 ? y * y : y * y * x;
    }
}

方法2:

C++题解:

class Solution {
public:
    double quickMul(double x, long long N) {
        double ans = 1.0;
        // 贡献的初始值为 x
        double x_contribute = x;
        // 在对 N 进行二进制拆分的同时计算答案
        while (N > 0) {
            if (N % 2 == 1) {
                // 如果 N 二进制表示的最低位为 1,那么需要计入贡献
                ans *= x_contribute;
            }
            // 将贡献不断地平方
            x_contribute *= x_contribute;
            // 舍弃 N 二进制表示的最低位,这样我们每次只要判断最低位即可
            N /= 2;
        }
        return ans;
    }

    double myPow(double x, int n) {
        long long N = n;
        return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N);
    }
};

JAVA题解:

class Solution {
    public double myPow(double x, int n) {
        long N = n;
        return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N);
    }

    public double quickMul(double x, long N) {
        double ans = 1.0;
        // 贡献的初始值为 x
        double x_contribute = x;
        // 在对 N 进行二进制拆分的同时计算答案
        while (N > 0) {
            if (N % 2 == 1) {
                // 如果 N 二进制表示的最低位为 1,那么需要计入贡献
                ans *= x_contribute;
            }
            // 将贡献不断地平方
            x_contribute *= x_contribute;
            // 舍弃 N 二进制表示的最低位,这样我们每次只要判断最低位即可
            N /= 2;
        }
        return ans;
    }
}

七、复盘对我分析思考过程的评价

大师的评价

我的代码和Leetcode题解的方法和代码的比较:

这个题解提供了两种解决方案:快速幂+递归和快速幂+迭代。

1. 快速幂 + 递归

这种方法采用分治的思想,每次将幂次减半。它用递归来实现,所以空间复杂度为O(logn)。这个方法的优势在于它的简洁性和直观性,对于理解问题很有帮助。但是,由于递归的开销,当n非常大时,可能会造成堆栈溢出。

2. 快速幂 + 迭代

这种方法将递归方法转化为迭代,消除了递归带来的堆栈溢出的风险,空间复杂度为O(1),比递归方法更加高效。它通过观察n的二进制表示中1的位置来计算x的幂,实际应用中更为常用。

对比你的方法

你的方法是直接循环n次来计算x的n次方。这种方法的时间复杂度是O(n)。当n非常大时,这会是一个很低效的算法。而且,你的方法没有处理n为负数的情况,直接循环会造成死循环。

总结

  1. 优势

    • 快速幂方法,无论是递归还是迭代,时间复杂度都是O(logn),非常高效。
    • 迭代方法的空间复杂度为O(1),对于空间敏感的场合非常适用。
  2. 劣势

    • 递归方法的空间复杂度为O(logn),在幂次非常大时可能会有堆栈溢出的风险。
    • 递归方法的理解和实现相对迭代方法更复杂一些。
  3. 改进你的方法

    • 你的方法可以通过实现快速幂来减少时间复杂度到O(logn)。
    • 处理n为负数的情况,可以通过计算x的正n次方,然后取倒数来得到结果。

八、反思总结

学到了什么:

通过这道题目,我们能学到以下几点:

### 1. **算法优化的重要性**
这道题目展示了相同问题的不同解决方案会有很大的效率差异。对于初学者来说,很容易想到暴力解法,即直接计算x的n次方,但这种方法的时间复杂度是O(n),在n很大时效率很低。而快速幂方法,无论是递归还是迭代,时间复杂度都可以优化到O(logn),大大提高了算法的效率。

### 2. **不同解法的优劣**
- **递归**:易于理解和实现,但可能有堆栈溢出的风险,且空间复杂度较高。
- **迭代**:迭代版本可以消除递归带来的堆栈溢出风险,且空间复杂度为O(1)。

学会权衡不同解法的优劣,并根据实际情况选择最合适的解法,是解决问题的关键。

### 3. **边界条件和特殊情况的处理**
这道题目要求处理n为负数的情况。处理特殊和边界情况是算法设计中很重要的一步,否则可能导致程序错误或者无法处理某些输入。

### 4. **二进制和位运算的应用**
快速幂算法利用了n的二进制表示来高效地计算x的n次方。通过观察n的二进制表示中1的位置,我们可以减少不必要的计算。这显示了二进制和位运算在算法设计中的重要应用。

### 5. **算法设计的灵活性和多样性**
这道题目通过展示递归和迭代两种不同的解法,体现了算法设计的灵活性和多样性。掌握多种解法并能灵活运用,可以帮助我们更好地解决实际问题。

### 6. **数学知识的运用**
这个问题还涉及到一些数学知识,比如指数和幂的性质。对基础数学知识的理解能帮助我们更好地理解问题和设计算法。

### 总结
综上所述,这道题目不仅能帮助我们学习和巩固快速幂算法,还能够加深我们对于递归、迭代、位运算、数学知识运用等方面的理解,让我们更加灵活和深入地去思考和解决问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1053249.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java大数 -- BigInteger类

在java语言中&#xff0c;每一种整数类型都有自己的上限和下限&#xff0c;如果要想对非常大的整数做运算&#xff0c;就需要使用BigInteger类。特别在做算法题传入一个数值型的字符串时。 1.包 import java.math.*; 2.构造方法 public BigInteger(String str){...} BigInte…

Go_原子操作和锁

原子操作和锁 本文先探究并发问题&#xff0c;再探究锁和原子操作解决问题的方式&#xff0c;最后进行对比。 并发问题 首先&#xff0c;我们看一下程序 num该程序表面看上去一步就可以运行完成&#xff0c;但是实际上&#xff0c;在计算机中是分三步运行的&#xff0c;如下…

让大脑自由

前言 作者写这本书的目的是什么&#xff1f; 教会我们如何让大脑更好地为自己工作。 1 大脑的运行机制是怎样的&#xff1f; 大脑的基本运行机制是神经元之间通过突触传递信息&#xff0c;神经元的兴奋和抑制状态决定了神经网络的运行和信息处理&#xff0c;神经网络可以通过…

[架构之路-226]:信息系统建模 - 实体关系图、数据流图、数据字典、流程图

目录 一、信息系统建模概述 二、常见建模工具 2.1 实体关系图 -- “实体》类” 》关注实体&#xff0c;对象 2.2 数据流图 -- 数据流动 -- 关注数据本身 2.3 业务-流程图 -- 活动步骤 -- 关注动作、活动 三、建模工具的比较 3.1 数据流图与业务流程图的区别 3.2 数据、…

Linux高性能服务器编程 学习笔记 第九章 IO复用

IO复用使程序能同时监听多个文件描述符&#xff0c;这可以提高程序的性能&#xff0c;通常网络程序在以下情况需要使用IO复用&#xff1a; 1.客户端进程需要同时处理多个socket。 2.客户端进程需要同时处理用户输入和网络连接。 3.TCP服务器要同时处理监听socket和连接socket…

网络-Ajax

文章目录 前言一、Ajax优点&#xff1a;缺点&#xff1a; 二、使用步骤XNLHttpRequest对象完整代码 总结 前言 本文主要记录Ajax技术的简介&#xff0c;以及用法。 一、Ajax Ajax是一组用于在Web浏览器和Web服务器之间进行异步通信的Web开发技术。 它代表着Asynchronous Java…

如果在 Mac 上的 Safari 浏览器中无法打开网站

使用网络管理员提供的信息更改代理设置。个人建议DNS解析&#xff0c;设置多个例如114.114.114.114 8.8.8.8 8.8.4.4 如果打不开网站&#xff0c;请尝试这些建议。 在 Mac 上的 Safari 浏览器 App 中&#xff0c;检查页面无法打开时出现的信息。 这可能会建议解决问题的…

第 114 场 LeetCode 双周赛题解

A 收集元素的最少操作次数 模拟: 反序遍历数组&#xff0c;用一个集合存当前遍历过的不超过 k k k 的正数 class Solution { public:int minOperations(vector<int> &nums, int k) {unordered_set<int> vis;int n nums.size();int i n - 1;for (;; i--) {if…

nodejs+vue活鲜物流监控系统elementui

第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;技术背景 5 3.2.2经济可行性 6 3.2.3操作可行性&#xff1a; 6 3.3 项目设计目标与原则 6 3.4系统流程分析 7 3.4.1操作流程 7 3.4.2添加信息流程 8 3.4.3删除信息流程 9 第4章 系统设计 11 …

蓝桥等考Python组别十级003

第一部分&#xff1a;选择题 1、Python L10 &#xff08;15分&#xff09; 已知s Pencil&#xff0c;下列说法正确的是&#xff08; &#xff09;。 s[0]对应的字符是Ps[1]对应的字符是ns[-1]对应的字符是is[3]对应的字符是e 正确答案&#xff1a;A 2、Python L10 &am…

【OpenCV-Torch-dlib-ubuntu】Vm虚拟机linux环境摄像头调用方法与dilb模型探究

前言 随着金秋时节的来临&#xff0c;国庆和中秋的双重喜庆汇聚成一片温暖的节日氛围。在这个美好的时刻&#xff0c;我们有幸共同迎来一次长达8天的假期&#xff0c;为心灵充电&#xff0c;为身体放松&#xff0c;为未来充实自己。今年的国庆不仅仅是家国团聚的时刻&#xff…

SSL/TLS介绍以及wireshark抓包TLS Handshake报文

文章目录 1.概念1.1 SSL/TLS发展历史1.2 TLS两个阶段1.3 TLS报文头 2.TLS Handshake2.1 Handshake具体过程2.1.1 单向认证和双向认证2.1.2 复用TLS协商结果Session Identifier&#xff08;会话标识符&#xff09;Session Ticket&#xff08;会话票据&#xff09; 2.2 Handshake…

实验篇——根据群体经纬度提取环境数据(数据降维)

实验篇——根据群体经纬度提取环境数据&#xff08;数据降维&#xff09; 文章目录 前言一、先导二、R语言实现2.1. 分气温、降水、光照、风速、蒸汽压划分数据集2.2. 对每个数据集降维处理2.2.1. 气温2.2.2. 降水2.2.2. 光照2.2.3. 风速2.2.4. 蒸汽压2.2.5.定义一个函数&#…

【小沐学前端】Node.js实现UDP和Protobuf 通信(protobuf.js)

文章目录 1、简介1.1 node1.2 Protobuf 2、下载和安装2.1 node2.2 Protobuf 3、node 代码示例3.1 HTTP3.2 UDP单播3.4 UDP广播 4、Protobuf 代码示例4.1 例子:awesome.proto 结语 1、简介 1.1 node Node.js 是一个开源的、跨平台的 JavaScript 运行时环境。 Node.js 是一个开源…

基于 SpringBoot+Vue 的教室人事档案管理系统

1 简介 教师人事档案管理系统利用信息的合理管理&#xff0c;动态的、高效的、安全的实现了教师的各种需求&#xff0c;改变了传统的网上查看方式&#xff0c;使教师可以足不出户的在线查看最适合自己个人档案、奖惩信息、档案变动、培训报名或者新闻资讯。 1、教师后台功能模…

闪存工作原理

前言 1、闪存类型 闪存有两种分类&#xff0c;NAND型闪存主要用于存储 2、MOS的特性 MOS管的三个引脚分别是Gate&#xff08;G&#xff09;、Source&#xff08;S&#xff09;和Drain&#xff08;D&#xff09;。Gate&#xff08;G&#xff09;引脚是晶闸管的控制引脚&…

Qt::图层框架-图片图层-序列图层-QGraphicsPixmapItem

二维矢量动画智能制作软件开发合集 链接&#xff1a;软件开发技术分享及记录合集 个人开发二维矢量动画智能制作软件界面如下&#xff1a; 目录 一、图片序列图层原理 二、图片序列图层代码实现 三、图片序列图层软件测试视频 结束语 一、图片序列图层原理 本软件的11种…

Sentinel学习(2)——sentinel的使用,引入依赖和配置 对消费者进行流控 对生产者进行熔断降级

前言 Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件&#xff0c;主要以流量为切入点&#xff0c;从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。 本篇博客介绍sentinel的使用&#x…

后端各层的部署开发

目录 一、创建数据库 二、entity层 三、mapper层 四、service层 五、controller层 一、创建数据库 CREATE TABLE user (id bigint NOT NULL AUTO_INCREMENT COMMENT id,name varchar(10) DEFAULT NULL COMMENT 姓名,sex varchar(5) DEFAULT NULL COMMENT 性别,phone varcha…

NLP 03(LSTM)

一、LSTM LSTM (Long Short-Term Memory) 也称长短时记忆结构,它是传统RNN的变体,与经典RNN相比&#xff1a; 能够有效捕捉长序列之间的语义关联缓解梯度消失或爆炸现象 LSTM的结构更复杂,它的核心结构可以分为四个部分去解析: 遗忘门、输入门、细胞状态、输出门 LSTM内部结构…