整数のデジタル硬度


26

整数のデジタル硬さを見つけるには、そのバイナリ表現を取得し、先頭末尾1がで始まるか終わるまで削除できる回数をカウントし0ます。削除されたビットの総数は、デジタル硬度です。

これは非常に冗長な説明です。実際の例で説明しましょう。

この例では、番号3167を使用します。バイナリでは、これは次のとおりです。

110001011111

(バイナリへの変換中に、先行ゼロを必ず削除する必要があることに注意してください)

で始まったり終わったりしない0ため、1ペアのビットを削除します。

1  1000101111  1

そしてもう一つ:

11  00010111  11

しかし、最初は0であるため、もう1ペアを削除することはできません。合計で4ビットが削除されたため、43167のデジタル硬度です

ただし、正のnに対して2 n -1(つまり、バイナリ表現のみを含む)として記述できる数値の場合、0には到達しないため、すべてのビットを削除できます。これは、硬度が単に整数のビット長であることを意味します。1


チャレンジ

あなたの仕事は、負でない整数を与えられてn >= 0そのデジタル硬度を決定するプログラムまたは関数を書くことです。

I / Oを実行する完全なプログラム、または結果を返す関数を送信できます。送信はn、言語の標準整数範囲内の値に対して機能する必要があります。


テストケース

これらのいずれかが正しくない場合、または追加するエッジケースを提案する場合は、私に通知してください。

0     -> 0
1     -> 1
8     -> 0
23    -> 2
31    -> 5
103   -> 4
127   -> 7
1877  -> 2
2015  -> 10

以下は、これらのテストケースを生成するために使用した、バグのないPythonソリューションです(バグがないことは保証されていません)。

def hardness(num) -> int:
    binary = bin(num)[2:]

    if binary.count('0') == 0:
        return num.bit_length()

    revbin = binary[::-1]

    return min(revbin.find('0'), binary.find('0')) * 2

1
何も含まれてい1ない場合、どのように1を返し0ますか?つまり、文字列から1を十分に削除して、開始または終了させることはできません0
-busukxuan

2
@busukxuan「チャレンジ」見出しの直前の段落を読んでください:2 ^ n-1(つまり、バイナリ表現で1のみを含む)として記述できる数値の場合、0に到達しないため、すべてのビットを削除できます。 。これは、硬度が単に整数のビット長であることを意味します。
FlipTack

2
@busukxuanは、ゼロに達する前に、各サイドにパディングされる1の数と考えることができます。
-FlipTack

2
明らかにエッジケースが気に入らなかったダウンボッターにとって:硬さとは、それが埋め込まれた固体(1)ビットの数です-全体が固体であれば、確実に100%の硬さ、そのビットの長さですか?
-FlipTack

1
@FlipTack私はあまり影響を与えたくありません、それはあなたの挑戦です。最初に、「硬さ」は、両側から1つずつ除去できる外側のペアの最大数として理解していました。しかし、あなたが正しいかもしれません、最後に1つが残っている場合は、おそらくカウントされるべきです
ルイス・メンドー

回答:


6

ゼリー11 10バイト

BµQL××Ṛa\S

オンラインでお試しください!

使い方

BµQL××Ṛa\S  Main link. Argument: n

B           Binary; convert n to base 2.
 µ          Begin a new, monadic chain. Argument: A (array of binary digits)
  Q         Unique; deduplicate the digits.
   L        Length; count the unique digits.
    ×       Multiply each digit by the result.
     ×Ṛ     Multiply the results by reversed A.
       a\   Cumulative reduce by logical AND.
            This zeroes out all elements after the first zero.
         S  Compute the sum of the result.

8

Python76 69 68 63 62 60 57バイト

f=lambda n,k=0:n>>k&(n&n>>k>n>>k+1)and(n&n+1>0)-~f(n,k+1)

オンラインでお試しください!

使い方

これは、LSB k(n)(右からインデックスkのビット)とMSB k(n)(左からインデックスkのビット)の両方で、入力nを受け取り、0から開始してkを増分し続ける再帰的ソリューションです。設定されています。終了すると、nのビットがすべて設定されている場合はkを返し、設定されていない場合は2kを返します。

ラムダfを、補助変数tを使用して名前付き関数Fとして書き換えることから始めましょう。

def F(n, k = 0):
    t = n >> k
    return t & (n & t > t >> 1) and (n & (n + 1) > 0) + 1 + F(n, k + 1)

Fを呼び出すたびに、まずnを合計kユニット右にビットシフトし、結果をtに格納します。このように、LSB 0(t)= LSB k(n)なので、LSB k(n)が設定されている場合にのみtは奇数になります。

MSB k(n)が設定されているかどうかを判断するのは少し複雑です。これがn & t > t >> 1達成するものです。それがどのように動作するか説明するために、レッツは、整数考えるN =1αβγδεζη 2ビット長の8を、関数呼び出し分析F(N、3) 、すなわち、K = 3

私たちは、かどうかを判断しようとしているMSB 3(N)=γは比較の真理値を調べることによって設定されている(N&T> T >> 1)=(1αβγδεζη 2&1αβγδ 2 >1αβγ 2。関係する整数を調べてみましょう。

MSB-index  012k4567

n          1αβγδεζη
t             1αβγδ

t >> 1         1αβγ

n&t> t >> 1の場合に限り、γ= 1と主張します。

  • もしγ= 1、次いでN&Tビット長有する5ながらT >> 1ビット長有する4ので、N&T> T >> 1

    これは、γ= 1n&t> t >> 1を意味することを証明しています。

  • 場合は、N&T> T >> 1、2つのオプションがあります。どちらかγ= 1またはγ= 0。最初のケースでは、証明するものは何もありません。

    第二のケースでは、我々は持っているαβγδ 2 ≥N&T> T >> 1 =1αβγ 2

    以来αβγδ 2 >1αβγ 2、我々は持っている必要がありますMSB 0(αβγδ 2)≥MSB 0(1αβγ 2ことを意味し、= 1αを

    この方法で、1βγδ 2 >11βγ 2、我々が持っている必要がありますので、MSB 1(1βγδ 2)≥MSB 1(11βγ 2、その意味β= 1を

    ターンでは、これはその意味11γδ 2 >111γ 2。その覚え= 0γを第二のケースでは、我々は不平等得る110δ 2 > 1110年2ため偽で、MSB 2(110δ 2)= 0 <1 = MSB 2(1110年2

    したがって、最初のケースのみが可能であり、n&t> t >> 1はγ= 1を意味します。

まとめると、LSB k(n)MSB k(n)の両方が設定されている場合、tは奇数になり、n&t> t >> 1Trueになるため、t&(n&t> t >> 1)は収量1。ただし、LSB k(n)またはMSB k(n)が設定されていない場合(または両方が設定されている場合)、tは偶数になるか、n&t> t >> 1Falseになるため、t&(n&t> t> > 1)0を生成します

単一の引数でFを呼び出すと、k = 0が初期化されます。前に説明した条件が保持andされている間、後のコードが実行され、(特に)kを増分してFを再帰的に呼び出します。

一度LSB K(N)又はMSBのK(n)が設定されていない、条件が失敗し、F(n、k)は戻り0。先行するk関数呼び出しのそれぞれは、F(n、k)= 0(n&(n + 1)> 0)+ 1を加算するため、F(n)((n&(n + 1)> 0)+ 1)k

現在、nのすべてのビットが等しい場合(つまり、n0であるか、そのビットがすべて設定されている場合)、n + 1にnと共通のビットがないため、n&(n + 1)= 0およびF(n)kを返します。ただし、nに設定ビットと設定解除ビットの両方がある場合、n&(n + 1)> 0F(n)2kを返します。


2
Pythonの再帰的ソリューションは、最近非常によく得点されているようです。
mbomb007

少なくとも反復的なソリューションと比較すると、常にあります。input()while、およびprintすでに17のバイト...
デニス・

ええ、でも私はそれらを書くのがとても難しいと思います。
mbomb007

1
けっこうだ。ただし、同じアイデアの単純な反復実装では、5バイトしか長くなりません。tio.run/nexus/…いくつかのコツでさらに2バイトを保存できます。tio.run/nexus/python2#JY1BDsIgFAXX7SnepgUUI1BNm1K4jKVJQ/…–
デニス

6

MATL13 12バイト

Btv`6L&)}x@q

オンラインでお試しください!または、すべてのテストケースを確認します

説明

このコードは各2進数を繰り返し、外側の2つの数字を削除できる回数をカウントします。

B        % Input number (implicit). Horizontal vector of binary digits
tv       % Duplicate and concatenate vertically
`        % Do...while
  6L&)   %   Flatten the array if needed (in column-major order), and split it
         %   into two subarrays: one with the inner entries, and another
         %   with the two outer entries. The latter will be used for deciding
         %   if the loop continues or is exited
}        % Finally (execute before exiting the loop)
  x      %   Delete last subarray of inner entries
  @q     %   Push last iteration index minus 1
         % End (implicit). The next iterarion is executed if the array at the
         % top of the stack is non-empty and only contains nonzero values. 
         % Otherwise the loop is exited, executing the "finally" block first
         % Display (implicit)

6

Python、82バイト

まだゴルフができるように感じていますが、さまざまな方法を試してみましたが、これは最短でした。

def f(n):b=bin(n)[2:];x=min(b.find('0'),b[::-1].find('0'));print(x<0)*len(b)or x*2

オンラインで試す

これはOPのPythonプログラムと同様に機能しますが、このようなプログラムが含まれていないSandboxで質問を表示した後、質問を投稿する前に作成しました。


6

Python 2、66バイト

s=bin(input())[2:].split('0')
print len(min(s[-1],s[0]))<<1%len(s)

入力のバイナリ表現を1のチャンクに分割します。最初のチャンクと最後のチャンクのうち小さい方の1の数をカウントし、ダブルカウントする単一のチャンクがない限り、それを2倍にします。


賢いが、それでも理解しやすい。私はそれが好きです!
mbomb007

5
@ mbomb007デニスのを理解するためのウォームアップとしてそれを取る:)
xnor

3

PowerShell109 106バイト

$a=[convert]::ToString($args[0],2)-split0;(((($b=$a[0].length),$a[-1].length|sort)[0]*2),$b)[$a.count-eq1]

オンラインでお試しください!

入力を受け取り$args[0]、に.NET呼び出しを使用しconverttoStringベースで2、その後(すなわち、それはバイナリ作る)-splitでその文字列s 0、店舗それに秒$a。注:.NET呼び出しは先行ゼロを返さないため、最初の数字は常に1。です。

したがって、2つの可能性があります。バイナリ文字列はすべて1であるか、少なくとも1つのゼロがありました。によってインデックス化された疑似三項を持つものを区別し$a.count-eq1ます。バイナリに少なくとも1つのゼロ(左の場合)がある場合、sの最初の[0]文字列1と最後の[-1]文字列の長さの最小値を取得します(|sortその後に[0])それらの短い方が削除できるペアの数が多いため、それをで乗算し2ます。元のバイナリ文字列の端部があればそのノート0、入力のためのように8、その後[-1].lengthもなり0乗じ、(それが空の文字列なので)2依然としてあります0

それ以外の場合、バイナリ文字列すべて1を使用します$b(以前は最初の[0]文字列の長さ、この場合はバイナリ文字列全体に設定されていました)。

どちらの場合でも、その結果はパイプラインに残り、出力は暗黙的です。


3

JavaScript(ES6)、57バイト

f=
n=>n.toString(2).replace(/^(1*)(.*(\1))?$/,'$1$3').length
<input oninput=o.value=1/this.value?f(+this.value):''><input id=o readonly>

バイナリを1s取得し、等しい数の先頭と末尾のすべてに一致するか失敗することを試み1sます。


2

網膜、48バイト

.+
$*
+`(1+)\1
$1o
o1
1
m(+`^1(.*)1$
xx¶$1
x|^1$

オンラインで試す

説明:

.+              # Convert to unary
$*
+`(1+)\1        # Convert to binary (but with `o` instead of `0` -- it's shorter)
$1o
o1
1
m(+`^1(.*)1$    # Replace pairs of surrounding ones with `xx`
xx¶$1
x|^1$,          # Count x's, including the possibility of a single remaining `1`

2

C#、133バイト

硬さを返す関数。引数から整数を取ります。

int h(int b){var n=Convert.ToString(b,2);for(b=0;;){if(n[0]+n[n.Length-1]==98)n=n.Substring(1,n.Length-2);else break;b+=2;}return b;}

さて、今日'1' + '1' = 98はC#で見つけました。


1
それ'1'はASCII文字49であり、49 + 49 = 98であるためです
。– FlipTack

私は文字通り10分を費やして、なぜ私1 + 1 = 2が働かなかったのかを突き止めました。@FlipTack
devRicher

2

C、89 88 85バイト

@FlipTackが無駄な宣言を指摘したため、2バイトを節約しました。

f()テストする番号を指定して呼び出すと、関数から出力が返されます。

t,h;f(l){for(t=l;t&&~t&1<<30;t*=2);for(h=0;t&1<<30&&l&1;t*=2,l/=2)++h;return h<<!!l;}

ideoneで試してみてください




2

C、137 132 122 119 117 114 98 94 92 87 85のバイト

ゴルフを始める時間B-)

i,j;f(n){for(i=1<<30;i&~n;i/=2);for(j=0;n&i;n/=2,i/=4)j+=~n&1?i=0:2;return j-=n<1*j;}

ここに証拠があります

main()
{
  printf("%d %d\n", 0, f(0));
  printf("%d %d\n", 1, f(1));
  printf("%d %d\n", 8, f(8));
  printf("%d %d\n", 23, f(23));
  printf("%d %d\n", 31, f(31));
  printf("%d %d\n", 103, f(103));
  printf("%d %d\n", 127, f(127));
  printf("%d %d\n", 1877, f(1877));
  printf("%d %d\n", 2015, f(2015));
  printf("%d %d\n", 3167, f(3167));
} 

および出力;

0 0
1 1
8 0
23 2
31 5
103 4
127 7
1877 2
2015 10
3167 4 


1

Mathematica、63 56バイト

(2-Min[l=#~IntegerDigits~2])Min[Tr/@Split[l][[{1,-1}]]]&

説明

l=#~IntegerDigits~2

でラップされた入力のbase-2表現を生成しListます。に保管するl

(2-Min[...])

の最小要素lが1の場合、1を出力します。そうでない場合、2を出力します。

Split[l]

l実行に分割します。

... [[{1,-1}]]

最初と最後の要素を取ります。

Tr/@ ...

両方を合計してください。

Min[ ... ]

2つのうち小さい方を見つけます。

(最初の結果(1または2)にこの結果を掛けます)。


1

オクターブ、56 54バイト

 @(n)cummin(d=dec2bin(n)-48)*cummin(flip(d))'*2^!all(d)

オンラインでお試しください!

説明:

d=dec2bin(n)-48

のバイナリ表現 n

cumd= cummin(d);
cumfd = cummin(flip(d));

累積最小d および累積最小を反転しますd

res = cumd * cumfd ';

行列乗算を行う

out = res*2^!all(d)

すべての桁が1の場合、2を掛けます。


@FlipTackありがとう、リンクが更新されました!
rahnema1

1

Pyth、18バイト

?*FJjQ2lJyhSxR0_BJ

整数の入力を受け取り、結果を出力するプログラム。

テストスイート(フォーマットの最初の行)

使い方

?*FJjQ2lJyhSxR0_BJ  Program. Input: Q
?                   If
  F                 reducing
    jQ2             the binary representation of Q as a list
   J                (store in J)
 *                  by multiplication is truthy:
       lJ            Yield len(J)
                    Else:
          hS         Yield the minimum
            xR0      of the first index of zero
               _BJ   in J and its reverse
         y           * 2
                    Implicitly print

1

APL、26バイト

+/∘(∧\≢↑(∊⊢(,∧∧)¨⌽))2⊥⍣¯1⊢

テストケース:

      ( +/∘(∧\≢↑(∊⊢(,∧∧)¨⌽))2⊥⍣¯1⊢ ) ¨ 0 1 8 23 31 103 127 1877 2015    
0 1 0 2 5 4 7 2 10

説明:

+ /∘(∧\≢↑(∊⊢(、∧∧)¨⌽))2⊥⍣¯1⊢

                         ⊢入力
                    2⊥⍣¯1はバイナリ表現に変換します
   ()
        (⊢¨⌽)各ビットおよび反対側のその一致ビット
            (∧)両方のビットの論理と
             、両方のビットのリストを作成し、
              ∧次に、リストのandを取り、and
         resulting結果の配列を平坦化します
      ≢↑最初のNビットのみを取得します。Nは
                                ビットの元のリストの長さ
    running \実行中の論理および(
                                開始のもの)
+ /∘それらを合計する

1

J、22バイト

(#<.2*(<.&(#.~)|.))@#:

これはこの挑戦から学んだ巧妙なトリックに基づいています。

オンラインでお試しください!

説明

(#<.2*(<.&(#.~)|.))@#:  Input: integer n
                    #:  Binary digits of n
(                 )@    Operate on those digits D
               |.         Reverse D
       <.                 Take the minimum of
         &(#.~)           the "trailing truths" of D and reverse(D)
    2*                    Multiply by 2
 #                        The length of D
  <.                      Minimum of length and the previous result

1

PHP、83 74バイト

Jörgによって保存された3 + 6バイト

<?=(~$s=decbin($argn))[$a=strspn($s,1)]?min($a,strspn(strrev($s),1))*2:$a;

STDINから入力を受け取ります。で実行し-nRます。

壊す

<?=                     # print ...
(~
    $s=decbin($argn)        # $s = binary representation of input
)[
    $a=strspn($s,1)         # $a = number of leading `1`s
]                           # if $s has more than $a digits,
?   min($a,                     # 2. minimum of $a and
        strspn(strrev($s),1)    # 1. number of trailing `1`s
    )*2                         # 3. *2
:   $a                      # else $a (==strlen)

1
<?=~($s=decbin($argn))[$a=strspn($s,1)]?2*min($a,strspn(strrev($s),1)):$a;
ヨルクヒュルサーマン

0

JavaScript(ES6)、83バイト

f=x=>(y=x.toString(2),y.match(/^1*$/)?y:([s,e]=y.match(/^1*|1*$/g),s<e?s:e)).length

ゴルフをしていない:

function f(n) {
    var binStr = n.toString(2);
    if(binStr.match(/^1*$/)) {
        // If binary representation is all 1s, return length of binary
        return binStr.length;
    } else {
        // Grab the starting and ending 1s in the binary representation
        var [start1s, end1s] = binStr.match(/^1*|1*$/g);
        var startHardness = start1s.length;
        var endHardness = end1s.length;
        return Math.min(startHardness, endHardness);
    }
}

0

Mathematica、62バイト

(h=0;#~IntegerDigits~2//.{{1,m___,1}:>(h+=2;{m}),{1}:>h++};h)&

純粋な機能 #最初の引数を表す。

(h=0;...;h)&セットh=0し、たくさんのこと...をしてから戻りますh(硬さ)。たくさんのものを見てみましょう:

#~IntegerDigits~2                                     Binary representation of the input
                 //.                                  Apply the following list of rules repeatedly until there is no change
                    {                                 Start of the list of rules
                     {1,m___,1}                       If you see a list starting and ending with 1 with the sequence m (possibly empty) in between
                               :>(h+=2;{m}),            replace it with just {m} after incrementing h twice.
                                            {1}       If you see the singleton list {1}
                                               :>h++    replace it with h, then increment h.
                                                    } End of the list of rules

このトリックを紹介してくれたGreg Martinに感謝します。


0

Haskell94 92バイト

b 0=[]
b n=mod n 2:b(div n 2)
h n|(c,_:_)<-span(>0)$zipWith(*)n$reverse n=c++c|1<3=n
sum.h.b

オンラインでお試しください!使用法:

Prelude> sum.h.b $ 3167
4

説明:
b数値を2進数に変換し、最下位ビットが最初の0と1のリストを返します。でh、このリストは元に戻され、元のリストと要素ごとに乗算さspan(>0)れ、最初1のsの後に分割されます。

       b 3167 = [1,1,1,1,1,0,1,0,0,0,1,1] = n
    reverse n = [1,1,0,0,0,1,0,1,1,1,1,1] = m
zipWith(*)n m = [1,1,0,0,0,0,0,0,0,0,1,1] = z
   span(>0) z = ([1,1],[0,0,0,0,0,0,0,0,1,1])

結果のタプルは、空でないリストに一致する(c,_:_)where とパターンマッチングされます。バイトは前後で削除されるため、返され、最終的に合計されて_:_c = [1,1]c++c = [1,1,1,1]デジタル硬度ます。

タプルの2番目のリストが空の場合、バイナリ表現には1のみが含まれ、1の数はデジタル硬度です。パターンマッチングに失敗hするとn、ちょうどが返されます。


0

Perl、61バイト

sub f{$_=sprintf('%b',pop);length(/0/?/^(1+).*\1$/&&$1x2:$_)}

これの中心は正規表現/^(1+).*\1$/で、長さの2倍$1が答えです。コードの残りはオーバーヘッドであり、すべて1の特殊なケースを処理します。


sprintf引数を囲む括弧は省略できます。また、-pflagを使用すると、省略できるため、関数よりも短い完全なプログラムを作成できますsub f{...}(代わりに終了する必要がありますが、$_=...それでも4バイトの改善です)。最後に、の代わりにをlength(...)実行できます/0/&&s/^(1+).*\1$/$1$1/;$_=y///c。これで51バイトになります。
ダダ


0

CJam、14バイト

ri2b_0#\W%0#e<

説明:

ri e# Read integer:      | 3167
2b e# Convert to binary: | [1 1 0 0 0 1 0 1 1 1 1 1]
_  e# Duplicate:         | [1 1 0 0 0 1 0 1 1 1 1 1] [1 1 0 0 0 1 0 1 1 1 1 1]
0# e# Index of first 0:  | [1 1 0 0 0 1 0 1 1 1 1 1] 2
\  e# Swap:              | 2 [1 1 0 0 0 1 0 1 1 1 1 1]
W% e# Reverse:           | 2 [1 1 1 1 1 0 1 0 0 0 1 1]
0# e# Index of first 0:  | 2 5
e< e# Minimum:           | 2
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.