AcWing 801. 二进制中1的个数——算法基础课题解

AcWing 801. 二进制中 1 的个数

题目描述

给定一个长度为 n 的数列,请你求出数列中每个数的二进制表示中 1 的个数。

输入格式

第一行包含整数 n。

第二行包含 n 个整数,表示整个数列。

输出格式

共一行,包含 n 个整数,其中的第 i 个数表示数列中的第 i 个数的二进制表示中 1 的个数。

数据范围

1≤n≤100000,

0≤数列中元素的值≤10^9

输入样例

cpp 复制代码
5
1 2 3 4 5

输出样例

cpp 复制代码
1 1 2 1 2

C++

cpp 复制代码
#include <iostream>

using namespace std;

int main() {
    int n;
    scanf("%d", &n);
    while (n--) {
        int x, s = 0;
        scanf("%d", &x);

        for (int i = x; i; i -= i & -i) s++;

        printf("%d ", s);
    }

    return 0;
}

i -= i & -i 这行代码是在计算 i 的二进制表示中最低位的 1,然后从 i 中减去这个值。

首先,-ii 的二进制补码,它的计算方式是先对 i 的二进制表示取反,然后加 1。这样,i & -i 的结果就是 i 的二进制表示中最低位的 1

然后,i -= i & -i 就是将 i 减去它的二进制表示中最低位的 1。这样,i 的二进制表示中的最低位的 1 就被去掉了。

例如,假设 i 的值是 12,它的二进制表示是 1100-i 的二进制表示是 0100,所以 i & -i 的结果是 0100。然后,i -= i & -i 的结果就是 1000,也就是 8。这样,i 的二进制表示中的最低位的 1 就被去掉了。

这个操作在计算一个数的二进制表示中 1 的个数时非常有用,因为每次循环都会去掉 i 的二进制表示中的一个 1,直到 i 变为 0 为止。

在 C++中,-i 是通过取 i 的二进制补码来计算的。具体步骤如下:

  1. 首先,对 i 的二进制表示取反。这意味着所有的 1 变为 0,所有的 0 变为 1
  2. 然后,将取反后的结果加 1

例如,假设 i 的值是 5,它的二进制表示是 0101。取反后,我们得到 1010。然后,我们将这个结果加 1,得到 1011。所以,-i 的二进制表示是 1011,对应的十进制值是 -5

这种计算方式是基于二进制补码的原理,它是计算机内部表示和处理负数的一种方式。

Go

go 复制代码
package main

import (
	"bufio"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	line, _ := reader.ReadString('\n')
	params := strings.Fields(line)
	n, _ := strconv.Atoi(params[0])
	line, _ = reader.ReadString('\n')
	params = strings.Fields(line)
	writer := bufio.NewWriter(os.Stdout)
	defer writer.Flush()
	for i := 0; i < n; i++ {
		var count int
		num, _ := strconv.Atoi(params[i])
		for num > 0 {
			num -= num & -num
			count++
		}
		writer.WriteString(strconv.Itoa(count) + " ")
	}
}
go 复制代码
package main

import "fmt"

func main() {
	var n int
	fmt.Scanf("%d\n", &n)
	for i := 0; i < n; i++ {
		var tmp int64
		var count int
		fmt.Scanf("%d", &tmp)
		for tmp > 0 {
			tmp -= tmp & -tmp
			count++
		}
		fmt.Printf("%d ", count)
	}
}

模板

cpp 复制代码
求n的第k位数字: n >> k & 1
返回n的最后一位1:lowbit(n) = n & -n

n >> k 这个操作是将 n 右移 k 位。在二进制表示中,右移一位等同于将这个数除以 2。所以,n >> k 就是将 n 除以 2k 次方。这个操作的结果是将 n 的第 k 位移动到最低位。

然后,& 1 这个操作是将上述结果与 1 进行按位与操作。在二进制表示中,任何数与 1 进行按位与操作,结果都等于这个数的最低位。所以,n >> k & 1 的结果就是 n 的第 k 位。

例如,假设 n 的值是 13,它的二进制表示是 1101。如果我们想获取第 2 位,我们可以计算 n >> 2 & 1

  1. n >> 2 的结果是 11(即 3),这是将 n 的第 2 位移动到最低位的结果。
  2. 3 & 1 的结果是 1,这就是 n 的第 2 位。
相关推荐
龙的爹233314 分钟前
论文翻译 | The Capacity for Moral Self-Correction in Large Language Models
人工智能·深度学习·算法·机器学习·语言模型·自然语言处理·prompt
鸣弦artha1 小时前
蓝桥杯——杨辉三角
java·算法·蓝桥杯·eclipse
我是聪明的懒大王懒洋洋1 小时前
力扣力扣力:动态规划入门(1)
算法·leetcode·动态规划
丶Darling.1 小时前
Day44 | 动态规划 :状态机DP 买卖股票的最佳时机IV&&买卖股票的最佳时机III
算法·动态规划
TN_stark9322 小时前
多进程/线程并发服务器
服务器·算法·php
汉克老师2 小时前
GESP4级考试语法知识(贪心算法(四))
开发语言·c++·算法·贪心算法·图论·1024程序员节
nameofworld2 小时前
前端面试笔试(二)
前端·javascript·面试·学习方法·数组去重
smj2302_796826523 小时前
用枚举算法解决LeetCode第3348题最小可整除数位乘积II
python·算法·leetcode
摇光933 小时前
promise
前端·面试·promise
爱吃生蚝的于勒3 小时前
C语言最简单的扫雷实现(解析加原码)
c语言·开发语言·学习·计算机网络·算法·游戏程序·关卡设计