Leetcode 191.位1的个数

 

编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数(也被称为汉明重量)。

提示:

  • 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。
  • 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在 示例 3 中,输入表示有符号整数 -3

示例 1:

输入:n = 00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。

示例 2:

输入:n = 00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。

示例 3:

输入:n = 11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。

提示:

  • 输入必须是长度为 32 的 二进制串 。

进阶

  • 如果多次调用这个函数,你将如何优化你的算法?

我的答案:

一、信息

1.输入是一个二进制无符号整数

2.返回'1'的个数

二、分析

条件1告诉我输入的数据类型是无符号整型

条件2告诉我此次编程的目标

三、步骤

遇到问题

1.如何计算位数? 

四、实现 

我的答案:

毫无思路

这是一个常见的面试问题。让我们首先为这个问题创建一个C语言的解决方案,然后是一个C++的解决方案。

#include <stdint.h> // for uint32_tint hammingWeight(uint32_t n) {int count = 0;while (n) {count += n & 1;n >>= 1;}return count;
}

C++:

#include <cstdint> // for uint32_tint hammingWeight(uint32_t n) {int count = 0;while (n) {count += n & 1;n >>= 1;}return count;
}

进阶:优化算法

如果要多次调用这个函数,我们可以使用Brian Kernighan的算法,它可以更快地计算二进制中1的个数,它的工作原理是每次迭代都去掉最右边的1,直到所有的1都被去掉。

C语言(进阶)

#include <stdint.h> // for uint32_tint hammingWeight(uint32_t n) {int count = 0;while (n) {n &= (n - 1);count++;}return count;
}

C++(进阶)

#include <cstdint> // for uint32_tint hammingWeight(uint32_t n) {int count = 0;while (n) {n &= (n - 1);count++;}return count;
}

Brian Kernighan的算法的效率是O(k),其中k是二进制数中1的个数,因此对于具有少量1的数字,它的效率非常高。

Leetcode答案

方法一:循环检查二进制位
思路及解法

我们可以直接循环检查给定整数 nnn 的二进制位的每一位是否为 111。

具体代码中,当检查第 iii 位时,我们可以让 nnn 与 2i2^i2 
i
  进行与运算,当且仅当 nnn 的第 iii 位为 111 时,运算结果不为 000。

代码
C++

class Solution {
public:int hammingWeight(uint32_t n) {int ret = 0;for (int i = 0; i < 32; i++) {if (n & (1 << i)) {ret++;}}return ret;}
};


复杂度分析

时间复杂度:O(k)O(k)O(k),其中 kkk 是 int\texttt{int}int 型的二进制位数,k=32k=32k=32。我们需要检查 nnn 的二进制位的每一位,一共需要检查 323232 位。

空间复杂度:O(1)O(1)O(1),我们只需要常数的空间保存若干变量。

方法二:位运算优化
思路及解法

观察这个运算:n & (n−1)n~\&~(n - 1)n & (n−1),其运算结果恰为把 nnn 的二进制位中的最低位的 111 变为 000 之后的结果。

如:6 & (6−1)=4,6=(110)2,4=(100)26~\&~(6-1) = 4, 6 = (110)_2, 4 = (100)_26 & (6−1)=4,6=(110) 
2

 ,4=(100) 
2

 ,运算结果 444 即为把 666 的二进制位中的最低位的 111 变为 000 之后的结果。

这样我们可以利用这个位运算的性质加速我们的检查过程,在实际代码中,我们不断让当前的 nnn 与 n−1n - 1n−1 做与运算,直到 nnn 变为 000 即可。因为每次运算会使得 nnn 的最低位的 111 被翻转,因此运算次数就等于 nnn 的二进制位中 111 的个数。

代码

C++
Java
Python3
Golang
JavaScript
C

class Solution {
public:int hammingWeight(uint32_t n) {int ret = 0;while (n) {n &= n - 1;ret++;}return ret;}
};


复杂度分析

时间复杂度:O(log⁡n)O(\log n)O(logn)。循环次数等于 nnn 的二进制位中 111 的个数,最坏情况下 nnn 的二进制位全部为 111。我们需要循环 log⁡n\log nlogn 次。

空间复杂度:O(1)O(1)O(1),我们只需要常数的空间保存若干变量。
链接:https://leetcode.cn/problems/number-of-1-bits/solutions/672082/wei-1de-ge-shu-by-leetcode-solution-jnwf/
来源:力扣(LeetCode)
英雄师傅答案:

int hammingWeight(uint32_t n){int c=0;while(n){if(n&1){++c;}n>>=1;}return c;
}

几种方法的比较:

我的方法

1. **Brian Kernighan算法:** 这实际上与你给出的第二种方法相同,即使用`n & (n-1)`技巧。它直接移除了数字中最右侧的'1'。

2. **直接计数:** 这是一个直观的方法。对数字的每一位进行循环,并用`n & 1`检查最低位是否为'1'。之后,右移数字。

### 对比与分析

**1. 循环检查二进制位 vs 直接计数**
- **思路相似性:** 这两种方法都是基于检查每一位来计算'1'的数量。
- **优势:** 这两种方法都是非常直观的。对于初学者或者希望代码具有更高可读性的情境,它们都很适用。
- **劣势:** 它们的性能可能不如位运算优化方法,特别是当原始数字的二进制表示中有较少的'1'时。

**2. 位运算优化 vs Brian Kernighan算法**
- **思路相似性:** 它们实际上是同一种方法。都使用了`n & (n-1)`的技巧来移除数字中的一个'1'。
- **优势:** 它们都比直接计数方法快,尤其是在数字中'1'较少时。
- **劣势:** 对于不熟悉这种特定位运算的人来说,可能不够直观。

### 总结

- 我的"直接计数"方法和你给的"循环检查二进制位"方法非常相似。它们都是基于检查每一位的简单方法。然而,由于涉及到的位移操作,实现的细节可能会有所不同。
  
- 我的"Brian Kernighan算法"和你给的"位运算优化"方法实际上是同一种方法。这种方法利用了`n & (n-1)`来高效地计算'1'的数量,它比基于逐位检查的方法更快。

无论选择哪种方法,最重要的是理解其背后的逻辑和原理,这样在遇到不同的问题时,你可以灵活地应用和调整这些方法。

总结:

一、发现的不足。

1.运算符>>知识点尤其是移位运算不熟悉

2.

二、学到什么?

从这道题目中,我们可以学到以下几点:

1. **二进制基础**:题目加深了我们对二进制数的理解,特别是如何操作和解读32位无符号整数的二进制形式。

2. **位操作**:题目展示了如何使用位操作符,特别是`&` (位与) 和 `<<` (左移)。位操作是计算机科学中的一个重要概念,特别是在低级编程、嵌入式系统和性能关键应用中。

3. **算法优化**:通过比较两种方法,我们看到了如何从一个直接的算法优化到一个更高效的算法。方法一直接检查每一位,而方法二使用了一个巧妙的技巧,即`n & (n - 1)`,来迅速定位并清除最右侧的`1`。这显示了算法和数据结构知识的重要性,特别是如何使用基础的位操作来优化算法。

4. **代码简洁性和效率**:两种方法都提供了解决同一问题的有效方法,但它们之间的效率有所不同。这强调了在解决问题时不仅要考虑解决方案的正确性,还要考虑其效率。

5. **问题分析与解决策略**:面对一个问题时,首先需要理解其背后的概念和要求,然后尝试提出不同的策略或方法。对于同一个问题,可能存在多种有效的解决策略,但它们在实际应用中的效率可能会有所不同。

6. **细节注意**:在处理位操作时,特别要注意边界条件和位数。例如,对于32位的整数,当我们移动超过32位时,需要注意可能出现的行为。

综上所述,这道题目为我们提供了一个很好的机会,来学习和实践位操作、算法优化和问题解决策略。

 

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

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

相关文章

2023/08/27

一、图片引入 项目中往往不使用相对路径引入文件&#xff0c;一般都使用实现绝对路径引入文件。 方式一&#xff1a;【适用vue2&#xff0c;不适用vue3】 <img :src"require(/assets/images/home/bottom_can.png)" alt"">方式二&#xff1a;【适用…

mac m1 docker 安装kafka和zookeeper

获取本地ip地址 ifconfig en0 192.168.0.105. 下面的ip都会使用到 1、拉取镜像 docker pull wurstmeister/zookeeper docker pull wurstmeister/kafka 2、启动容器 启动 zookeeper docker run -d --name zookeeper -p 2181:2181 映射 3、 启动 kafka 注意&#xff…

计网-All

路由器的功能与路由表的查看_路由器路由表_傻傻小猪哈哈的博客-CSDN博客路由基础-直连路由、静态路由与动态路由的概念_MikeVane-bb的博客-CSDN博客路由器的功能与路由表的查看_路由器路由表_傻傻小猪哈哈的博客-CSDN博客 直连路由就是路由器直接连了一个网段&#xff0c;他就…

一个短视频去水印小程序,附源码

闲来无事&#xff0c;开发了一个短视频去水印小程序&#xff0c;目前支持抖音、快手&#xff0c;后续再加上别的平台。 因为平台原因&#xff0c;就不放二维码了&#xff0c;你可以直接微信搜索【万能老助手】这里贴一张效果图。 页面非常简单&#xff0c;这里就不过多介绍了&…

Git企业开发控制理论和实操-从入门到深入(五)|标签管理

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量博客汇总 然后就是博主最近最花时间的一个专栏…

正则表达式总结

作为软件工程师&#xff0c;工作中经常都需要使用正则表达式进行搜索&#xff0c;替换&#xff0c;验证数据&#xff08;手机号、邮箱、账号&#xff09;等。 但没有系统的学习总结过。现在就来学习总结一下。 认识元字符 元字符就是一些特殊符号&#xff0c;代表一些特殊意思…

初始Netty

文章目录 目录 文章目录 前言 一、netty 总结 前言 认识netty 一、netty Netty是一个基于Java的高性能网络应用框架&#xff0c;用于快速开发可扩展的网络服务器和客户端。它提供了易于使用的抽象API&#xff0c;使开发人员能够轻松地构建各种网络应用程序&#xff0c;包括…

JavaScript基础语法

一、JavaScript编写方式 位置一&#xff1a;HTML代码行内&#xff08;不推荐&#xff09; <!-- 方式一&#xff1a;行内编写 --> <a href"javascript:alert(hello world)">hello world</a> <!-- 方式二&#xff1a;行内编写&#xff0c;通过监…

学信息系统项目管理师第4版系列03_文件与标准

审核未通过&#xff0c;删除文件部分&#xff0c;仅保留标准化相关内容&#xff0c;重发 12. 标准化 12.1. 采用国际标准和国外先进标准的程度分为等同采用、修改采用和等效采用 3 种 12.1.1. 【高21上选20】 12.1.2. 采用指与国际标准在技术内容和文本结构上相同,或者与国…

期权是什么?期权的优缺点是什么?

期权是一种合约&#xff0c;有看涨期权和看跌期权两种类型&#xff0c;也就是做多和做空两个方向&#xff0c;走势标的物对应大盘指数&#xff0c;这也是期权与其他金融工具的主要区别之一&#xff0c;可以用于套利&#xff0c;对冲股票和激进下跌的风险&#xff0c;下文介绍期…

DML语句的用法(MySQL)

文章目录 前言一、DML介绍二、DML语句操作1、给指定字段添加数据2、给全部字段添加数据3、批量添加数据4、修改数据5、删除数据 总结 前言 本文主要介绍SQL语句中DML语句的用法。 在实验开始之前我们先创建一下所要使用表&#xff0c;如下图所示&#xff1a; 一、DML介绍 DM…

Modbus转Profinet网关连接三菱变频器博图快速配置

本案例将分享如何使用兴达易控的modbus转profinet网关&#xff08;XD-MDPN100&#xff09;来连接西门子1200系列plc&#xff0c;并实现三菱变频器的485通讯兼容转modbusTCP通信。通过在博图中进行配置&#xff0c;我们可以实现设备之间的连接和通信。 首先&#xff0c;我们需要…

Vue自定义指令- v-loading封装

Vue自定义指令- v-loading封装 文章目录 Vue自定义指令- v-loading封装01-自定义指令自定义指令的两种注册语法&#xff1a; 02自定义指令的值03-自定义指令- v-loading指令封装 01-自定义指令 什么是自定义指令&#xff1f; 自定义指令&#xff1a;自己定义的指令&#xff0c…

webassembly003 GGML Tensor Library part-1

GGML ggml的函数 可以看到官方示例项目仅依赖于#include "ggml/ggml.h"&#xff0c; #include "common.h"&#xff0c;可以阅读ggml.h获取ggml的使用帮助 函数解释注释ggml_tensor多维张量按行主顺序存储。ggml_tensor结构包含每个维度中元素数&#xf…

httpd协议与apache

1.http 相关概念 HTTP是处于应用层的协议&#xff0c;使用TCP传输层协议进行可靠的传送。因此&#xff0c;需要特别提醒的是&#xff0c;万维网是基于因特网的一种广泛因特网应用系统&#xff0c;且万维网采用的是HTTP&#xff08;80/TCP&#xff09;和 HTTPS&#xff08;443/…

OpenCV基础知识(8)— 图形检测

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。图形检测是计算机视觉的一项重要功能。通过图形检测可以分析图像中可能存在的形状&#xff0c;然后对这些形状进行描绘&#xff0c;例如搜索并绘制图像的边缘&#xff0c;定位图像的位置&#xff0c;判断图像中有没有直线、…

前端开发工具: VSCode

VSCode 安装使用教程&#xff08;图文版&#xff09; | arry老师的博客-艾编程 1. 下载 在官方网站&#xff1a;https://code.visualstudio.com/ 下载最新版本的 VSCode 即可 2. VSCode 常见插件安装 所有插件安装后,需要重启一下才生效 2.1 简体中文语言包 2.2 编辑器主…

webscoket在vue中的使用

项目场景&#xff1a; 提示&#xff1a;项目相关背景&#xff1a; 什么是webscoket&#xff1f;: WebSocket是一种计算机通信协议&#xff0c;通过单个TCP连接提供全双工通信信道。实现了web客户端和服务器之间的实时通信&#xff0c;与传统的HTTP连接相比&#xff0c;允许以…

Docker harbor私有仓库部署与管理

一、搭建本地私有仓库二、Harbor私有仓库部署与管理1、Harbor概述2、Harbor的特性3、Harbor的核心组件3.1 Proxy3.2 Registry3.3 Core services3.3.1 UI&#xff08;harbor-ui&#xff09;3.3.2 WebHook3.3.3 Token 服务 3.4 Database&#xff08;harbor-db&#xff09;3.5 Log…

package.json

问题原因&#xff1a; 查了下原因&#xff0c;主要是 nodeJs V17 版本发布了 OpenSSL3.0 对算法和秘钥大小增加了更为严格的限制&#xff0c;nodeJs v17 之前版本没影响&#xff0c;但 V17 和之后版本会出现这个错误。 在 package.json 的 scripts 中新增&#xff1a; SET N…