前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >布尔值数组的状态压缩

布尔值数组的状态压缩

作者头像
我脱下短袖
发布2020-02-25 13:00:43
1.5K0
发布2020-02-25 13:00:43
举报
文章被收录于专栏:算法无遗策算法无遗策

今天做一个LeetCode题发现一个小技巧,特来与你们分享一下。

做的LeetCode题是关于二维矩阵的图论建模,像下面这样的:

图论建模

二维矩阵可以不产生一个图结构,直接在二维矩阵上计算。相应地,会设定一个布尔值数组visited[ i ] [ j ],表示某一个位置是否被遍历,true表示被遍历,false表示未被遍历。

我们首先看看图论建模是如何建模的, 二维数组会有两个索引下标i和j,分别对阵为行和列。我们会设定一个常量C,而这个常量正是列的长度,即nums[i].length。

对二维矩阵每一个位置都可以用 i * C + j 表示,如下图:

代号

如果图结构想转换成二维矩阵也可以这样表示,假设图结构的一个节点的键为g,位于二维矩阵的,第几行用 g / C 表示,第几列用 g % C 表示。

代码语言:javascript
复制
i = g / C; // 获得第几行
j = g % C; // 获得第几列

三维矩阵也是通过这样的方式进行图论建模,会设定两个常量,一个是 j 的长度,另一个是 i 和 j 的面积。这里就不进行多介绍了,因为本篇介绍布尔值数组压缩状态的小技巧,再讲三维矩阵的图论建模就偏了,了解二维矩阵就好了。

在进行二维矩阵的图论建模中,如果不转成图形结构,直接在二维矩阵上计算,我们会设定一个布尔类型的二维数组visited,数组的值表示图的某个节点是否遍历过。

接着我们可以把true看作是1,false看作是0,然后转成一维数组,如下表示:

代码语言:javascript
复制
[
 0 0 0 0 0
 0 0 0 0 0   =>   [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 0 0 0 0 0
]

然后可以把这看作是二进制,将一维数组直接转成一个数字。

最重要的是,转成了一个数字,如何查看某个节点是否被遍历过,又如何将某个节点设成0和1。

我们可以这样做,假设visited一维数组为[0 0 0 1 0],表示第3位已经遍历过,转成二进制表示为0b01000,转成十进制表示为8。

我们看第0位是否是0,将visited与0b00001进行与运算,返回结果,如果结果为0说明没有遍历过;如果结果不为0遍历过。

代码语言:javascript
复制
  0b01000
& 0b00001
----------   =>   8 & (2^0) = 0
  0b00000

我们看第3位是否是0,将visited与0b01000进行与运算,返回结果。

代码语言:javascript
复制
  0b01000
& 0b01000
----------   =>   8 & (2^3) = 8
  0b01000

可以总结为:

代码语言:javascript
复制
visited & (2^i) == 0 ? 未遍历过 : 遍历过; // visited表示一个数字,i 表示第几位

2^i 也可以用 1<<i 表示
即:
visited & (1<<i) == 0 ? 未遍历过 : 遍历过;

那如何将某个节点设成1或0呢?

我们将第1位设为1,表示第1位刚遍历过,

代码语言:javascript
复制
  0b01000
+ 0b00010
----------   =>   8 + (2^1) = 10
  0b01010

注意:要提前判断第1位是否为1,如果不是可以设为1,如果是则忽略。

将第2位设为1,表示第2位刚遍历过,

代码语言:javascript
复制
  0b01010
+ 0b00100
----------   =>   10 + (2^2) = 14
  0b01110

可以总结为:

代码语言:javascript
复制
// 如果第i位为0,设为1:
if(visited & (2^i) == 0) // visited表示一个数字,i 表示第几位
    visited += 2^i;

// 2^i 也可以用 1<<i 表示
if(visited & (1<<i) == 0)
    visited += 1<<i;

同理,将第i位设为0,可以总结为:

代码语言:javascript
复制
// 如果第i位为1,设为0:
if(visited & (2^i) != 0) // visited表示一个数字,i 表示第几位
    visited -= 2^i;

// 2^i 也可以用 1<<i 表示
if(visited & (1<<i) != 0)
    visited -= 1<<i;

举一反三,学会了二进制数组压缩成一个数字的状态,多进制数组也同样可以压缩状态,只需要找到最大的那个数就可以了。

如果找到最大的数为5,那就成六进制;如果找到最大的数为25,那就成二十六进制。如果数字确实比较大,也可以考虑最小的数,进行一一映射。

通过这样的状态压缩,很多指数级别的空间复杂度直接降为O(1),省空间了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-02-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 算法无遗策 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档