「这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战」
题目
位集 Bitset 是一种能以紧凑形式存储位的数据结构。
请你实现 Bitset 类。
- Bitset(int size) 用 size 个位初始化 Bitset ,所有位都是 0 。
- void fix(int idx) 将下标为 idx 的位上的值更新为 1 。如果值已经是 1 ,则不会发生任何改变。
- void unfix(int idx) 将下标为 idx 的位上的值更新为 0 。如果值已经是 0 ,则不会发生任何改变。
- void flip() 翻转 Bitset 中每一位上的值。换句话说,所有值为 0 的位将会变成 1 ,反之亦然。
- boolean all() 检查 Bitset 中 每一位 的值是否都是 1 。如果满足此条件,返回 true ;否则,返回 false 。
- boolean one() 检查 Bitset 中 是否 至少一位 的值是 1 。如果满足此条件,返回 true ;否则,返回 false 。
- int count() 返回 Bitset 中值为 1 的位的 总数 。
- String toString() 返回 Bitset 的当前组成情况。注意,在结果字符串中,第 i 个下标处的字符应该与 Bitset 中的第 i 位一致。
示例
输入
["Bitset", "fix", "fix", "flip", "all", "unfix", "flip", "one", "unfix", "count", "toString"]
[[5], [3], [1], [], [], [0], [], [], [0], [], []]
输出
[null, null, null, null, false, null, null, true, null, 2, "01010"]
解释
Bitset bs = new Bitset(5); // bitset = "00000".
bs.fix(3); // 将 idx = 3 处的值更新为 1 ,此时 bitset = "00010" 。
bs.fix(1); // 将 idx = 1 处的值更新为 1 ,此时 bitset = "01010" 。
bs.flip(); // 翻转每一位上的值,此时 bitset = "10101" 。
bs.all(); // 返回 False ,bitset 中的值不全为 1 。
bs.unfix(0); // 将 idx = 0 处的值更新为 0 ,此时 bitset = "00101" 。
bs.flip(); // 翻转每一位上的值,此时 bitset = "11010" 。
bs.one(); // 返回 True ,至少存在一位的值为 1 。
bs.unfix(0); // 将 idx = 0 处的值更新为 0 ,此时 bitset = "01010" 。
bs.count(); // 返回 2 ,当前有 2 位的值为 1 。
bs.toString(); // 返回 "01010" ,即 bitset 的当前组成情况。
复制代码
提示
- 至多调用 fix、unfix、flip、all、one、count 和 toString 方法 总共 次
- 至少调用 all、one、count 或 toString 方法一次
- 至多调用 toString 方法 5 次
题解
先搭个架子
class Bitset {
constructor(size) {}
fix(idx) {}
unfix(idx) {}
flip() {}
all() {}
one() {}
count() {}
toString() {}
}
复制代码
模拟法
按照题目上描述
- 构建长度为 的数组,数组初始值全部为0;
-
函数将数组
指定位置设为
fix(idx) { this.list[idx] = 1 } 复制代码
-
函数将数组
指定位置设为
unfix(idx) { this.list[idx] = 0 } 复制代码
- 函数将数组 所有位置数据反转
如果需要通过枚举方式将数组 所有位置数据反转, 的时间复杂度将为 O(n) ;
提示中说:
- 调用 fix、unfix、flip、all、one、count 和 toString 方法 总共 次;
这么大的数据量,执行这么多次, 的时间复杂度将为 O(n) ;有很大概率超时;
这里也是本题的难点,如果降低 函数的时间复杂度;
有没有可能,这里只记录一个标识位,标识 数组是否反转,在其他函数中根据标识位操作数组;
这里使用 标识位标识 数组是否反转
- 数组未反转,若数组反转两次,因为数组中只有 ,反转两次与数组未反转一致
- 数组反转过
在搭个架子
class Bitset {
constructor(size) {
this.list = Array(size).fill(0);
// 标识位
this.sign = 0
}
fix(idx) {}
unfix(idx) {}
flip() {}
all() {}
one() {}
count() {}
toString() {}
}
复制代码
-
函数作用是将下标为 的位上的值更新为 ,因为有标识位
fix(idx) { // 如果标识位为0,数组数据没有反转过,所以需要将 idx 处为 0 的元素修改为 1 if (this.sign === 0) { if (this.list[idx] === 0) { this.list[idx] = 1 } } else { //此处标识,如果标识位为1,数组数据反转过,所以需要将 idx 处为 1 的元素修改为 0 // 这里需要解释一下,因为数组元素反转仅仅使用 sign 记录,并没有修改 数组元素 // 所以元素 1 在反转应该为 0;fix函数是将idx 处为 0 修改修改为 1 // 所以 此处判断 this.list[idx] === 1 符合条件后修改 this.list[idx] if (this.list[idx] === 1) { this.list[idx] = 0 } } } 复制代码
-
函数按照 函数处理
-
函数
- ,将数组元素直接转字符串输出
- ,将数组元素取反转字符串输出
toString() { let s = '' for (let i = 0; i < this.list.length; i++) { if (this.sign === 0) { s += this.list[i] } else { s += this.list[i] ? 0 : 1 } } return s } 复制代码
-
函数需要数组中 的数量,可以增加变量 , 在 iaod, 函数中记录 数据
根据上述思路分析编辑代码如下
完整代码
class Bitset {
constructor(size) {
this.list = Array(size).fill(0)
this.sign = 0
this.oneNumber = 0
}
fix(idx) {
if (this.sign === 0) {
if (this.list[idx] === 0) {
this.list[idx] = 1
this.oneNumber++
}
} else {
if (this.list[idx] === 1) {
this.list[idx] = 0
this.oneNumber++
}
}
}
unfix(idx) {
if (this.sign === 0) {
if (this.list[idx] === 1) {
this.list[idx] = 0
this.oneNumber--
}
} else {
if (this.list[idx] === 0) {
this.list[idx] = 1
this.oneNumber--
}
}
}
flip() {
const len = this.list.length
if (this.sign === 0) {
this.sign = 1
} else {
this.sign = 0
}
this.oneNumber = len - this.oneNumber
}
all() {
return this.oneNumber === this.list.length
}
one() {
return this.oneNumber > 0
}
count() {
return this.oneNumber
}
toString() {
let s = ''
for (let i = 0; i < this.list.length; i++) {
if (this.sign === 0) {
s += this.list[i]
} else {
s += this.list[i] ? 0 : 1
}
}
return s
}
}
复制代码