python- 算法题-8_找出所有子集的异或总和再求和

一个数组的 异或总和 定义为数组中所有元素按位 XOR 的结果;如果数组为 空 ,则异或总和为 0 。

例如,数组[2,5,6] 的 异或总和 为 2 XOR 5 XOR 6 = 1 。
给你一个数组 nums ,请你求出 nums 中每个 子集 的 异或总和 ,计算并返回这些值相加之 和 。

注意:在本题中,元素 相同 的不同子集应 多次 计数。

数组 a 是数组 b 的一个 子集 的前提条件是:从 b 删除几个(也可能不删除)元素能够得到 a 。

示例1

输入:nums = [1,3]
输出:6
解释:[1,3] 共有 4 个子集:

  • 空子集的异或总和是 0 。
  • [1] 的异或总和为 1 。
  • [3] 的异或总和为 3 。
  • [1,3] 的异或总和为 1 XOR 3 = 2 。
    0 + 1 + 3 + 2 = 6

示例2

输入:nums = [5,1,6]
输出:28
解释:[5,1,6] 共有 8 个子集:

  • 空子集的异或总和是 0 。
  • [5] 的异或总和为 5 。
  • [1] 的异或总和为 1 。
  • [6] 的异或总和为 6 。
  • [5,1] 的异或总和为 5 XOR 1 = 4 。
  • [5,6] 的异或总和为 5 XOR 6 = 3 。
  • [1,6] 的异或总和为 1 XOR 6 = 7 。
  • [5,1,6] 的异或总和为 5 XOR 1 XOR 6 = 2 。
    0 + 5 + 1 + 6 + 4 + 3 + 7 + 2 = 28

示例3

输入:nums = [3,4,5,6,7,8]
输出:480
解释:每个子集的全部异或总和值之和为 480 。

  • 解法1:

from typing import List

def subsetXORSum(nums: List[int]) -> int:
    length = len(nums)
    res = 0
    for index in range(0, 2 ** length):
        subset_res = 0
        for sub_index in range(0, length):
            cur_bit = (index >> sub_index) & 1
            if cur_bit == 1:
                subset_res ^= nums[sub_index]
        res += subset_res
    return res

#nums = [1, 3]
#nums = [5, 1, 6]
nums = [3, 4, 5, 6, 7, 8]
print(subsetXORSum(nums))



## 测试脚本,用于显示上述脚本的执行流程过程。
from typing import List

def subsetXORSum(nums: List[int]) -> int:
    length = len(nums)
    res = 0
    for index in range(0, 2 ** length):
        subset_res = 0
        test = ''
        test2 = ''
        test3 = ''
        for sub_index in range(0, length):
            cur_bit = (index >> sub_index) & 1
            test = test + str(cur_bit)
            test3 = str(cur_bit) + test3
            if cur_bit == 1:
                subset_res ^= nums[sub_index]
                test2 = test2 + str(nums[sub_index])
            else:
                test2 = test2 + ' '
        res += subset_res
        print(test3, '\t本次循环', index, '的二进制表示')
        print(test, '\t本次循环', index, '的二进制反序表示')
        print(test2, '\t本次循环子集组合')
        print(subset_res, '\t该子集异或结果')
        print(res, '\t目前为止所有子集的总和')
        print()
    return res

#nums = [1, 3]
#nums = [5, 1, 6]
nums = [3, 4, 5, 6, 7, 8]
print(subsetXORSum(nums))

这段代码实现了一个函数 subsetXORSum,该函数接受一个整数列表 nums 作为输入,并返回该列表中所有子集的异或和。

代码解析如下:

  1. 导入了 typing 模块中的 List 类型,用于标注函数参数和返回值的类型。

  2. 定义了函数 subsetXORSum,参数为 nums,返回值为整数类型。

  3. 创建了变量 length 并赋值为输入列表 nums 的长度。

  4. 创建了变量 res 并初始化为0,用于存储子集异或和的累加结果。

  5. 使用循环遍历所有可能的子集,循环条件为 range(0, 2 ** length)。其中 2 ** length 表示子集个数的上限,因为每个元素都有两种选择:包含或不包含。

  6. 在内部循环中,使用 sub_index 遍历子集的位索引,循环条件为 range(0, length)。该循环用来判断当前子集中是否包含 列表numssub_index 位的元素。

  7. 使用位运算 (index >> sub_index) & 1 取出当前子集的第 sub_index 位,并将结果赋给变量 cur_bit。如果 cur_bit 等于1,则表示该子集包含 列表numssub_index 位元素。

  8. 如果 cur_bit 等于1,则将该子集中的元素与 subset_res 进行异或操作,并将结果赋给 subset_res。这样就得到了当前子集的异或和。

  9. 将每个子集的异或和累加到变量 res 上。

  10. 循环结束后,返回最终的累加结果 res

  11. 调用函数 subsetXORSum,传入列表 nums,并将结果打印输出。你可以根据需要修改 nums 的值,取消注释对应的行即可。例如,如果 nums = [1, 3],则输出为6;如果 nums = [5, 1, 6],则输出为28;如果 nums = [3, 4, 5, 6, 7, 8],则输出为480。

  • 解法2:

该解法的解释可以参考下篇。python- 算法题-8_找出所有子集的异或总和再求和_扩展

def subsetXORSum(nums: list[int]) -> int:
    res = 0
    length = len(nums)
    for num in nums:
        res |= num
    return res << (length - 1)

#nums = [1, 3]
#nums = [5, 1, 6]
nums = [3, 4, 5, 6, 7, 8]
print(subsetXORSum(nums))


num * 2 ** N = num << N ,num 和 N 必须是整数。

这段 Python 3 代码实现了一个函数 subsetXORSum,它接受一个整数列表 nums 作为参数,并返回对所有子集进行异或操作的结果。

让我们逐行解析这段代码:

def subsetXORSum(nums: list[int]) -> int:

这一行定义了一个名为 subsetXORSum 的函数,它接受一个名为 nums 的参数,该参数是一个整数列表,并且返回一个整数。

    res = 0

在函数内部,我们初始化一个整数变量 res 并将其设置为 0。该变量用于存储异或操作的结果。

    length = len(nums)

我们使用 len() 函数获取 nums 列表的长度,并将其赋值给变量 length,以便在后面的计算中使用。

    for num in nums:
        res |= num

这是一个循环语句,用于遍历 nums 列表中的每个元素。在循环中,我们使用位运算符 |= 将当前元素 numres 进行按位或(bitwise OR)操作,并将结果存回 res。这样做的目的是将所有的元素进行异或操作。

    return res << (length - 1)

最后,我们使用位运算符 <<res 左移 (length - 1) 位,然后将结果返回。这是因为对于 nums 列表中的每个元素,在所有子集中都有 (length - 1) 个子集中包含了该元素。所以我们将结果左移 (length - 1) 位,相当于将每个元素的异或结果乘以 2 的 (length - 1) 次方。

nums = [3, 4, 5, 6, 7, 8]
print(subsetXORSum(nums))

在这段代码的最后,我们定义了一个名为 nums 的列表,并将其赋值为 [3, 4, 5, 6, 7, 8]。然后我们调用 subsetXORSum 函数,将 nums 作为参数传递给它,并打印函数的返回值。

扩展:

XOR 全称为异或运算,是一种逻辑运算符,通常用符号 “^” 表示。其作用是对两个二进制数进行逐位比较,如果相同则输出 0,不同则输出 1。

XOR 的真值表如下:

A B A ^ B
0 0 0
0 1 1
1 0 1
1 1 0

其中 A 和 B 均为二进制数值(可以是 0 或 1)。

XOR 运算有一些特殊的性质:

  1. 相同数值 XOR 后结果为 0。即 a ^ a = 0。
  2. 任何数值与 0 进行 XOR 运算,结果均为其本身。即 a ^ 0 = a。
  3. XOR 运算支持交换律和结合律,即 a ^ b = b ^ a,a ^ (b ^ c) = (a ^ b) ^ c。
  4. XOR 运算可以用于找到只出现一次的数字,例如在一个数组中,除了某个元素只出现一次以外,其余每个元素均出现两次。使用 XOR 运算,可以将所有数字进行逐个异或,最终结果即为只出现一次的数字。

在计算机领域,XOR 运算还常常被用来进行二进制数据的加密和解密。

扩展1:

num * 2 ** N = num << N

这个等式表示,将一个数字 num 左移 N 位,结果与将 num 乘以 2N 次方相等。

数学公式为:\text{num} * 2^\text{N} = \text{num} << \text{N}

其中,<< 表示左移运算符,将一个数的二进制表示向左移动指定的位数。

请注意,上述等式成立的前提是 numN 必须是整数。

参考:
https://www.bilibili.com/video/BV1YT4y117AH?p=9&vd_source=fd551c73306d10ac7c5d19c2369e1ce3
https://leetcode.cn/problems/sum-of-asub_l-subset-xor-totals/
https://leetcode.cn/problems/sum-of-asub_l-subset-xor-totals/solution/zhi-xu-yao-li-jie-zi-ji-he-er-jin-zhi-sh-h9l2/
https://leetcode.cn/problems/sum-of-all-subset-xor-totals/solution/sum-of-all-subset-xor-totals-by-leetcode-o5aa/
https://leetcode.cn/problems/sum-of-all-subset-xor-totals/solution/onsuan-fa-jian-ming-jiang-jie-by-yuyinsl-9sod/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容