Leetcode 191.位1的个数

news2024/12/26 11:44:32

 

编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '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_t

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

C++:

#include <cstdint> // for uint32_t

int 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_t

int hammingWeight(uint32_t n) {
    int count = 0;
    while (n) {
        n &= (n - 1);
        count++;
    }
    return count;
}

C++(进阶)

#include <cstdint> // for uint32_t

int 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.coloradmin.cn/o/937883.html

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

相关文章

4、Spring之Bean生命周期源码解析(创建)

Spring最重要的功能就是帮助程序员创建对象(也就是IOC),而启动Spring就是为创建Bean对象做准备,所以我们先明白Spring到底是怎么去创建Bean的,也就是先弄明白Bean的生命周期。 Bean的生命周期就是指:在Spring中,一个Bean是如何生成的,如何销毁的。 Bean生命周期流程图…

帆软报表系统获取管理员权限

子曰&#xff1a;“君子食无求饱&#xff0c;居无求安&#xff0c;敏于事而慎于言&#xff0c;就有道而正焉&#xff1a;可谓好学也已。” 漏洞实战 构造payload&#xff0c;访问漏洞url后台地址&#xff1a; /ReportServer?opfr_auth&cmdah_loginui&_161983254558…

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

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

node.js安装好后测试报错解决

node.js的版本是18.X.X node.js安装好后&#xff0c;执行命令&#xff1a; npm install express -g 报错&#xff01;&#xff01;&#xff01; 解决办法&#xff1a; 看报错是由于权限不够&#xff0c; 所以打开cmd时&#xff0c;以管理员的方式打开 然后再执行命令就OK了…

LLMs:LangChain-Chatchat(一款可实现本地知识库问答应用)的简介、安装、使用方法之详细攻略

LLMs&#xff1a;LangChain-Chatchat(一款可实现本地知识库问答应用)的简介、安装、使用方法之详细攻略 目录 LangChain-Chatchat的简介 1、原理图解 2、文档处理实现流程 1、模型支持 (1)、LLM 模型支持 (2)、Embedding 模型支持 LangChain-Chatchat的安装 1、镜像部署…

nacos总结1

5.Nacos注册中心 国内公司一般都推崇阿里巴巴的技术&#xff0c;比如注册中心&#xff0c;SpringCloudAlibaba也推出了一个名为Nacos的注册中心。 5.1.认识和安装Nacos Nacos是阿里巴巴的产品&#xff0c;现在是SpringCloud中的一个组件。相比Eureka功能更加丰富&#xff0c…

记一种不错的缓存设计思路

之前与同事讨论接口性能问题时听他介绍了一种缓存设计思路&#xff0c;觉得不错&#xff0c;做个记录供以后参考。 场景 假设有个以下格式的接口&#xff1a; GET /api?keys{key1,key2,key3,...}&types{1,2,3,...} 其中 keys 是业务主键列表&#xff0c;types 是想要取到的…

原生微信小程序 动态(横向,纵向)公告(广告)栏

先看一下动态效果 Y轴滚动公告的原理是swiper组件在页面中的Y轴滚动&#xff0c;属性vertical&#xff0c;其余属性也设置一下autoplay circular interval"3000" X轴滚动的原理是&#xff0c;利用动画效果&#xff0c;将内容从右往左过渡过去 wxml&#xff1a; &l…

80%的攻击仅使用三个恶意软件加载程序

根据 IT 安全公司 ReliaQuest 的威胁研究人员的说法&#xff0c;QakBot、SocGholish 和 Raspberry Robin 这三种恶意软件加载程序在 80% 的事件中造成了严重破坏。 恶意软件加载程序用作传递和执行其他形式恶意软件的工具&#xff0c;例如勒索软件、病毒、木马或蠕虫。它们是攻…

Android SDK 上手指南||第八章 应用程序资源

第八章 应用程序资源 在系列教程中的最新一篇里&#xff0c;我们将研究大家最可能在第一个开发项目中涉及到的资源类型。项目资源当中包含布局、图片以及数据值&#xff0c;这些都是应用需要使用的元素。当我们创建一个新项目时&#xff0c;项目目录下会自动生成多个用于容纳通…

[管理与领导-53]:IT基层管理者 - 8项核心技能 - 8 - 持续改进

前言&#xff1a; 管理者存在的价值就是制定目标&#xff0c;即目标管理、通过团队&#xff08;他人&#xff09;拿到结果。 要想通过他人拿到结果&#xff1a; &#xff08;1&#xff09;目标&#xff1a;制定符合SMART原则的符合业务需求的目标&#xff0c;团队跳一跳就可以…

飞腾uboot命令简单介绍

飞腾uboot和开源uboot并无大差异,故飞腾uboot固件命令可以直接从网上搜索开源uboot相关命令。 这里为了便于大家调试,将一些可能用到的命令说明一下。 在 Uboot 命令行下,输入 help 将打印所有的可用命令,复杂命令操作,通过命令 help 的方式获取具体说明。 1.help命令 …

GDB用法(一)

预备 测试代码 main.cpp #include <iostream> #include <vector> #include "student.h"using namespace std;int add(int a, int b) {return a b; }int main() {vector<int> v {1, 3};Student* s1 new Student("zz", 20);Student* …

如何评估一个需求开发通常需要多长时间?

业务人员和产品管理者有时候会想要知道在他们即将进行的项目中&#xff0c;“处理需求”的环节会花费多长时间。但这个问题并没有固定的答案&#xff0c;因为这会取决于很多因素。 有许多已经公开的行业平均数据可以提供参考&#xff0c;它可以提示我们在一个典型项目中应该花…

本质矩阵E推R和T

https://zhuanlan.zhihu.com/p/500798616 https://zhuanlan.zhihu.com/p/435306687

在vue项目中引入vuex使用(引入到vue项目中)

项目下新建store文件 // npm下载后 导入 import Vue from vue import Vuex from vuex// 注册在vue实例上 Vue.use(Vuex)// 定义结构 export default new Vuex.Store({state: {},getters: {},mutations: {},actions: {},modules: {} })//main.js import store from ./storenew …

LLMs参数高效微调(PEFT) Parameter efficient fine-tuning (PEFT)

正如你在课程的第一周所看到的&#xff0c;训练LLMs需要大量的计算资源。完整的微调不仅需要内存来存储模型&#xff0c;还需要在训练过程中使用的各种其他参数。 即使你的计算机可以容纳模型权重&#xff0c;最大模型的权重现在已经达到几百GB&#xff0c;你还必须能够为优化…

windows系统 Fooocus 图片生成模型 ,4-6GB显存即可玩,27S/p

安装步骤: 1.下载程序代码框架,大小2GB ,下载 ​​​​​​https://github.com/lllyasviel/Fooocus/releases/download/1.0.35/Fooocus_win64_1-1-1035.7z 2.下载模型文件sd_xl_base_1.0_0.9vae.safetensors ,大小6GBhttps://huggingface.co/stabilityai/stable-diffusion-x…

【C++】—— C++11之线程库

前言&#xff1a; 在本期&#xff0c;我将给大家介绍的是 C11 中新引进的知识&#xff0c;即关于线程库的相关知识。 目录 &#xff08;一&#xff09;线程库的介绍 1、线程库的由来 2、线程库的简单介绍 &#xff08;二&#xff09;线程函数参数 &#xff08;三&#xf…

在线外卖平台源码 美团外卖源码 支持多商户+多样化配送费模式+本土外卖平台+支持第三方配送

进云仿美团外卖源码是一个进云源生插件&#xff0c;支持多商户多样化配送费模式本土外卖平台支持第三方配送&#xff0c;运行需要进云框架支撑&#xff01; 特点&#xff1a; 1、多样化配送费模式&#xff1b; 2、板块-绑定商户分类机制&#xff1b; 3、板块显示时间&#…