【问题标题】:Combinations of a string double loop (JavaScript)字符串双循环的组合 (JavaScript)
【发布时间】:2017-08-02 14:31:22
【问题描述】:

我正在尝试了解如何使用双循环查找字符串的所有组合,但我遇到的解决方案对我的理解来说太复杂了。该函数可以满足我的需要,但我对设置单或双 for 循环有初学者的理解。

我希望对正在发生的事情进行一般性的逐步解释,但针对具体问题:什么函数是“i Math.pow(2,n)-1”,“ ((i & (1 j)) == 1 j)”和“var comb = '';(临时存储?)”服务?

subsets = function(str) { 
      var n = str.length;
      for (var i=1; i< Math.pow(2,n)-1; i++) {
        var comb = '';
        
        for (var j=0; j<n; j++) {
          var use = ((i & (1 << j)) == 1 << j);
          if(use)comb+=str.charAt(j);
        }
        console.log(comb);
      }
    }
    
    subsets("age");

输出:a a g a e g ge e

【问题讨论】:

  • 您的输出顺序错误。必须是 g ae 例如

标签: javascript loops combinations


【解决方案1】:

为了得到字符串的随机组合,我们可以设置一个布尔数组,存储其中一个字符是否应该显示,例如:

"a","g","e"
[true,false,true]
=>"ae"

所以可能的变化的数量是

2 /*true/false*/ ** str.length 

旧式写法:

Math.pow(2,str.length)

因此,主 for 循环遍历所有可能的组合,除了第一个组合(因为 i 以 1 开头),因为那将是一个空字符串,而最后一个 (-1) 将是“年龄”。虽然 i 是一个简单地向上计数的整数,但我们也可以想象它是一个布尔数组(在按位视图中):

integer
bits
boolean array

1
001
[false,false,true]

2
010
[false,true,false]

3
011
[false,true,true]

4
100
[true,false,false]

... 
6 < 2 ** 3 -1
110
[true,true,false]

现在是内部循环:

for (var j=0; j<n; j++) {
  var use = ((i & (1 << j)) == 1 << j);
  if(use)comb+=str.charAt(j);
}

只需检查我们的字母并检查布尔标志是否为真,因此在 i = 5 时,布尔数组将是:

[true,false,true]//101

然后转换为

"ae"

按位显示:

一个真正的(“a”):

 101 // i
&001 //1<<j where j is 0
=001
===
 001 //1<<j

一个假的(“g”):

 101
&010 //1<<j where j is 1
=000
!==
010 //1<<j

一个真正的(“e”):

 101 // i
&100 //1<<j where j is 2
=100
===
 100 //1<<j

因此它检查布尔数组 (i) 在 js 索引处是否为真,如果是则添加该字母。顺便说一句:

 if(i & (1<<j))

【讨论】:

  • 惊人的解释 Jonas :) 我刚刚掌握了如何用位和 Big O(2^n -1) 二叉树分支选项来表示和操作数字的概念......某事某事。什么是“更高级别”?双循环看起来像没有按位运算和 i
【解决方案2】:
var i=1; i< Math.pow(2,n)-1; i++

Math.pow(2, n) - 1 的意思是运行这个循环直到 (2^n)-1,其中 'n' 是字符串的长度。因此,对于输入“年龄”,第一个 for 循环将运行,而 i 从 1 开始,每个循环递增 1,小于 (2^3)-1。因此,第一个循环将运行 6 次。

var comb = ''

正是您认为的那样 - 存储在 for 循环执行其操作时填充的日志内容!

至于(i &amp; (1 &lt;&lt; j)) == 1 &lt;&lt; j),这就是我们进入Bitwise operators! 的地方,不幸的是,我对这些内容的理解几乎不足以解释它们:(

【讨论】:

  • 不幸的是,我对这些内容的理解还不够好,无法解释它们:(,至少你是诚实的,+1 ;)
【解决方案3】:

Math.pow 是幂函数。第一个参数是底数,第二个参数是指数,所以 Math.pow(2, n) 等价于 2^n。循环中i&lt; Math.pow(2,n)表示for循环的边界是while i小于2^n,其中n为字符串长度。

var comb = ''; 正在初始化一个空字符串。此字符串稍后在循环中连接,因此此声明用于建立该变量以进行连接。

【讨论】:

  • 通过连接是指将 concat 的 a 与 e 组合在一起以使“ae”作为整个结果的一部分输出,或者它连接(或保持/收集)结果的集合,因为它循环到找到要输出到控制台的组合,例如“a ag ae g ge e”?
  • @springathing 第一
【解决方案4】:

这是一个基于二进制 (0/1) 的代码 @ 987654321@ 解释

如果您在理解代码时遇到问题,请通过简单的示例逐步在纸上尝试。 尝试示例 str = "a",尝试 "on" ...

For "a" the beginning is 
 var n = str.length; // 1
for (var i=1; i< Math.pow(2,n)-1; i++) { // for i=1;i<2^1-1 =2-1=1;i++
var comb = '';
for (var j=0; j<n; j++) {//for j=0;j<1;j++
var use = ((i & (1 << j)) == 1 << j);// use = 1 & (1 << 0 insert 0 times 0)) == 1 << 0= (1 & 1)== 1=true (1==1)
if(use)comb+=str.charAt(j);//comb='' + a.charAt(0)=  comb= '' + "a"='a'

...你继续循环。

二进制是一种用 0/1 写入数字的方法:

示例 00101(二进制)

你有 5 个数字,那么第一个 0 = 0*2^(从右边开始的数字的位数-1) = 0*2^4=0

那么 00101(二进制) = 0*2^4 + 0*2^3 + 1*2^2 + 0*2^1 + 1*2^0

               = 0     + 0     + 1*4   + 0     + 1*1

               = 5 in current using (decimal)

你用谷歌找到很多关于二进制的解释

【讨论】:

  • 请修正格式。 00101(二进制) = 0*2^4+0*2^3+1*2^2+0*2^1+1*2^0=0+0+1*4+0+1* 1=5 无法理解
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-16
  • 2012-05-25
  • 1970-01-01
相关资源
最近更新 更多