二进制子串的总和


16

这个挑战很简单,给定一个十进制数,将其转换为二进制数,并计算其长度小于原始数的二进制数子串的总和。这是一个例子:

Input:
  11
Binary:
  11 -> 1011
Substrings:
  101 = 5
  011 = 3
  10  = 2
  01  = 1
  11  = 3
  1   = 1
  0   = 0
  1   = 1
  1   = 1
Sum:
  5+3+2+1+3+1+0+1+1=17
Output:
  17

您的程序应采用一个十进制整数作为输入,并输出二进制子字符串的总和,如上所述。您可能会假设输入的二进制表示形式始终有两位以上的数字,并且输入的内容在程序执行期间不会引起任何错误。

这是,以字节为单位的最短代码胜出!

测试用例:

2  => 1
3  => 2
4  => 3
5  => 5
6  => 7
7  => 9
8  => 7
9  => 10
10 => 14
11 => 17

4
奇怪的是,排除全长子字符串是一项重大的额外挑战。
彼得·泰勒,

Answers:


12

果冻,10 7个字节

BṡRḄFS_

在线尝试!

怎么运行的

BṡRḄFS_  Main link. Input: n

B        Convert n to base 2.
  R      Yield [1, ..., n].
 ṡ       Get all overlapping slices of lengths 1 to n.
         This yields empty arrays if the slice size is longer than the binary list.
   Ḅ     Convert each binary list to integer.
    F    Flatten the resulting, nested list.
     S   Compute the sum of the result.
      _  Subtract n from the sum.

哪种编码可为您提供该程序1个字节/字符?
Toby Speight

1
@TobySpeight Jelly使用其自己的代码页。
意大利面条

8

珀斯10

sPiR2.:.BQ

在线尝试或运行测试套件

说明:

sPiR2.:.BQ    ##   Q = eval(input())
       .BQ    ##   get binary string of Q
     .:       ##   get all substrings of that
  iR2         ##   convert them all to base 10
sP            ##   sum all but the last element, which is the input number

6

CJam,27个 21字节

向丹尼斯大喊帮助我节省6个字节!

q~:Q{)Q2bew2fb~}%1bQ-

仅适用于最新版本的CJam(在TIO上可用)。在线尝试

旧版本:

qi2b_,,0-\f{ew}{{2b}%}%e_:+

在线尝试


5

Python 3,111个字符

N=bin(int(input()))[2:];L=len(N);r=range;print(sum(int(n,2)for n in[N[j:j+i]for i in r(1,L)for j in r(L-i+1)]))

编辑:说明:

N=bin(int(input()))[2:]

将输入字符串转换为int,然后将int转换为二进制字符串并删除其前两个字符,因为该bin方法返回的格式为0b...

取二进制字符串的所有子字符串,使用将它们转换为十进制int(n, 2)并求和。

[N[j:j+i]for i in r(1,L)for j in r(L-i+1)]

是所有子字符串的列表。非高尔夫版本:

def all_substrings(N):
    result = []
    for i in range(1, len(N)):
        for j in range(len(N) - i + 1):
            result.append(N[j:j+i])
    return result

希望这可以帮助。


4

CJam(22字节)

这比当前的最佳CJam答案长一个字节,但是该方法可能可以非常有益地适用于某些其他语言。

3,ri_2b_,,:).*\+fbW%:-

在线演示

分析

假设问题是

计算二进制数的子字符串之和

没有一点

长度比原始号码短

这样就不难证明最高有效位是在总权重1*(2^B-1)下出现的,其中B位是位数。第二高有效位出现在总权重中2*(2^(B-1)-1);下降到Bth最高有效位,该位与总权重有关B*(2^1-1)

现在考虑原始数字的减法x,我们得出总和

sum_i (x & 2^i) * 2^i * 2*(B-i)  -  sum_i (x & 2^i) * (B-i)  -  x

解剖

3,        e# Put [0 1 2] on the stack - we'll need it later
ri_       e# Get the input x and copy it
2b        e# Convert the copy to base 2
_,,:).*   e# Pointwise multiply by 1 plus the index
\+        e# Append x to the resulting array, giving A
fb        e# Map a base conversion
W%:-      e# Reverse and fold a subtraction

转换为基数2将得出主要总和的第一部分x;以1为底给出第二部分加x; 并以0为底数得到just x,因此从以2为底数的基数减去以1为底数的xs抵消,然后以0为底数减去就得到期望的结果。


3

JavaScript(ES6),78个字节

n=>[...n.toString(2)].map(c=>[...s+=c].map((_,i)=>n-='0b'+s.slice(i)),s='')|-n

外部map建立了n二进制表示形式的前导子字符串;内部一个提取前导子串的结尾子串,从而覆盖所有可能的子串,包括原始的二进制表示形式。

每个子字符串都从二进制转换为十进制,并从原始输入中减去,因为这比将它们加在一起然后减去原始输入要短一些。


2

Mathematica,73个 70字节

Tr[FromDigits[#,2]&/@StringCases[#~IntegerString~2,__,Overlaps->All]]&

功能。整数->整数


1
可怜的数学家没有很好的工具来处理子列表。
西蒙斯(Simmons)

1

视网膜,64

.*
$*
+`(1+)\1
$1a
a1
1
r&!M`.*
&!M`.*
^.*

+`1(a*)\b
a$.1$*1;
;

在线尝试!

逐级描述:十进制转换为一进制,一进制转换为二进制,获取前缀,获取前缀后缀,转储原始数字,将二进制转换为一元,返回计数。打完高尔夫球后,我将写一个更详细的描述,其中很多阶段似乎都是可疑的...


1

C,71字节

f(n){int a=0,m=0,i;for(;++m<n;m+=m)for(i=n;i+i>m;i/=2)a+=i&m;return a;}

我们维护一个蓄能器a和面具m。掩码从1开始,并且每次在外循环周围都增加一位。在内部循环中,i输入的副本将连续右移,直到它比掩码短,每次都会累积掩码值。

测试程序

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
    while (*++argv) {
        int n = atoi(*argv);
        printf("%d -> %d\n", n, f(n));
    }
    return 0;
}

测试输出

./73793 $(seq 0 11)
0 -> 0
1 -> 0
2 -> 1
3 -> 2
4 -> 3
5 -> 5
6 -> 7
7 -> 9
8 -> 7
9 -> 10
10 -> 14
11 -> 17

1

C#,148个字节

int x(int i){int s,r=0,j=i,p=System.Convert.ToString(i,2).Length+1,k;for(;--p>-1;){k=j;s=-1;for(;++s<p;)r+=(k>>=1);j=(i&((1<<p-1)-1))<<1;}return r;}

或者,如果添加“使用静态System.Math导入”;然后用138

int x(int i){int s,r=0,j=i,p=(int)Round(Log(i,2)+1.49,0),k;for(;--p>-1;){k=j;s=-1;for(;++s<p;)r+=(k>>=1);j=(i&((1<<p-1)-1))<<1;}return r;}

像C#这样的OOP语言不会赢得这场比赛,但是我还是想尝试一下。这是一个更加美化的版本+测试器。

class Program
{
    // Tester: 50 bytes
    static void Main(string[] args)
    {
        int i=2;
        do System.Console.WriteLine($"{i} -> {x(i++)}"); while (i < 12);
        System.Console.Read();
    }
    // Function: 65 bytes (size according to ILDASM.exe)
    static int x(int iOrg)
    {
        int pos, shift, retVal=0, iPrev=iOrg, iTemp;
        pos = System.Convert.ToString(iOrg, 2).Length;
        do {
            iTemp = iPrev; shift = 0;
            do retVal += (iTemp >>= 1); while (++shift < pos);
            iPrev = (iOrg & ((1 << pos - 1) - 1)) << 1;
        } while (--pos > -1); 
        return retVal;
    }
}

只要shift + 1小于pos,则嵌套do-while会添加iTemp的右移值(分配后)。下一行计算iPrev的下一个移位值

x1 = 1 << p -1; // 1 << 4 -1 = 8 [1000]
x2 = x1 - 1;    // 8 -  1 = 7    [0111]
x3 = i & x2;    // 1011 & 0111 = 0011 
x4 = x3 << 1;   // 0011 << 1 = 00110
i2 = x4;

x1和x2计算掩码,x3应用它,然后左移它,因为最后一位总是被丢弃。对于11,它看起来像这样:

START -> _1011[11]
101
10
1   -->  X0110[6], r=0+5+2+1=8
 011
 01
 0  -->  XX110[6], r=8+4=12
  11
  1 -->  XXX10[2], r=12+4=16
   1 ->  XXXX0[X], r=16+1=17

我知道,C语言中的大多数答案也可以在C#中无缝运行(@ Tony-Speight可以毫无问题地工作),但是我敢于达到目的。另外,直到我自己完成评论之后,我才查看注释(好吧,除了粗体标头),因此没有像“ C”那样做的危险。
DW.com

0

PowerShell v2 +,138字节

param($a)$a=[convert]::ToString($a,2);(($b=$a.length-1)..1|%{$l=$_;0..($b-$l+1)|%{[convert]::ToInt32($a.substring($_,$l),2)}})-join'+'|iex

哎呀 到二进制的转换非常昂贵。

接受输入$a,然后使用.NET调用[convert]::ToString($a,2)将其转换为二进制表示形式。从那里开始,我们经历两个循环-第一个循环从字符串的末尾向下1计数到,而第二个循环从计数0。(第一个是将子字符串拉出多长时间,第二个是在字符串中开始子字符串的位置的索引。)我们$l沿路径设置了一个辅助函数,以将其传递到内部循环。

在内部循环中,我们使用另一个.NET调用[convert]::ToInt32()将适当的值.substring()从base 2转换为整数。然后,将它们中的每一个都留在管道上。我们封装所有的与括号(),并-join与他们一起+,再折腾那关到iex(简称Invoke-Expression和类似十岁上下到eval)。

认为这从技术上要求v2或更高版本才能正确调用.NET调用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.