İkili Alt Dizelerin Toplamı


16

Bu zorluk, ondalık sayı verildiğinde, ikilik biçime dönüştürülür ve uzunluğu orijinal sayıdan daha kısa olan ikili sayının alt dizelerinin toplamını hesaplar. İşte bir örnek:

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

Programınız girdi olarak tek bir ondalık basamaklı tamsayı almalı ve yukarıda görüldüğü gibi ikili alt dizelerin toplamını çıkarmalıdır. Girdinin her zaman ikili gösteriminde ikiden fazla basamağa sahip olacağını ve girdide programınızın yürütülmesi sırasında herhangi bir hataya neden olmayacağını varsayabilirsiniz.

Bu , bayt kazanır en kısa kod kazanır!

Test senaryoları:

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

4
İlginç bir şekilde, tam uzunlukta alt dizenin dışlanması önemli bir ekstra zorluktur.
Peter Taylor

Yanıtlar:


12

Jöle, 10 7 bayt

BṡRḄFS_

Çevrimiçi deneyin!

Nasıl çalışır

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.

Hangi kodlama size bu program için 1 bayt / karakter verir?
Toby Speight

1
@TobySpeight Jelly kendi kod sayfasını
bir

8

Pyth, 10

sPiR2.:.BQ

Çevrimiçi deneyin veya Test Suite'i çalıştırın

Açıklama:

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 bayt

6 bayt kurtarmama yardım ettiği için Dennis'e sesleniyorum!

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

Yalnızca CJam'in en yeni sürümüyle çalışır (TIO'da mevcuttur). Çevrimiçi deneyin !

Eski versiyon:

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

Çevrimiçi deneyin .


5

Python 3, 111 karakter

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)]))

EDIT : Açıklama:

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

Giriş dizesini bir int'e, ardından int'i ikili bir dizeye dönüştürün ve binyöntem, dizeyi bir dize döndürdüğü için ilk iki karakterini kaldırın0b...

İkili dizenin tüm alt dizelerini alın, bunları kullanarak ondalık sayıya dönüştürün int(n, 2)ve toplayın.

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

tüm alt dizelerin listesidir. Ungolfed sürümü:

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

Bu yardımcı olur umarım.


4

CJam (22 bayt)

Bu, mevcut en iyi CJam cevabından bir bayt daha uzun, ancak yaklaşım muhtemelen diğer bazı dillere oldukça karlı bir şekilde uyarlanabilir.

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

Çevrimiçi demo

analiz

Sorunun,

ikili sayının alt dizelerinin toplamını hesaplar

bit olmadan

uzunluğu orijinal sayıdan daha kısa olan

O zaman en önemli bitin , bit sayısının 1*(2^B-1)olduğu toplam ağırlıkla oluştuğunu göstermek çok zor değildir B; ikinci en önemli bit toplam ağırlıkla oluşur 2*(2^(B-1)-1); toplam ağırlıkla ortaya çıkan Bth-en önemli bitine kadar B*(2^1-1).

Şimdi orijinal sayının çıkarılmasını dikkate alarak x, toplamı

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

teşrih

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

Baz 2'ye dönüşüm ana toplamın ilk kısmını artı verir x; taban 1'e ikinci kısım artı x; ve taban 0'a sadece verir x, böylece taban-1'in taban-2'den xçıkarılması iptal edilir ve taban-0'ın çıkarılması istenen sonucu verir.


3

JavaScript (ES6), 78 bayt

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

Dış map, nikili gösterimin önde gelen alt dizelerini oluşturur ; iç kısım, önde gelen alt dizilerin sondaki alt dizelerini çıkarır, böylece orijinal ikili temsil dahil tüm olası alt dizeleri kapsar.

Her bir alt dize, ikili dosyadan ondalığa dönüştürülür ve orijinal girişten çıkarılır, çünkü bu, bunları bir araya getirip orijinal girişi çıkarmaktan biraz daha kısadır.


2

Mathematica, 73 70 bayt

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

İşlev. Integer-> Tamsayı


1
Yazık bir matematikte alt listelerle başa çıkmak için harika araçlar yoktur.
A Simmons

1

Retina , 64

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

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

Çevrimiçi deneyin!

Aşama açıklamasına göre yüksek düzeyli bir aşama: ondalık sayıyı tekli, tekli olmayanı ikiliye dönüştürün, önekleri alın, öneklerin soneklerini alın, orijinal sayıyı boşaltın, ikiliyi tekliğe dönüştürün, geri sayım. Golf yaptıktan sonra daha ayrıntılı bir açıklama yazacağım, bu aşamaların çoğu şüpheli görünüyor ...


1

C, 71 bayt

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

Bir akümülatör ave maske sağlıyoruz m. Maske 1'den başlar ve dış döngü etrafında her seferinde biraz daha uzar. İç döngüde, igirdinin bir kopyası maskeden daha kısa olana kadar sağa doğru kaydırılır ve her seferinde maskelenmiş değeri biriktirir.

Test programı

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

Test çıktısı

./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 bayt

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

Veya, Import "statik System.Math kullanarak;" sonra 138 ile

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 # gibi OOP dilleri böyle bir yarışı kazanamayacak, ama yine de denemek istedim. İşte daha güzelleştirilmiş bir sürüm + test cihazı.

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

Yuvalanmış do-while, shift + 1 öğesi daha sonra pos'tan daha küçük olduğu sürece sağa kaydırılmış iTemp değerini (atadıktan sonra) ekler. Bir sonraki satır iPrev'in bir sonraki kaydırılan değerini hesaplar

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 ve x2 maskeyi hesaplar, x3 uygular ve ardından sola kaydırır, çünkü son basamak her zaman bırakılır. 11 için şöyle görünüyor:

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

Biliyorum, C'deki cevapların çoğu C # 'da da sorunsuz çalışıyor (@ Tony-Speight sorunsuz çalıştı), ama amacına meydan okuyacağım. Ayrıca, kendimi bitirinceye kadar (Bold başlıkları hariç) yorumlara bakmadım, bu yüzden "C gibi" yapma tehlikesi yoktu.
DW.com

0

PowerShell v2 +, 138 Bayt

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

Ooof. İkili dosyaya / sistemden dönüştürme işlemi pahalıdır.

Girdiyi alır $a, sonra ikili çağrıyı[convert]::ToString($a,2) dönüştürmek için .NET çağrısını kullanır . Oradan, iki döngüden geçiyoruz - birincisi ipin sonundan geriye doğru sayar 1ve ikincisi yukarı doğru sayar 0. (Birincisi bir alt dize ne kadar süre dışarı çekilir ve ikincisi dize içinde alt dizeyi başlatmak için nerede indeksidir.) Bunu $liç döngüye geçirme yolu boyunca bir yardımcı ayarladık .

İç döngü içinde, uygun olanı tabandan bir tam sayıya dönüştürmek için başka bir .NET çağrısı[convert]::ToInt32() kullanırız . Bunların her biri daha sonra boru hattında bırakılır. Tüm bunları parenlerle ve a ile birlikte kapsülliyoruz , sonra bunu atıyoruz (kısa ve benzer ish )..substring()2()-join+iexInvoke-Expressioneval

Ben düşünüyorum bu teknik olarak düzgün .NET aramaları çağırmak v2 veya yenisini gerektirir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.