[路飞]_6002.设计位集

「这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战

6002. 设计位集

题目

位集 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 的当前组成情况。

复制代码

提示

  • 1 < = s i z e < = 1 0 5 1 <= size <= 10^5
  • 0 < = i d x < = s i z e 1 0 <= idx <= size - 1
  • 至多调用 fix、unfix、flip、all、one、count 和 toString 方法 总共 1 0 5 10^5
  • 至少调用 all、one、count 或 toString 方法一次
  • 至多调用 toString 方法 5 次

题解

先搭个架子

class Bitset {
  constructor(size) {}
  fix(idx) {}
  unfix(idx) {}
  flip() {}
  all() {}
  one() {}
  count() {}
  toString() {}
}
复制代码

模拟法

按照题目上描述

  • 构建长度为 s i z e size 的数组,数组初始值全部为0;
  • f i x fix 函数将数组 s i z e size 指定位置设为 1 1
    fix(idx) {
        this.list[idx] = 1
    }
    复制代码
  • u n f i x unfix 函数将数组 s i z e size 指定位置设为 0 0
    unfix(idx) {
       this.list[idx] = 0
    }
    复制代码
  • f l i p flip 函数将数组 s i z e size 所有位置数据反转

如果需要通过枚举方式将数组 s i z e size 所有位置数据反转, f l i p flip 的时间复杂度将为 O(n) ;

提示中说:

  • 调用 fix、unfix、flip、all、one、count 和 toString 方法 总共 1 0 5 10^5 次;
  • 1 < = s i z e < = 1 0 5 1 <= size <= 10^5

这么大的数据量,执行这么多次, f l i p flip 的时间复杂度将为 O(n) ;有很大概率超时;

这里也是本题的难点,如果降低 f l i p flip 函数的时间复杂度;

有没有可能,这里只记录一个标识位,标识 s i z e size 数组是否反转,在其他函数中根据标识位操作数组;

这里使用 s i g n sign 标识位标识 s i z e size 数组是否反转

  • s i g n = 0 sign = 0 数组未反转,若数组反转两次,因为数组中只有 0 1 0和1 ,反转两次与数组未反转一致
  • s i g n = 1 sign = 1 数组反转过

在搭个架子

class Bitset {
  constructor(size) {
   this.list = Array(size).fill(0);
   // 标识位
   this.sign = 0
  }
  fix(idx) {}
  unfix(idx) {}
  flip() {}
  all() {}
  one() {}
  count() {}
  toString() {}
}
复制代码
  • f i x fix 函数作用是将下标为 i d x idx 的位上的值更新为 1 1 ,因为有标识位

     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
          }
        }
      }
    复制代码
  • u n f i x unfix 函数按照 f i x fix 函数处理

  • t o S t r i n g toString 函数

    • s i g n = 0 sign = 0 ,将数组元素直接转字符串输出
    • s i g n = 0 sign = 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
      }
    复制代码
  • a l l o n e c o u n t all、one、count 函数需要数组中 1 1 的数量,可以增加变量 o n e N u m b e r oneNumber , 在 f i x fix iaod, u n f i x unfix 函数中记录 o n e N u m b e r oneNumber 数据

根据上述思路分析编辑代码如下

完整代码

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
  }
}

复制代码

Guess you like

Origin juejin.im/post/7061529068209963039