Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LeetCode题解:90. 子集 II,迭代+位运算,JavaScript,详细注释 #211

Open
chencl1986 opened this issue Nov 4, 2020 · 0 comments

Comments

@chencl1986
Copy link
Owner

原题链接:https://leetcode-cn.com/problems/subsets-ii/

解题思路:

  1. 用两遍循环暴力穷尽所有集合。
  2. 第一遍循环是for (let i = 0; i < 1 << nums.length; i++) {},即穷尽了所有子集数量,但不做是否存值的判断。
  3. 第二遍循环for (let j = 0; j < nums.length; j++) {},即遍历每个索引,在通过i & (1 << j)判断当前索引是否需要存值。
  4. 关于去重的方法,可以参考题解详细通俗的思路分析,多解法中的位运算部分,结合我的注释加深理解。
/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var subsetsWithDup = function (nums) {
  let result = []; // 存储最终结果
  nums.sort((a, b) => a - b); // 将nums排序,保证能够有效去重

  // 第一遍循环
  // 以nums为[1 ,2 ,3]为例,1 << nums.length生成的为二进制数1000
  // 该循环遍历了所有可能的子级
  for (let i = 0; i < 1 << nums.length; i++) {
    let subset = []; // 存储当前可能的子级
    // 判断是否可以存储当前的子集,为true时可以存储。
    // 为false时,表示当前找到了重复子集,不可以存储
    let judge = true;

    // 第二遍循环
    // 利用该循环,遍历出每个索引对应的二进制数
    for (let j = 0; j < nums.length; j++) {
      // 1 << j生成的是二进制数1、10、100,分别对应3个索引
      // 每个i都与1 << j进行与操作。即完成了当前输赢是否要存入值的判断
      // 也就是每个索引都有存或不存值两种该状态
      if (i & (1 << j)) {
        /* console.log(
          i.toString(2).split('').reverse().join(''),
          (1 << j).toString(2).split('').reverse().join(''),
          (1 << (j - 1)).toString(2).split('').reverse().join(''),
          // nums[j] === nums[j - 1],
          // (i & (1 << (j - 1))) === 0,
          Boolean(nums[j] === nums[j - 1] && (i & (1 << (j - 1))) === 0),
          [...subset, nums[j]],
        ); */
        // 判断当前子集是否已被存储过
        if (
          // 表示相邻的两个值相等,如果相等,则表示可能出现重复值
          nums[j] === nums[j - 1] &&
          // 判断j-1的值是否已被存储过,如果为否,则表示可以跳过
          // 达到了只保存第一次nums[j]和nums[j - 1]都存为子集的效果,其余的子集都会被跳过
          (i & (1 << (j - 1))) === 0
        ) {
          // 将judge设置为false,表示当前子集不需要被保存
          judge = false;
          // 由于当前子集不需要被保存,可以直接退出循环
          // 实际上不退出对最终结果没有影响
          break;
        } else {
          // 将需要存储的值,存入当前集合中
          subset.push(nums[j]);
        }
      }
    }
    // console.log('finished subset', judge, subset);

    // 将当前集合存入结果
    if (judge) {
      result.push(subset);
    }
  }

  return result;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant