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 位。
相关推荐
新晓·故知21 分钟前
<基于递归实现线索二叉树的构造及遍历算法探讨>
数据结构·经验分享·笔记·算法·链表
总裁余(余登武)32 分钟前
算法竞赛(Python)-万变中的不变“随机算法”
开发语言·python·算法
Eric.Lee202144 分钟前
音频文件重采样 - python 实现
人工智能·python·深度学习·算法·audio·音频重采样
huapiaoy1 小时前
Redis中数据类型的使用(hash和list)
redis·算法·哈希算法
冷白白1 小时前
【C++】C++对象初探及友元
c语言·开发语言·c++·算法
鹤上听雷1 小时前
【AGC005D】~K Perm Counting(计数抽象成图)
算法
睡觉然后上课2 小时前
c基础面试题
c语言·开发语言·c++·面试
xgq2 小时前
使用File System Access API 直接读写本地文件
前端·javascript·面试
一叶祇秋2 小时前
Leetcode - 周赛417
算法·leetcode·职场和发展
武昌库里写JAVA2 小时前
【Java】Java面试题笔试
c语言·开发语言·数据结构·算法·二维数组