Leetcode 231.2的幂

给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true ;否则,返回 false 。

如果存在一个整数 x 使得 n == 2x ,则认为 n 是 2 的幂次方。

示例 1:

输入:n = 1
输出:true
解释:20 = 1

示例 2:

输入:n = 16
输出:true
解释:24 = 16

示例 3:

输入:n = 3
输出:false

示例 4:

输入:n = 4
输出:true

示例 5:

输入:n = 5
输出:false

提示:

  • -231 <= n <= 231 - 1

进阶:你能够不使用循环/递归解决此问题吗?

一、信息

1.给我一个整数n

2.判断该整数是否是2的幂次方

3.返回torf

二、分析

条件1.告诉我函数参数类型 int

条件2.告诉我本题的目的

条件3.告诉我函数返回值类型

三、步骤

第一步 接收一个int型

第二步 判断该数是否为2的幂次方

第三步 输出

四、问题出现

问题1.就是该如何判断该整数是否时2的幂次方呢?
 

我的答案:
对于这个问题我大致有两条思路

第一条思路 就是对n取log2看是否为整数如果为整数说明就是2的幂次方返回True反之返回false.这样新的问题就出现了在C语言或者C++或者JAVA中该如何使用对数函数?

第二条思路 就是对n除2或乘以2最后结果得到1返回true不过要提前判断这个数在1的左侧还是右侧。这条思路比较复杂而且很多分支,虽然理论上可行但是太复杂了。

问题2.该如何使用对数函数呢?

五、算法实现

思路一:

C语言:

bool isPowerOfTwo(int n) {if (n <= 0) {return false;}double result = log2(n);// 判断结果是否为整数return result == (int)result;
}

运行结果: 

思路二: 

bool isPowerOfTwo(int n) {if (n <= 0) {return false;}// 如果n大于1,不断除以2while (n > 1) {if (n % 2 != 0) {  // 如果不能被2整除return false;}n /= 2;}// 如果n小于1,不断乘以2while (n < 1) {n *= 2;if (n == 1) {return true;}}return true;
}

六、更正后我的答案

我的第二次分析

**一、信息**
- 需要判断一个整数是否是2的幂次方。
- 2的幂次方在二进制表示中只有一个1。

**二、分析**
1. 2的幂次方的特性是,在其二进制表示中,仅有一个位置为1。
2. 对于任何2的幂次方整数n,其n-1与n在二进制表示上是完全不同的。具体来说,n会在某一位上为1,而在这之前的所有位上都为0;而n-1则在相同的位置为0,并且在这之前的所有位上都为1。
3. 因此,对于2的幂次方的整数n和n-1,进行二进制与操作的结果必定为0。

**三、实现步骤**
1. 如果输入整数n小于或等于0,直接返回`false`。
2. 计算`n & (n - 1)`。如果结果为0,返回`true`,否则返回`false`。

**四、问题出现**
1. **特殊情况的处理:** 刚开始可能会忽视非正数的情况,如0或负数。需要在判断开始时直接将其排除。
2. **确保方法的有效性:** 在没有深入了解二进制表示的情况下,可能会对为什么n和n-1的与操作是0产生疑惑。这需要深入理解和观察二进制的特性。
3. **效率问题:** 尽管这个方法是高效的,但在开始时,可能会考虑使用其他方法,如循环检查,这在效率上是不可取的。

C语言实现:

#include <stdbool.h>bool isPowerOfTwo(int n) {if (n <= 0) {return false;}return (n & (n - 1)) == 0;
}#include <stdio.h>
int main() {printf("%d\n", isPowerOfTwo(1));   // trueprintf("%d\n", isPowerOfTwo(16));  // trueprintf("%d\n", isPowerOfTwo(3));   // falseprintf("%d\n", isPowerOfTwo(4));   // trueprintf("%d\n", isPowerOfTwo(5));   // falsereturn 0;
}

C++:

#include <iostream>
using namespace std;bool isPowerOfTwo(int n) {if (n <= 0) {return false;}return (n & (n - 1)) == 0;
}int main() {cout << isPowerOfTwo(1) << endl;   // true (输出 1)cout << isPowerOfTwo(16) << endl;  // true (输出 1)cout << isPowerOfTwo(3) << endl;   // false (输出 0)cout << isPowerOfTwo(4) << endl;   // true (输出 1)cout << isPowerOfTwo(5) << endl;   // false (输出 0)return 0;
}

JAVA:

public class PowerOfTwo {public static boolean isPowerOfTwo(int n) {if (n <= 0) {return false;}return (n & (n - 1)) == 0;}public static void main(String[] args) {System.out.println(isPowerOfTwo(1));   // trueSystem.out.println(isPowerOfTwo(16));  // trueSystem.out.println(isPowerOfTwo(3));   // falseSystem.out.println(isPowerOfTwo(4));   // trueSystem.out.println(isPowerOfTwo(5));   // false}
}

英雄师傅题解:

bool isPowerOfTwo(int n){int i;unsigned int k=1;if(n<=0){return false;}if(n==1){return true;}for(i=1;i<=31;i++){k*=2;if(k==n){return true;}}return false;
}

他的思路:

 //定义一个无符号整型
//如果n<=0,则必然不是2的幂
//1必然时2的0次幂
//枚举所有2的幂2 4 8 16 .....
//一旦找到一个和相等返回true
//最后,没有找到的话,返回false 

对该方法的评价: 

英雄师傅的思路基本上是一个暴力解法,但由于我们知道整数范围是`-2^31 <= n <= 2^31 - 1`,所以这种方法在这个范围内是有效且可行的。下面我对这种方法进行分析:

**思路分析**:
1. 首先,检查n是否小于等于0,因为2的幂不可能是0或负数。
2. 检查n是否为1,因为1是2的0次方。
3. 利用循环枚举所有可能的2的幂,从2的1次方开始,一直到2的31次方。
4. 在每一次迭代中,将k(初始化为1)乘以2,然后检查k是否与n相等。
5. 如果在某一次迭代中,k与n相等,则直接返回true。
6. 如果循环结束都没有找到相等的k,则返回false。

这种方法的好处是非常直观和简单。但缺点是需要循环31次,尽管这对于现代计算机来说并不是什么大问题。

与其他方法相比,如二进制方法或对数方法,这种方法在效率上可能稍微低一些,但考虑到题目的限制,这种方法完全足够。

Leetcode题解

我的理解:

1. **基本原则**:
   如果一个数`n`是2的幂,则它的二进制表示中仅有一个1。例如,2的幂有:1(`001`),2(`010`),4(`100`),8(`1000`)等。如您所见,每个数字的二进制形式中仅有一个1。

2. **第一个技巧 (`n & (n - 1)`)**:
   当执行`n & (n - 1)`时,您实际上移除了二进制数`n`的最右侧的1。原因是:`(n - 1)`会将`n`的最右侧的1变为0,并且该位之后的所有位都变为1。
   
   例如:  
   `n`     = `1000` (这是8)  
   `n-1`   = `0111` (这是7)  

   当执行`n & (n - 1)`时,得到的结果是`0000`。这表明`n`中只有一个1,因此`n`是2的幂。

   所以,如果`n`是正数且`n & (n - 1) = 0`,那么`n`就是2的幂。

3. **第二个技巧 (`n & (-n)`)**:
   负数在计算机中是使用补码表示的。`-n`的二进制表示是`n`的所有位取反后再加1。因此,`n & (-n)`的结果实际上会返回`n`的最低位的1。

   例如:
   `n`      = `1010` (这是10,它不是2的幂,但我们只是为了演示)  
   `-n`     = `0110` (按位取反再加1)

   执行`n & (-n)`得到`0010`。这表示`n`的最低位的1是在第二位上。但对于确定2的幂,我们关心的是这个操作的结果是否等于`n`,因为只有这样`n`才只有一个1。

   因此,如果`n`是正数且`n & (-n) = n`,那么`n`就是2的幂。

基于上述的理论,只需要使用第一个技巧或第二个技巧中的任何一个即可确定一个数字是否是2的幂。这是位操作的美妙之处,它提供了一种非常快速和高效的方法来解决这个问题。

七、复盘对我第一次分析的评价

大师对我第一次分析的评价

你的分析过程条理清晰。针对你提出的问题和思路,我可以为你补充一下:

**问题1:** 如何判断整数是否是2的幂次方?

你的答案中提到的两种思路都是可行的。对于第一条思路,使用对数函数确实可以实现,但可能会因为计算机浮点数运算的误差而导致判断不准确。第二条思路确实比较复杂。

实际上,还有一种更简单的方法,那就是利用二进制特性,如前文所述,2的幂次方在二进制中只有一个1。

**问题2:** 如何在C/C++/JAVA中使用对数函数?

- **C语言**: 你可以使用`math.h`库中的`log2`函数。首先,你需要包含`math.h`,然后链接`m`库。
 

  #include <math.h>double result = log2(n);

- **C++**: 同样可以使用`cmath`库中的`log2`函数。

 #include <cmath>double result = std::log2(n);

- **Java**: 可以使用`Math`类中的`log`函数,但是注意,Java中没有直接的log2函数,你需要自己计算。

  double result = Math.log(n) / Math.log(2);

不过请注意,使用对数函数需要考虑浮点数的误差,因此在比较结果时,可能需要考虑一个小的误差范围,而不是直接比较是否为整数。

总结点评:

**优点**:

1. **结构化**:您按照“信息、分析、步骤、问题出现”的结构进行了思考,这有助于对问题进行系统化分析。
2. **明确目标**:您明确了要解决的问题和函数需要实现的功能。
3. **多方位思考**:您不仅思考了如何解决问题,还考虑了可能遇到的问题和限制。
4. **多个方案**:对于如何判断一个数是否为2的幂,您给出了两种不同的解决方案,这显示了您具备多角度解决问题的能力。

**不足**:

1. **考虑效率**:尽管您考虑了多个方案,但在选择方案时,考虑它们的效率和实用性是很重要的。例如,第二种方法虽然理论上可行,但其效率较低且实现较为复杂。
2. **深入了解工具**:关于如何使用对数函数的问题,了解编程语言提供的库和常用函数是很重要的。这需要您深入研究和实践所使用的编程语言。
3. **考虑特殊情况**:在处理数学或算法问题时,考虑特殊情况或边界情况是很重要的。例如,对于这个问题,当`n`为负数或零时,应立即返回`false`。
4. **利用已有知识**:位操作是计算机科学中的一个核心概念,对于这类问题,考虑使用位操作可以得到更简洁、高效的解答。

总体来说,您的思考和分析过程是结构化且有深度的,但还可以在选择和实施方案时加强对效率和实用性的考虑,同时增强对编程语言和基础算法知识的了解。

八、反思总结

从这道题目关于判断一个数是否是2的幂次方,我们可以学到以下几点:

1. **位运算的应用**:位运算是一种高效的操作,它可以在某些情况下为我们提供简洁和高效的解决方案。特别是当问题涉及到数字的二进制表示时,位运算往往能够提供简单且高效的方法。

2. **深入理解数字的二进制表示**:数字在计算机内部是以二进制形式存储的。了解二进制的特点和规律,如一个数是2的幂时它的二进制表示只有一个1,可以帮助我们更好地解决与数字相关的问题。

3. **多种解决方案**:一个问题往往有多种解决方案,每种方案都有其优点和缺点。例如,可以使用对数函数,也可以使用位运算。能够掌握并比较多种方案,选择最合适的方案是一个重要的技能。

4. **问题分解**:当面对一个看似复杂的问题时,我们可以尝试将其分解为更小、更容易解决的子问题。例如,判断一个数是否是2的幂可以转化为判断其二进制表示中是否只有一个1。

5. **考虑边界情况**:在解决问题时,总是要考虑到所有可能的输入,包括边界情况。例如,当n为负数或0时,应该直接返回false。

6. **学会查找并利用工具**:面对某些特定的操作,如求对数,如果你不知道如何实现,你可以学会查找并使用相关的库和函数。这需要熟悉编程语言和其提供的工具。

7. **思维的扩展**:此题也展示了将一个数学问题转换为计算机科学问题的过程,这可以锻炼和增强我们的抽象思维和问题转化能力。

总的来说,这道题目不仅帮助我们掌握了一些实用的技巧和方法,而且也锻炼了我们的思维和分析能力。

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

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

相关文章

【重拾C语言】二、顺序程序设计(基本符号、数据、语句、表达式、顺序控制结构、数据类型、输入/输出操作)

目录 前言 二、顺序程序设计 2.1 求绿化带面积——简单程序 2.2基本符号&#xff1a; 2.2.1 字符集 可视字符 不可视字符 2.2.2 C特定符 关键字 分隔符 运算符 2.2.3 标识符 2.2.4 间隔符 2.2.5 注释 2.3 数据 2.3.1 字面常量&#xff08;Literal Constants&am…

【RP-RV1126】烧录固件使用记录

文章目录 烧录完整固件进入MASKROM模式固件烧录升级中&#xff1a;升级完成&#xff1a; 烧录部分进入Loader模式选择文件切换loader模式 烧录完整固件 完整固件就是update.img包含了所有的部件&#xff0c;烧录后可以直接运行。 全局编译&#xff1a;./build.sh all生成固件…

SDL2绘制ffmpeg解析的mp4文件

文章目录 1.FFMPEG利用命令行将mp4转yuv4202.ffmpeg将mp4解析为yuv数据2.1 核心api: 3.SDL2进行yuv绘制到屏幕3.1 核心api 4.完整代码5.效果展示 本项目采用生产者消费者模型&#xff0c;生产者线程&#xff1a;使用ffmpeg将mp4格式数据解析为yuv的帧&#xff0c;消费者线程&am…

单层神经网络

神经网络 人工神经网络&#xff08;Artificial Neural Network&#xff0c;ANN&#xff09;&#xff0c;简称神经网络&#xff08;Neural Network&#xff0c;NN&#xff09;&#xff0c;是一种模仿生物神经网络的结构和功能的数学模型或计算模型。1943年&#xff0c;McCulloc…

计数排序(Counting Sort)详解

计数排序&#xff08;Counting Sort&#xff09;是一种非比较排序算法&#xff0c;其核心思想是通过计数每个元素的出现次数来进行排序&#xff0c;适用于整数或有限范围内的非负整数排序。这个算法的特点是速度快且稳定&#xff0c;适用于某些特定场景。在本文中&#xff0c;我…

多层神经网络和激活函数

多层神经网络的结构 多层神经网络就是由单层神经网络进行叠加之后得到的&#xff0c;所以就形成了层的概念&#xff0c;常见的多层神经网络有如下结构&#xff1a; 1&#xff09;输入层&#xff08;Input layer&#xff09;&#xff0c;众多神经元&#xff08;Neuron&#xff…

电商项目常用的五个设计模式场景及分析实现

电商设计模式总结 1 单点登录模 1 业务介绍 单点登录&#xff08;Single Sign-On, SSO&#xff09;模块允许用户在多个相关应用系统之间进行无缝的身份验证。用户只需登录一次&#xff0c;然后可以访问所有连接的应用程序而无需重新登录。在电商应用中&#xff0c;这对于提供…

互联网Java工程师面试题·Dubbo篇·第一弹

目录 1、为什么要用 Dubbo&#xff1f; 2、Dubbo 的整体架构设计有哪些分层? 3、默认使用的是什么通信框架&#xff0c;还有别的选择吗? 4、服务调用是阻塞的吗&#xff1f; 5、一般使用什么注册中心&#xff1f;还有别的选择吗&#xff1f; 6、默认使用什么序列化框架&…

堆排序——向下调整

之前我们要想实现堆排序&#xff0c;是运用建堆代码来实现的&#xff1a; 向上调整建堆——向下调整排序 那么去我们可不可以只适用一种调整方法&#xff08;向下调整&#xff09;就能实现这样的功能呢&#xff1f; 向要只使用向下调整就实现堆排序 首先就是把数组里的值使用…

uboot启动流程-uboot内存分配工作总结

一. uboot 启动流程 _main 函数中会调用 board_init_f 函数&#xff0c;本文继续简单分析一下 board_init_f 函数。 本文继续具体分析 board_init_f 函数。 本文继上一篇文章的学习&#xff0c;地址如下&#xff1a; uboot启动流程-uboot内存分配_凌肖战的博客-CSDN博客 二…

全志ARM926 Melis2.0系统的开发指引④

全志ARM926 Melis2.0系统的开发指引④ 编写目的7. 固件打包脚本7.1.概要描述7.2.术语定义7.2.1. makefile7.2.2. image.bat 7.3.工具介绍7.4.打包步骤7.4.1. makefile 部分7.4.2. image.bat 部分 7.5.问题与解决方案7.5.1. 固件由那些文件构成7.5.2. melis100.fex 文件包含什么…

OpenCV 15(SIFT/SURF算法)

一、SIFT Harris和Shi-Tomasi角点检测算法&#xff0c;这两种算法具有旋转不变性&#xff0c;但不具有尺度不变性&#xff0c;以下图为例&#xff0c;在左侧小图中可以检测到角点&#xff0c;但是图像被放大后&#xff0c;在使用同样的窗口&#xff0c;就检测不到角点了。 尺度…

力扣 -- 96. 不同的二叉搜索树

解题步骤&#xff1a; 参考代码&#xff1a; class Solution { public:int numTrees(int n) {vector<int> dp(n1);//初始化dp[0]1;//填表for(int i1;i<n;i){for(int j1;j<i;j){//状态转移方程dp[i](dp[j-1]*dp[i-j]);}}//返回值return dp[n];} }; 你学会了吗&…

【C语言】循环结构程序设计 (详细讲解)

前言&#xff1a;前面介绍了程序中常常用到的顺序结构和选择结构&#xff0c;但是只有这两种结构是不够的&#xff0c;还有用到循环结构(或者称为重复结构)。因为在日常生活中或是在程序所处理的问题中常常遇到需要重复处理的问题。 【卫卫卫的代码仓库】 【选择结构】 【专栏链…

GEO生信数据挖掘(三)芯片探针ID与基因名映射处理

检索到目标数据集后&#xff0c;开始数据挖掘&#xff0c;本文以阿尔兹海默症数据集GSE1297为例 目录 处理一个探针对应多个基因 1.删除该行 2.保留分割符号前面的第一个基因 处理多个探针对应一个基因 详细代码案例一删除法 详细代码案例二 多个基因名时保留第一个基因名…

vs code 离线安装 CodeLLDB 包[Acquiring CodeLLDB platform package]

1. 问题描述 最近在配置使用vscode编译c&#xff0c;一打开vscode就弹出以下信息“Acquiring CodeLLDB platform package” 2. 问题原因 vscode在安装CodeLLDB插件时&#xff0c;速度太慢&#xff0c;一直不能成功 3. 解决方案&#xff1a; 离线下载 CodeLLDB插件&#xff0c…

一文读懂UTF-8的编码规则

之前写过一篇文章“一文彻底搞懂计算机中文编码”里面只是介绍了GB2312编码知识&#xff0c;关于utf8没有涉及到&#xff0c;经过查询资料发现utf8是对unicode的一种可变长度字符编码&#xff0c;所以再记录一下。 现在国家对于信息技术中文编码字符集制定的标准是《GB 18030-…

开源python双屏图片浏览器软件

源代码 需要安装pyqt5这个库 # -*- coding: utf-8 -*-from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QPushButton, QFileDialog, QAction, QSlider, QHBoxLayout, QWidget from PyQt5.QtGui import QPixmap from PyQt5.QtCore import Qt, QS…

新手学习笔记-----⽂件操作

目录 1. 为什么使⽤⽂件&#xff1f; 2. 什么是⽂件&#xff1f; 2.1 程序⽂件 2.2 数据⽂件 2.3 ⽂件名 3. ⼆进制⽂件和⽂本⽂件&#xff1f; 4. ⽂件的打开和关闭 4.1 流和标准流 4.1.1 流 4.1.2 标准流 4.2 ⽂件指针 4.3 ⽂件的打开和关闭 5. ⽂件的顺序读写 …

YOLOv5、YOLOv8改进:RepVGG结构

1.简介 论文参考&#xff1a;最新RepVGG结构: Paper 我们所说的“VGG式”指的是&#xff1a; 没有任何分支结构。即通常所说的plain或feed-forward架构。 仅使用3x3卷积。 仅使用ReLU作为激活函数。 主要创新点为结构重参数化。在训练时&#xff0c;网络的结构是多分支进…