전화 키패드 최적화


33

드보락이나 네오와 같은 새로운 키보드 레이아웃을 정통하게 배우는 사람들이 생산성을 높이기 때문에 이러한 열풍이 계속되고있는 것 같습니다. 키보드 레이아웃을 전환하는 것은 속도가 빠르기까지 몇 개월이 걸릴 수 있기 때문에 나쁜 생각이라고 주장합니다. 나머지보다 5 % 빠르면 컴퓨터에 입력해야 할 경우 문제가 발생합니다 당신 만의 것이 아닙니다.

또한이 모든 사람들 은 현대 통신 의 실제 병목 현상이있는 곳 ( 전화 키패드)을 잊어 버립니다 .

일반적인 전화 키패드는 다음과 같습니다.

전화 키패드

문자 'r'은 버튼 7의 세 번째 문자입니다. 따라서 휴대폰에 문자 'r'을 입력하려면 버튼 7을 세 번 누르고 's'는 4 번, 'a'는 버튼 2를 한 번 누릅니다.

이것을 고려할 때 'd'뒤에 'e'를 넣는 것은 잘못된 결정일 것입니다. 'e'는 영어 알파벳에서 가장 일반적으로 사용되는 문자이므로 "DEF"대신 버튼 3 "EDF"에 레이블을 지정하려면 많은 키 입력을 절약 할 수 있습니다.

또한, 같은 버튼을 공유하는 2 개의 문자를 입력하는 것이 번거 롭다는 것을 스스로 경험했을 것입니다. "TU"를 쓰려면 8을 세 번 누르기 만하면 'V'가됩니다. 따라서 일반적으로 'T'를 쓴 다음 스페이스를 누른 다음 백 스페이스를 누른 다음 'U'를 쓰십시오. 이는 3 대신 5 버튼 누름과 같습니다.


TL; DR

이 두 가지 규칙이 주어집니다.

  • 버튼을 n 번 누르면 문자가 입력됩니다. 여기서 n은 버튼의 레이블에서 문자가있는 위치입니다.
  • 같은 버튼을 사용하여 입력 한 두 글자를 쓰려면 추가로 두 번의 버튼 누름이 필요합니다

특정 텍스트가 주어지면 최소한의 버튼 누름이 필요한 전화 키보드 레이아웃은 무엇입니까? 2-9, 1 및 0 버튼 만 특수 기호로 예약되어 있어야합니다.

입력

최적의 레이아웃을 찾아야하는 텍스트는 stdin을 통해 제공됩니다. 소문자 알파벳 이외의 다른 것을 처리 할 필요가 없으며 입력만으로 구성되어 있다고 가정 할 수 있습니다. 입력 텍스트가 상당히 크고 모든 문자가 적어도 한 번 있으면 거기에 있다고 가정 할 수 있습니다.

산출

출력에 너무 많은 제약을두기를 원하지 않습니다. 때로는 일부 언어가 다른 언어보다 유리하기 때문입니다. 그러나 귀하의 언어는 배열이 훌륭하다는 것을 보여 주거나, 또는 각 줄을 개행으로 분리 할 수 ​​있습니다.

여러 가지 최적의 레이아웃이있을 수 있으며 그 중 하나를 인쇄 할 수 있습니다. 다음은 간단한 예입니다.

>> echo "jackdawslovemybigsphinxofquartz" | foo.sh
ojpt
avhz
cen
skm
dyf
wbq
ixu
lgr

보너스 포인트

알고리즘이 모든 가능한 레이아웃을 강제하지 않는 경우 -35 (여기서는 Haskell의 '순열'을보고 있습니다)

-3 코드가 문자 메시지 (140 자) 안에 들어가고 친구에게 코드를 보내는 사진을 게시하면 -3 입니다.

이것이 StackExchange의 첫 번째 도전입니다. 당신이 그것을 좋아하는지, 그것에 대해 다른 의견이 있으시면 기쁘겠습니다.


2
CodeGolf.SE에 오신 것을 환영합니다! 귀하의 질문에 아무런 문제가 보이지 않지만 , 기본 사이트에 게시하기 전에 먼저 샌드 박스에 도전 과제를 게시하여 피드백을 받고 모호성을 제거하는 것이 좋습니다.
Martin Ender

아 멋지다, 나는 확실히 미래에있을 것이다.
Flonk

1
내 전화는 하나의 60 자 SMS를 보낼 수 있지만 대괄호를 제대로 지원하지 않습니다. 보너스가 없습니까?
ζ--

1
좋은 질문! 누구도 -35 보너스 를 피할 수 없다고 생각 합니다. 키 중 두 개에 4 자, 나머지 6 개에 3자를 갖는 레이아웃으로 제한하더라도 키의 26! / (2! * 6!) = 280,063,514,671,253,913,600,000 > 2^77간단한 재 배열을 한 번만 계산 하는 고유 한 순열 이 있습니다 .
Dennis

2
또한 사람들이 솔루션의 버튼 누름 횟수를 인쇄 할 수 있는지 묻습니다. 그래서 누가 가장 좋은 것을 찾았는지 볼 수 있습니다!
Antonio Ragagnin

답변:


5

펄, 333

$_=<>;$c{$&}++while/./g;@c=sort{$c{$b}<=>$c{$a}}keys%c;$d{$&.$1}++while/.(?=(.))/g;sub f{my$x=shift;if(my$c=pop@$x){for(grep!$_[$_],0..7){my@y = @_;$y[$_]=$c;f([@$x],@y)}}else{for(0..7){$z=$_[$_];$c+=$d{$z.$_}+$d{$_.$z}for@{$a[$_]}}$c<$m?($m=$c,@n=@_):1}}while(@c){$m= ~0;f[splice@c,0,8];push@{$a[$_]},$n[$_]for 0..7}print@$_,$/for@a

다음은 규칙 # 2를 최적화하려는 시도입니다. 위의 의견과 위의 규칙을 고려한 답변 대신 (높은 질문 등급 참조), 나는 여기에 약간의 노력을 기울여야한다고 생각했습니다 ...

규칙 # 2에 대해 최적화되지 않은 솔루션은 최적에서 멀리 떨어진 결과를 생성 할 수 있습니다. 긴 자연 영어 텍스트 (실제로 "Alice in Wonderland"), 사전 처리 (소문자 만) 및 OJW의 답변에서 Perl 스크립트를 확인했습니다. 결과는 다음과 같습니다.

2: ermx
3: tdfz
4: alp
5: oub
6: ick
7: nwv
8: hgj
9: syq

er 혼자 그것을 망치고, 다른 쌍은 결코 같은 열쇠로 끝나지 않아야합니다 ...

Btw zxqjvkbpfmygwculdrshnioate는 해당 텍스트에서 정렬 된 문자, 빈도 오름차순입니다.

우리가 쉬운 방법으로 (-35 보너스를 원할 수도 있음) 해결하고 문자를 하나씩 배치하고 사용 가능한 키를 최소 쌍 단위 수로 선택하면 다음과 같이 끝날 수 있습니다.

slbx
hdmz
nrf
iuj
ogv
awk
tcp
eyq

이 (잘못된) 솔루션에 대한 코드를 여기에 게시하지 않습니다. 예를 들어, c보다 빈번 w하고 우선 순위가 높습니다 . tc( ct) 쌍은 202 + 355에 대해 ac( ca)-43 + 235 보다 분명히 덜 빈번 합니다. 그러나 598 + 88 로 w끝납니다 a. 우리는 쌍으로 끝나야 aw하고 tc더 나은 것하지만, (964 총) actw(635 총). 기타..

따라서 다음 알고리즘은 이미 남아있는 8 개의 문자 (또는 마지막 문자 인 경우 2 개)를 키패드에있는 문자와 비교하여 페어 단위 수를 최소화하도록 배치합니다.

$_=<>;                          # Read STDIN.
$c{$&}++while/./g;              # Count letters (%c hash).
@c=sort{$c{$b}<=>$c{$a}}keys%c; # Sort them by frequency, ascending
$d{$&.$1}++while/.(?=(.))/g;    # (@c array), and count pairs (%d hash).

                                # Next is recursive sub that does the job.
                                # Some CPAN module for permutations
                                # would probably do better...
                                # Arguments are reference to array of what's 
                                # left un-placed of current 8-pack of letters,
sub f{                          # and 8 element list of placed letters
    my$x=shift;                 # (or undefs).
    if(my$c=pop@$x){            # Pop a letter from 8-pack (if anything left),
        for(grep!$_[$_],0..7){  # try placing it on each available key, and 
            my@y = @_;          # call sub again passing updated arguments.
            $y[$_]=$c;
            f([@$x],@y)
        }
    }else{                      # If, OTOH, 8-pack is exhausted, find sum of
        for(0..7){              # pairs count of current permutation (@_) and 
            $z=$_[$_];          # letters placed in previous rounds (8-packs).
                                # @a is "array of arrays" - note, we didn't 
                                # have to initialize it. First "8-pack" will
                                # be placed on empty keypad "automatically".
                                # We re-use undefined (i.e. 0) $c.

            $c+=$d{$z.$_}+$d{$_.$z}for@{$a[$_]}
        }
        $c<$m                   # Is sum for current placement minimal?
            ?($m=$c,@n=@_)      # Then remember this minimum and placement.
            :1
    }
}

while(@c){
    $m= ~0;                         # Initialize "minimum" with large enough 
    f[splice@c,0,8];                # number, then call sub with each 8-pack
                                    # (and empty list of placed letters 
                                    # from current round). On return,
                                    # @n will have optimal arrangement.
    push@{$a[$_]},$n[$_]for 0..7    # Then place it permanently on keypad.
}
print@$_,$/for@a                    # Show us what you've done.

결과는 다음과 같습니다

sdfz
hlmx
nrv
iyp
ogk
acq
twb
euj

나는 ac쌍을 좋아하지 않지만 (The Cat은 문자 중 하나입니다), 그러나 내 코드가 잘못되지 않은 경우 영어에 가장 적합한 문자 배치입니다. 정확히 '골프'노력이 아니라 추악한 작업 솔루션 일뿐입니다.


3

Python3, Montecarlo Time입니다!

이 문제를 해결하기 위해 먼저 기본 키보드에 필요한 "클릭"수를 계산합니다 (초기 :) abc,def,ghi,jkl,mno,pqrs,tuv,wxyz. 그런 다음이 키보드를 수정하여 더 저렴한 지 확인하십시오 (텍스트는 적은 클릭으로 작성됩니다). 이 키보드가 저렴하면 기본 키보드가됩니다. 이 프로세스 1M시간을 반복합니다 .

키보드를 변경하려면 먼저 변경 횟수를 결정합니다 (최대 변경 횟수는 키보드의 총 문자 수입니다). 그런 다음 모든 스위치에 대해 두 개의 버튼과 두 개의 위치를 ​​선택하고 첫 번째 위치에서 두 번째 위치로 문자를 전송합니다.

시간당 최대 스위치 수는 두 개의 완전한 다른 키보드에서 전환해야하는 최소 변경 수이므로 키보드의 문자 수입니다. (한 키보드에서 다른 키보드로 항상 전환 할 수 있기를 바랍니다)

출력 echo "jackdawslovemybigsphinxofquartz" | python .\myscript.py은 다음과 같습니다.

61 ['anb', 'sef', 'hjc', 'iykl', 'odm', 'qgr', 'tuxv', 'wpz']

61주어진 메시지를 작성하기 위해 누른 버튼 수는 어디에 있습니까 ?

문자 (공백 없음 및 코멘트 없음) : 577

나는 그것의 길이를 알고 있지만 나는이 물건에 정말로 익숙하지 않습니다.

from random import *
S=['abc','def','ghi','jkl','mno','pqrs','tuv','wxyz']
def P(L): # perform a switch of the keys of the keyboard:to switch from a given keyboard to another, the maximum number of exchanges is the number of the keys.
    R=randint
    N = len(''.join(L))
    W = randint(1,N)   # decide how many switches to perform
    EL = list(L)
    for i in range(0,W):
        B1=R(0,len(EL)-1)   # decide what buttons are considered in the switch
        B2=R(0,len(EL)-1)
        if len(EL[B1])==0: continue   
        P1=R(0,len(EL[B1])-1)       # decide what letter to switch and where
        if len(EL[B2])==0: P2=0
        else:   P2=R(0,len(EL[B2])-1)
        C1 = EL[B1][P1]     
        EL[B1]=EL[B1].replace(C1,'')
        EL[B2]=EL[B2][:P2]+C1+EL[B2][P2:]
    return EL
def U(L,X): # count how many clicks you need to compose the text X
    S=0
    Z=' '
    for A in X:
        for T in L:
            if A in T and Z not in T: S+=1+T.index(A)
            if A in T and Z in T: S+=3+T.index(A) # if the last character was in the same button..here the penality!
        Z=A
    return S
X=input()
n_iter=10**6
L = list(S)
cc=U(L,X)
print(cc,L)
for i in range(0,n_iter): #do some montecarlo stuff
    cc=U(L,X)
    pl=P(L)
    pc=U(pl,X)
    if(cc>pc):
        L=pl 
        print(pc,L)

LO HOBBIT 로이 알고리즘을 시도하기로 결정한 것이 너무 재밌었습니다 (집에서도 원본이 있습니다!). 그것은 383964문자가 있으며 이들은 내가 찾은 몇 번의 클릭키패드 입니다.

909007 ['abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']
879344 ['abkc', 'def', 'gqhi', 'jl', 'mno', 'rs', 'tupv', 'wxyz']
861867 ['abg', 'def', 'qhyi', 'jcl', 'mno', 'r', 'tupxv', 'swkz']
851364 ['abg', 'e', 'qchi', 'jyl', 'mn', 'dr', 'tupxv', 'sowkfz']
829451 ['ag', 'ef', 'qchi', 'jyl', 'mn', 'dbr', 'tupxv', 'sowkz']
815213 ['amg', 'ef', 'qch', 'ojyl', 'i', 'dbnr', 'tupxv', 'swkz']
805521 ['amg', 'ef', 'ch', 'ojyl', 'qi', 'dbnr', 'tupxv', 'swkz']
773046 ['amg', 'ef', 'ch', 'ojyl', 'qi', 'bnr', 'tupxv', 'dswkz']
759208 ['amg', 'eqf', 'ch', 'ojyl', 'i', 'bnr', 'tupxv', 'dswkz']
746711 ['ag', 'ekq', 'clh', 'sojy', 'bi', 'nmfr', 'tupxv', 'dwz']
743541 ['ag', 'ekq', 'clh', 'sojy', 'bi', 'nmfr', 'tpxv', 'dwuz']
743389 ['ag', 'ekq', 'clh', 'sojy', 'i', 'nmfr', 'tpxbv', 'dwuz']
734431 ['ag', 'ekq', 'lh', 'sjy', 'ci', 'nrf', 'tpxbv', 'dowumz']
705730 ['ag', 'oekq', 'lh', 'sjy', 'ci', 'nrf', 'tpxbv', 'dwumz']
691669 ['ag', 'oekq', 'lh', 'nsjy', 'ic', 'rf', 'tpxbv', 'dwumz']
665866 ['ag', 'hokq', 'el', 'nsjy', 'ic', 'rbf', 'tpxv', 'dwumz']
661610 ['agm', 'hokq', 'e', 'nsj', 'ilc', 'rbf', 'tpyxv', 'dwuz']

따라서이 마지막 키패드는 클릭 측면에서 가장 실용적인 키패드 중 하나라고 주장합니다.


그것이 최적인지 어떻게 알 수 있습니까?
PyRulez

Montecarlo는이 방식으로 작동하지 않습니다. 최적의 솔루션에 더 가깝고 더 가까이 있습니다. 그러나 백만 번 시도해도 솔루션이 변경되지 않으면 최적의 솔루션을 사용하고 있다고 가정하십시오. (또는이 "현지 최소값"에서 충분히 움직이지 않습니다.)
Antonio Ragagnin at 30:14

그렇다면 도전을 위해 대부분의 시간 동안 만 작동해야합니까?
PyRulez

1
@PyRulez 나는 이것이 -35 보너스로 막고 싶었던 가능한 모든 솔루션을 시도하는 경우를 제외하고는 최적의 솔루션을 찾는 것이 쉬운 문제가 아니라는 것을 깨달았습니다.
Flonk

1
흥미로운 방법이지만이 작업이 정확히 그 도메인이 아닐 수도 있습니다. '앨리스'의 경우 기본 키보드에 291613 클릭이 필요합니다. 내 프로그램-195597로 최적화되었습니다. 'Monte Carlo'접근 방식을 사용하면 5 백만 회 이상 반복하여 클릭 수가 207000 회 미만이었습니다. 그리고 글자를 바꾸는 것이 좋습니다. 즉 2x4 + 6x3 레이아웃이 일정하게 유지됩니다.
2846289

2

빈 2-9에 가장 인기있는 캐릭터를 원한다면 Perl은 127 자로 그렇게 할 수 있습니다 ...

foreach(split /\s*/,<>){$x{$_}++}
foreach(sort{$x{$b}<=>$x{$a}}keys %x){$o{$n++%8}.=$_}
for(0..7){printf "%d: %s\n",$_+2,$o{$_}}

같은 것을주는 :

echo "jackdawslovemybigsphinxofquartz" | perl ./keypad.pl
2: ajeb
3: iynz
4: suv
5: ohm
6: wkl
7: rgp
8: xfc
9: dtq

또는 한 줄에 모두 인쇄하여 12자를 제거하십시오.

foreach(split /\s*/,<>){$x{$_}++}
foreach(sort{$x{$b}<=>$x{$a}}keys %x){$o[$n++%8].=$_}
print join",",values@o,"\n";

2
당신은 이것을 100 개의 문자로 쉽게 다듬을 수 있습니다 :$x{$_}++for split/\s*/,<>;map$o{$n++%8}.=$_,sort{$x{$b}<=>$x{$a}}keys%x;print map"$_:".$o{$_-2},2..9
ardnew

1

하스켈, 160-35 = 125

import Data.List
import GHC.Exts
main=interact f where f s=show$transpose$map($sortWith(\x->length$filter(/=x)s)['a'..'z'])[t,t.d,t.d.d,d.d.d];t=take 8;d=drop 8

예:

$ runhaskell % <<< "jackdaws loves my big sphinx of quartz"
["afpy","sgqz","ihr","ojt","bku","clv","dmw","enx"]
$ </usr/share/dict/propernames tr A-Z a-z | runhaskell % 
["atjx","edgq","rhb","nmp","iyv","lcf","ouw","skz"]

이것이 규칙 2에 대해 최적화되지는 않지만 가장 빈번한 문자를 다른 키 에 넣는다 고 주장 할 수 있습니다 .


0

자바 스크립트, 192-35 = 157

반복되는 문자 규칙을 보았습니다. 이것은 그것을 고려하지 않습니다. 그러나 @mniip이 그의 답변에서 언급했듯이 :

이것이 규칙 2에 대해 최적화되지는 않지만 가장 빈번한 문자를 다른 키 에 넣는다 고 주장 할 수 있습니다 .

o={}
a=[]
b=['','','','','','','','']
i=-1
s.split('').forEach(function(x){o[x]=o[x]?o[x]+1:1})
for(x in o)a.push([o[x],x])
a.sort().reverse().forEach(function(x){b[i=(i+1)%8]+=x[1]})
alert(b)

아마도 루비에 있었을 지 모르지만 집에 있지 않고 Internet Explorer (eww)를 사용해야합니다. 그러나 골프 때 골프에 끔찍한 언어를 사용하면 때로는 재미 있습니다! ;)

샘플 출력 (입력 용) :

avlc,sukb,otj,irh,zqg,ypf,xne,wmd

JS에는 STDIN이 없으므로 프로그램은 입력이 variable에 저장되어 있다고 가정합니다 s.


당신은뿐만 아니라 염두에두고 최적화되어 있습니다 : "같은 버튼을 사용하여 입력하는 두 글자를 쓰는 것은 추가로 2 버튼 누름이 필요합니다"
디지털 외상

다시 : 마지막 편집. 나는 출력 'abcdefghia'이 정확히 최적이 아니라고 생각합니다 .
user2846289

@VadimR "입력 텍스트가 상당히 크고 모든 문자가 적어도 한 번 이상 있다고 가정 할 수 있습니다"
Doorknob

알아. 'azbcdefghizjklmnopqzrstuvwxyz'
user2846289

1
b=['','','','','','','','']b=[x='',x,x,x,x,x,x,x], s.split('')s.split(x)o[x]=o[x]?o[x]+1:1에 최적화 할 수 있습니다 o[x]=-~o[x].
칫솔

0

파이썬 (119-35 = 84) :

문자열이 변수 a이고 소문자 만 포함한다고 가정합니다.

for h in range(8): print h+2,zip(*sorted([(__import__("collections").Counter(a)[d],d) for d in set(a)])[::-1])[1][h::8]

언 골프 :

import collections

#a="jackdawslovemybigsphinxofquartz"
a=__import__("string").lowercase

b=collections.Counter(a)

c=set(a)

d=[(b[d],d) for d in c]

e=sorted(d)

f=e[::-1]

g=zip(*f)[1]

for h in range(8): print h+2,g[h::8]

PYG (76-35 = 41) :

Aaah, 우리는 거대한 수입품을 버릴 수 있습니다. 다시 말하지만, 이것은 제거 된 문자열이 a에 있다고 가정합니다.

for h in R(8): print h+2,Z(*S([(CC(a)[d],d) for d in Se(a)])[::-1])[1][h::8]
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.