이진 부분 문자열의 합


16

이 문제는 10 진수로 간단하고 이진수로 변환하고 이진수의 하위 문자열 합계를 계산합니다. 길이는 원래 숫자보다 짧습니다. 예를 들면 다음과 같습니다.

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
흥미롭게도 전체 길이 부분 문자열을 제외하는 것은 중요한 추가 과제입니다.
피터 테일러

답변:


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

온라인으로 사용해 보거나 Test Suite를 실행하십시오.

설명:

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


5

파이썬 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를 2 진 문자열로 변환하고 처음 두 문자를 제거하십시오. bin 방법의 형식으로 문자열을 반환0b...

이진 문자열의 모든 하위 문자열을 사용하여 10 진수로 변환 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 답변보다 1 바이트 길지만 접근 방식은 다른 언어에 상당히 유리하게 적용될 수 있습니다.

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

온라인 데모

분석

질문이

이진수의 부분 문자열의 합을 계산

조금도없이

길이가 원래 숫자보다 짧은

그런 다음 가장 중요한 비트가 총 가중치 1*(2^B-1)에서 발생하는 것을 보여주기가 너무 어렵지 않습니다 B. 두 번째로 중요한 비트는 총 중량으로 발생합니다 2*(2^(B-1)-1). 총 가중치로 발생하는 B 번째 최상위 비트까지 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이면 그냥 x을 주므로 밑이 2에서 밑이 1을 x빼면 취소되고, 밑이 0을 빼면 원하는 결과가 나옵니다.


3

자바 스크립트 (ES6), 78 바이트

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

바깥 쪽 map은 앞의 하위 문자열을 만듭니다.n 이진 표현의 . 내부 문자열은 선행 하위 문자열의 후행 하위 문자열을 추출하여 원래 이진 표현을 포함하여 가능한 모든 하위 문자열을 포함합니다.

각 하위 문자열은 이진수에서 10 진수로 다시 변환되고 원래 입력에서 빼고 원래 입력을 빼는 것보다 약간 짧습니다.


2

Mathematica, 73 70 바이트

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

함수. 정수-> 정수


1
동정스러운 수학에는 하위 목록을 다루는 데 유용한 도구가 없습니다.
시몬스

1

망막 , 64

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

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

온라인으로 사용해보십시오!

높은 수준의 단계별 설명 : 10 진수를 1 진수로, 1 진수를 2 진수로, 접두사를 가져오고, 접두사를 가져오고, 원래 숫자를 덤프하고, 2 진수를 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에서 시작하여 외부 루프 주위에서 매번 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;를 사용하여 Import"를 추가하면 그런 다음 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;
    }
}

중첩 된 do-while은 shift + 1이 pos보다 작 으면 오른쪽으로 이동 된 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

우프 바이너리로의 변환은 비싸다.

input $a을 가져온 다음 .NET 호출[convert]::ToString($a,2) 을 사용 하여 이진 표현으로 바꿉니다. 거기에서 우리는 두 개의 루프를 겪습니다. 첫 번째는 문자열의 끝에서 뒤로 내려 가고 1두 번째는에서 올라 0갑니다. (첫 번째는 부분 문자열을 가져 오는 길이이고, 두 번째는 문자열에서 하위 문자열을 시작할 위치의 색인입니다.) 우리는 $l이를 통해 내부 루프로 전달할 수 있도록 도우미 를 설정했습니다 .

내부 루프 내에서 다른 .NET 호출을 사용 합니다.[convert]::ToInt32() 적절한 변환 .substring()기지에서 2정수로. 그런 다음 각 파이프 라인에 남아 있습니다. 우리는 모든 것을 parens로 캡슐화 ()하고 -join그것들을 a와 함께 캡슐화 +한 다음에 iex(약칭 Invoke-Expression하고 비슷하게) 버립니다 eval.

나는 생각 이 기술적으로 제대로 .NET 호출을 호출 할 V2 이상이 필요합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.