글자 맞추기에서 한 글자의 백에서 단어를 그릴 수없는 확률


27

타일 이있는 가방이 있고 각각에 글자 가있는 것으로 가정 해 봅시다 . 문자 'A' 가있는 타일, 'B'가있는 등, '와일드 카드'타일이 있습니다 ( n = n_A + n_B + \ ldots + n_Z + n_ *가 있습니다 ). 한정된 수의 단어가있는 사전이 있다고 가정합니다. 당신은 선택 K 교체없이 가방에서 타일을. 선택한 k 타일이 주어진 경우 사전에서 0 단어를 형성 할 확률을 어떻게 계산 (또는 추정) 하시겠습니까?n A n B n n = n A + n B + + n Z + n k knnAnBnn=nA+nB++nZ+nkk

Scrabble (TM)에 익숙하지 않은 사용자는 와일드 카드 문자를 사용하여 모든 문자를 일치시킬 수 있습니다. 따라서 [ BOOT ] 라는 단어 는 타일 'B', '*', 'O', 'T'로 '맞춤법'이 될 수 있습니다.

문제의 규모를 이해하기 위해 k 는 7과 같이 작고 , n 은 약 100이며, 사전에는 k 이하 의 약 100,000 단어가 포함되어 있습니다 .

편집 : '단어'를 형성한다는 것은 길이가 k 이하인 단어를 의미합니다 k. 따라서 단어 [ A ]가 사전에 있다면, 가방에서 하나의 'A'조차도 그려서 '단어'를 형성 한 것입니다. 사전에 길이가 1 인 단어가 있다고 가정하면 와일드 카드 문제는 근본적으로 단순화됩니다. 존재하는 경우, 임의의 와일드 카드 드로우는 자동으로 길이 1 단어와 일치 할 수 있으므로 와일드 카드가없는 경우에 집중할 수 있습니다. 따라서 더 미끄러운 형태의 문제는 사전에 1 글자 단어가 없습니다.

또한 가방에서 글자가 나오는 순서는 중요하지 않다고 명시 적으로 언급해야합니다. 단어의 '정확한'순서로 글자를 그릴 필요는 없습니다.


' 교체 하지 않고 픽 k 타일'이 아니어야합니까 ? 매우 흥미로운 질문입니다.

죄송합니다. 실제로해야합니다.
shabbychef

내가 기억하는 한, 글자 맞추기는 한 글자의 단어를 허용하지 않으므로 적어도 문제의 일부가 해결됩니다.;)
nico

1
@nico 좋은 지적이지만, 이것은 게임 중반에만 해당된다고 생각합니다. 1 글자는 글자를 재생하는 데 필요하지 않거나 보드의 어느 곳에 나 하나의 글자를 배치 할 수 있습니다. 그러나 나는 개막 움직임을 생각하고 있었다. 실제로 스크 러블에 익숙한 사람들은 "첫 번째 플레이어가 합격 할 확률은 얼마입니까?"라는 질문을 간단하게 언급 할 수 있습니다.
shabbychef

@nico 감사합니다. 이론적으로 유사한 문제는 가능한 모든 두 글자 조합을 단어로 포함하는 사전과 관련이 있습니다.이 경우 2 개 이상의 문자를 가진 손은 자동으로 단어를 포함합니다. 게임 중반에 대한 @shabbychef의 의견은 게임 중 7 개의 문자 외에 단어 부분 (접두사, 접미사 및 중간 부분)을 사용할 수 있기 때문에 원래 질문이 대부분의 글자 맞추기와 관련성이 없음을 보여줍니다. 손. 이것은 단어를 만들 수있는 기회를 크게 증가시킵니다.
whuber

답변:


14

이것은 @vqv가이 글에 올린 멋진 작품에 대한 (긴!) 주석입니다. 명확한 답을 얻는 것을 목표로합니다. 그는 사전을 단순화하기 위해 열심히 노력했습니다. 남아있는 것은 그것을 최대한 활용하는 것입니다. 그의 결과는 무차별 대입 솔루션이 실현 가능 하다는 것을 암시합니다 . 와일드 카드를 포함하여 결국 7 개의 문자로 만들 수 있는 최대 단어가 있으며 그 중 1/10000 미만 (약 백만 개)으로 표시됩니다. 유효한 단어를 포함시키지 마십시오. 277=10,460,353,203

첫 번째 단계는 와일드 카드 문자 "?"로 최소 사전을 보강하는 것입니다. 22 개의 글자가 두 글자로 표시됩니다 (c, q, v, z 제외). 22 개의 문자에 와일드 카드를 연결하여 사전에 추가합니다 : {a ?, b ?, d ?, ..., y?}가 이제 입력되었습니다. 마찬가지로 최소 3 글자 단어를 검사하여 추가 단어를 생성 할 수 있습니다. 사전에 나타납니다. 마지막으로 "??"를 추가합니다 사전에. 반복되는 결과를 제거한 후 최소 342 개의 단어가 포함됩니다.

아주 적은 양의 인코딩을 실제로 사용하는 우아한 방법은 이 문제를 대수적으로 보는 것 입니다. 정렬되지 않은 문자 집합으로 간주되는 단어는 단지 일식입니다. 예를 들어, "spats"는 단수 입니다. 따라서 사전은 모노 미아 모음입니다. 마치aps2t

{a2,ab,ad,...,ozψ,wxψ,ψ2}

(혼동을 피하기 위해 와일드 카드 문자에 를 썼습니다 ).ψ

해당 단어가 랙을 나누는 경우에만 유효한 단어가 랙에 포함됩니다.

더 추상적이지만 매우 강력한 방법은 사전 이 다항식 링 R = Z [ a , b , , z , ψ ] 에서 이상적인 을 생성하고 유효한 단어가있는 랙이 몫에서 0이된다는 것입니다. 링 R은 / 나는 , 반면에 올바른 단어가없는 랙 몫에 제로 남아있다. 우리가 R 에서 모든 랙의 합을 형성 하고이 몫 고리에서 계산하면 단어가없는 랙의 수는 몫의 고유 한 모노 수의 수와 같습니다.IR=Z[a,b,,z,ψ]R/IR

또한 의 모든 랙의 합계 는 간단합니다. α = a + b + + z + ψ를 알파벳의 모든 문자의 합 이라고합시다 . α 7 에는 각 랙마다 하나의 모노가 포함되어 있습니다. (추가 보너스로서, 계수는 각 랙을 구성 할 수있는 방법의 수를 계산하여 원하는 경우 확률을 계산할 수 있습니다.)Rα=a+b++z+ψα7

간단한 예 (이것이 어떻게 작동하는지보기 위해), (a) 와일드 카드를 사용하지 않고 (b) "a"에서 "x"까지의 모든 문자를 단어로 간주한다고 가정하십시오. 그런 다음 단어를 만들 수없는 가능한 랙은 모두 y와 z로 구성되어야합니다. 우리는 한 번에 한 단계 씩 { a , b , c , , x }에 의해 생성 된 이상을 모듈로 계산합니다 .α=(a+b+c++x+y+z)7{a,b,c,,x}

α0=1α1=에이++기음++엑스+와이+와이+모드나는α2(와이+)(에이+++와이+)(와이+)2모드나는α7(와이+)6(에이+++와이+)(와이+)7모드나는.

우리는 최종 답변에서 비 워드 랙을 얻는 기회를 읽을 수 : 각 계수는 해당 랙을 그리는 방법을 계산합니다. 예를 들어, y의 계수 때문에 2 개의 y와 5 개의 z를 그리는 21 가지 방법 (26 ^ 7 개 중) 이 있습니다.y7+7y6z+21y5z2+35y4z3+35y3z4+21y2z5+7yz6+z7 21과 같습니다.y2z5

기초 계산에서 이것이 정답이라는 것이 분명합니다. 요점은이 절차가 사전의 내용에 관계없이 작동한다는 것입니다.

각 단계에서 이상적인 전력 모듈로 감소가 계산을 줄이는 방법에 주목하십시오. 이것이 바로이 접근법에 의해 드러난 바로 가기입니다. (예시)

다항식 대수 시스템은 이러한 계산을 구현합니다 . 예를 들어 Mathematica 코드는 다음과 같습니다.

alphabet =  a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + 
            p + q + r + s + t + u + v + w + x + y + z + \[Psi];
dictionary = {a^2, a b, a d, a e, ..., w z \[Psi], \[Psi]^2};
next[pp_] := PolynomialMod[pp alphabet, dictionary];
nonwords = Nest[next, 1, 7];
Length[nonwords]

(사전은 @vqv의 min.dict에서 간단하게 구성 할 수 있습니다. 원하는 경우 직접 지정할 수있을 정도로 짧다는 것을 나타내는 줄을 여기에 넣습니다.)

10 분의 계산 시간이 걸리는 출력은 577958입니다. ( NB 이 메시지의 이전 버전에서 나는 사전을 준비하는 데 약간의 실수를했고 577940을 얻었습니다. 나는 현재 원하는 것을 반영하도록 텍스트를 편집했습니다. 정확한 결과!) 예상했던 백만 개 정도의 작은 값이지만 같은 크기입니다.

그러한 랙을 얻을 가능성 을 계산하려면 랙을 그릴 수있는 방법의 수를 고려해야합니다. 예제에서 보았 듯이 이것은 계수가 것과 같습니다 . 도면의 기회 일부 이러한 랙은 1과 동일 쉽게 모든 문자를 설정하여 볼 모든 계수의 합이다 :α7

nonwords /. (# -> 1) & /@ (List @@ alphabet)

정답은 1066056120으로, 유효한 단어를 만들 수없는 랙을 그릴 때 10.1914 %의 확률을 제공합니다 (모든 문자가 똑같이 가능할 경우).

글자의 확률이 다를 경우 각 글자를 그릴 가능성으로 바꾸십시오.

tiles = {9, 2, 2, 4, 12, 2, 3, 2, 9, 1, 1, 4, 2, 6, 8, 2, 1, 6, 4, 6, 
         4, 2, 2, 1, 2, 1, 2};
chances = tiles / (Plus @@ tiles);
nonwords /. (Transpose[{List @@ alphabet, chances}] /. {a_, b_} -> a -> b)

출력은 1.079877553303 %이며 정확한 답변입니다 ( 대체 모델을 사용 하더라도 교체 하여 그리기 ). 다시 찾고, 그것은 일을하기 위해 데이터 (알파벳, 사전 및 알파벳 주파수) 만 세 줄을 입력 할 네 줄을했다 :의 다음 동력 인출하는 방법에 대해 설명 모듈 I를 , 재귀 7 전원을, 그리고 대체 글자의 확률.αI


+1 사전에 인접한 다음 다시 최소화하는 것이 영리한 생각입니다. 대수는 저 너머이지만 초 지오메트리가 아닌 다항식 확률을 계산하는 것처럼 느낍니다. 확률 그래서 샘플링입니다 으로 교체. 나는 이것이 1.08 %의 답이 나의 예상 0.4 %보다 훨씬 더 큰 이유를 설명한다고 생각합니다. 교체없이 샘플링을 처리하기 위해 접근 방식을 수정하는 방법이 있습니까?
vqv

2
@vqv 예. 이제 우리는 단어가없는 50 만 개 정도의 랙 목록을 가지게되었으므로 (마지막 두 줄의 코드를 변경하여) 각 랙의 기회를 계산하고 (교체하지 않고) 초 거시 결과를 얻는 것이 간단합니다. 정확한 답변은 349870667877/80678106432000 = 0.43366 % 입니다. N = 100K 시험에서는 SE가 0.021 %이므로 답은 0.38 %와 0.49 % (양면 99 % CI) 사이 여야합니다. 우리의 답변에 동의합니다!
whuber

@whuber WWF (Words With Friends) 타일 분포를 사용하여 계산을 실행할 수 있습니까? 내 추정치 0.4 %는 WWF 사전 및 WWF 타일 분포를 기반으로합니다. WWF 사전과 함께 스크래블 타일 배포판을 사용하고 있다고 생각합니다.
vqv

죄송합니다. 정확한 답은 실제로 349870675899입니다 (사전 오류로 인해 8022를 벗어났습니다). 다행히도 실질적인 차이는 없습니다.
whuber

@vqv 다양한 타일 배포판에 익숙하지 않습니다. 나는 당신의 코드에서 직접 내 것을 복사했습니다 (그리고 나는 사전을 사용했습니다 : :)). 당신의 분포를 의미하는 경우 osxreality.com/2010/01/01/...을 , 그때 얻을 1.15444 % (교체 포함), 0.43366 % (교체없이)를. 두 번째 숫자는 실제로 8 번째 유효 숫자에서 스크래블 주파수와 다릅니다.
whuber

14

글자 맞추기와 그 변형에 유효한 단어가 포함되지 않은 랙을 그리는 것은 매우 어렵습니다. 아래는 초기 7 타일 랙에 유효한 단어가 포함되지 않을 확률을 추정하기 위해 작성한 R 프로그램입니다. 그것은 몬테 카를로 접근법과 친구와 함께하는 단어 사전을 사용합니다 (공식적인 글자 맞추기 사전을 쉬운 형식으로 찾을 수 없었습니다). 각 시험판은 7 타일 랙을 그린 다음 랙에 유효한 단어가 포함되어 있는지 확인합니다.

최소 단어

랙에 유효한 단어가 포함되어 있는지 확인하기 위해 전체 사전을 스캔 할 필요는 없습니다. 최소한의 단어 로 구성된 최소한의 사전 을 스캔 하면됩니다. 단어에 하위 단어로 다른 단어가 포함되어 있지 않으면 단어가 최소화됩니다. 예를 들어 'em'은 최소한의 단어입니다. '빈'은 아닙니다. 요점은 랙에 단어 x가 포함 된 경우 x의 하위 집합도 포함해야한다는 것 입니다. 다시 말해, 랙에는 최소 단어가 포함되어 있지 않으면 단어가 포함되지 않습니다. 운 좋게도 어휘집의 대부분의 단어는 최소가 아니므로 제거 할 수 있습니다. 순열 등가 단어를 병합 할 수도 있습니다. 나는 친구들과 함께하는 단어 사전을 172,820에서 201 개의 최소 단어로 줄일 수있었습니다.

랙과 단어를 문자의 분포로 취급하여 와일드 카드를 쉽게 처리 할 수 ​​있습니다. 한 분포에서 다른 분포를 빼서 랙에 단어가 포함되어 있는지 확인합니다. 이것은 랙에서 누락 된 각 문자의 수를 제공합니다. 그 수의 합이 경우 와일드 카드의 개수는, 그 단어는 랙이다.

몬테 카를로 접근법의 유일한 문제는 우리가 관심을 갖는 사건이 매우 드물다는 것입니다. 따라서 충분히 작은 표준 오차로 추정값을 얻으려면 많은 시도가 필요합니다. 나는 시험으로 내 프로그램을 (바닥에 붙여) 실행 했으며 초기 랙에 유효한 단어가 포함되어 있지 않을 확률은 0.004입니다 . 해당 추정치의 추정 표준 오차는 0.0002입니다. 어휘집 다운로드를 포함하여 Mac Pro에서 실행하는 데 몇 분 밖에 걸리지 않았습니다.N=100,000

누군가가 효율적인 정확한 알고리즘을 만들 수 있는지 알고 싶습니다. 포함 제외에 기반한 순진한 접근 방식은 조합 폭발이 수반되는 것처럼 보입니다.

포함 제외

나는 이것이 나쁜 해결책이라고 생각하지만, 여기에 불완전한 스케치가 있습니다. 원칙적으로 계산을 수행하는 프로그램을 작성할 수 있지만 사양은 비참합니다.

계산할 확률은 우측의 확률 내부 이벤트가 이벤트의 조합이다 : P ( K 랙 -tile 단어를 포함 ) = P ( X M이 { k는 -tile 랙 포함하는  X } ) , M

P(k-tile rack does not contain a word)=1P(k-tile rack contains a word).
P(k-tile rack contains a word)=P(xM{k-tile rack contains x}),
M최소한의 어휘입니다. 포함 제외 수식을 사용하여 확장 할 수 있습니다. 그것은 위의 사건들의 가능한 모든 교차점을 고려하는 것을 포함합니다. 하자 의 힘 세트 나타내는 M 의 가능한 모든 부분 집합의 예 세트 M을 . 그때 P(M)MM
P(k-tile rack contains a word)=P(xM{k-tile rack contains x})=j=1|M|(1)j1SP(M):|S|=jP(xS{k-tile rack contains x})


xS{k-tile rack contains x}
S

그때

P(xS{k-tile rack contains x})=w=0nP(xS{k-tile rack contains x}|k-tile rack contains w wildcards)×P(k-tile rack contains w wildcards).

I'm going to stop here, because the expansions are tortuous to write out and not at all enlightening. It's easier to write a computer program to do it. But by now you should see that the inclusion-exclusion approach is intractable. It involves 2|M| terms, each of which is also very complicated. For the lexicon I considered above 2|M|3.2×1060.

Scanning all possible racks

I think this is computationally easier, because there are fewer possible racks than possible subsets of minimal words. We successively reduce the set of possible k-tile racks until we get the set of racks which contain no words. For Scrabble (or Words With Friends) the number of possible 7-tile racks is in the tens of billions. Counting the number of those that do not contain a possible word should be doable with a few dozen lines of R code. But I think you should be able to do better than just enumerating all possible racks. For instance, 'aa' is a minimal word. That immediately eliminates all racks containing more than one 'a’. You can repeat with other words. Memory shouldn’t be an issue for modern computers. A 7-tile Scrabble rack requires fewer than 7 bytes of storage. At worst we would use a few gigabytes to store all possible racks, but I don’t think that’s a good idea either. Someone may want to think more about this.

Monte Carlo R program

# 
#  scrabble.R
#  
#  Created by Vincent Vu on 2011-01-07.
#  Copyright 2011 Vincent Vu. All rights reserved.
# 

# The Words With Friends lexicon
# http://code.google.com/p/dotnetperls-controls/downloads/detail?name=enable1.txt&can=2&q=
url <- 'http://dotnetperls-controls.googlecode.com/files/enable1.txt'
lexicon <- scan(url, what=character())

# Words With Friends
letters <- c(unlist(strsplit('abcdefghijklmnopqrstuvwxyz', NULL)), '?')
tiles <- c(9, 2, 2, 5, 13, 2, 3, 4, 8, 1, 1, 4, 2, 5, 8, 2, 1, 6, 5, 7, 4, 
           2, 2, 1, 2, 1, 2)
names(tiles) <- letters

# Scrabble
# tiles <- c(9, 2, 2, 4, 12, 2, 3, 2, 9, 1, 1, 4, 2, 6, 8, 2, 1, 6, 4, 6, 4, 
#            2, 2, 1, 2, 1, 2)


# Reduce to permutation equivalent words
sort.letters.in.words <- function(x) {
  sapply(lapply(strsplit(x, NULL), sort), paste, collapse='')
}

min.dict <- unique(sort.letters.in.words(lexicon))
min.dict.length <- nchar(min.dict)

# Find all minimal words of length k by elimination
# This is held constant across iterations:
#   All words in min.dict contain no other words of length k or smaller
k <- 1
while(k < max(min.dict.length))
{
  # List all k-letter words in min.dict
  k.letter.words <- min.dict[min.dict.length == k]

  # Find words in min.dict of length > k that contain a k-letter word
  for(w in k.letter.words)
  {
    # Create a regexp pattern
    makepattern <- function(x) {
      paste('.*', paste(unlist(strsplit(x, NULL)), '.*', sep='', collapse=''), 
            sep='')
    }
    p <- paste('.*', 
               paste(unlist(strsplit(w, NULL)), 
                     '.*', sep='', collapse=''), 
               sep='')

    # Eliminate words of length > k that are not minimal
    eliminate <- grepl(p, min.dict) & min.dict.length > k
    min.dict <- min.dict[!eliminate]
    min.dict.length <- min.dict.length[!eliminate]
  }
  k <- k + 1
}

# Converts a word into a letter distribution
letter.dist <- function(w, l=letters) {
  d <- lapply(strsplit(w, NULL), factor, levels=l)
  names(d) <- w
  d <- lapply(d, table)
  return(d)
}

# Sample N racks of k tiles
N <- 1e5
k <- 7
rack <- replicate(N,
                  paste(sample(names(tiles), size=k, prob=tiles), 
                        collapse=''))

contains.word <- function(rack.dist, lex.dist)
{
  # For each word in the lexicon, subtract the rack distribution from the 
  # letter distribution of the word.  Positive results correspond to the 
  # number of each letter that the rack is missing.
  y <- sweep(lex.dist, 1, rack.dist)

  # If the total number of missing letters is smaller than the number of 
  # wildcards in the rack, then the rack contains that word
  any(colSums(pmax(y,0)) <= rack.dist[names(rack.dist) == '?'])
}

# Convert rack and min.dict into letter distributions
min.dict.dist <- letter.dist(min.dict)
min.dict.dist <- do.call(cbind, min.dict.dist)
rack.dist <- letter.dist(rack, l=letters)

# Determine if each rack contains a valid word
x <- sapply(rack.dist, contains.word, lex.dist=min.dict.dist)

message("Estimate (and SE) of probability of no words based on ", 
        N, " trials:")
message(signif(1-mean(x)), " (", signif(sd(x) / sqrt(N)), ")")

와우 .. 아주 좋은 후속 조치입니다.
매트 파커

나는 그것이 201 단어로 줄어든 것에 놀랐습니다. 첫 번째 단어가 재생되었지만 하우스 규칙은 'I'와 'A'를 단어로 받아들이므로 최소 단어 수를 더 줄일 수 있습니다. 나는 누군가가 포함 제외 분석을 망칠 것을 기대하고 있었는데, 이것은 꽤 털이 있어야합니다 ...
shabbychef

@shabbychef There are no 1-letter words in the lexicon. Most minimal words are 2- and 3-letter words. Here is the full distribution of minimal word lengths: 2: 73, 3:86, 4:31, 5:9, 6:2. The 6-letter words are: GLYCYL and SYZYGY.
vqv

@shabbychef I updated my answer to include a sketch of an exact inclusion-exclusion approach. It is worse than hairy.
vqv

great work! I love that this question, which could be posed as one sentence (to those with sufficient background), has brought out monte carlo, inclusion-exclusion, DAGs, searching trees, polynomial algebra, and that your simulations are confirmed by the theoretical of @whuber. cheers!
shabbychef

7

Srikant is right: a Monte Carlo study is the way to go. There are two reasons. First, the answer depends strongly on the structure of the dictionary. Two extremes are (1) the dictionary contains every possible single-letter word. In this case, the chance of not making a word in a draw of 1 or more letters is zero. (2) The dictionary contains only words formed out of a single letter (e.g., "a", "aa", "aaa", etc.). The chance of not making a word in a draw of k letters is easily determined and obviously is nonzero. Any definite closed-form answer would have to incorporate the entire dictionary structure and would be a truly awful and long formula.

The second reason is that MC indeed is feasible: you just have to do it right. The preceding paragraph provides a clue: don't just generate words at random and look them up; instead, analyze the dictionary first and exploit its structure.

One way represents the words in the dictionary as a tree. The tree is rooted at the empty symbol and branches on each letter all the way down; its leaves are (of course) the words themselves. However, we can also insert all nontrivial permutations of every word into the tree, too (up to k!1 of them for each word). This can be done efficiently because one does not have to store all those permutations; only the edges in the tree need to be added. The leaves remain the same. In fact, this can be simplified further by insisting that the tree be followed in alphabetical order.

In other words, to determine whether a multiset of k characters is in the dictionary, first arrange the elements into sorted order, then look for this sorted "word" in a tree constructed from the sorted representatives of the words in the original dictionary. This will actually be smaller than the original tree because it merges all sets of words that are sort-equivalent, such as {stop, post, pots, opts, spot}. In fact, in an English dictionary this class of words would never be reached anyway because "so" would be found first. Let's see this in action. The sorted multiset is "opst"; the "o" would branch to all words containing only the letters {o, p, ..., z}, the "p" would branch to all words containing only {o, p, ..., z} and at most one "o", and finally the "s" would branch to the leaf "so"! (I have assumed that none of the plausible candidates "o", "op", "po", "ops", or "pos" are in the dictionary.)

A modification is needed to handle wildcards: I'll let the programmer types among you think about that. It won't increase the dictionary size (it should decrease it, in fact); it will slightly slow down the tree traversal, but without changing it in any fundamental way. In any dictionary that contains a single-letter word, like English ("a", "i"), there is no complication: the presence of a wildcard means you can form a word! (This hints that the original question might not be as interesting as it sounds.)

The upshot is that a single dictionary lookup requires (a) sorting a k-letter multiset and (b) traversing no more than k edges of a tree. The running time is O(klog(k)). If you cleverly generate random multisets in sorted order (I can think of several efficient ways to do this), the running time reduces to O(k). Multiply this by the number of iterations to get the total running time.

I bet you could conduct this study with a real Scrabble set and a million iterations in a matter of seconds.


@whuber The tree is a neat idea (upvote for that idea) but would it not require lot of memory? I guess it depends on how diverse the dictionary is but I am guessing a reasonably diverse dictionary would require many trees For example, the 'b' tree would start with the letter 'b' instead of 'a' for all those words which do not have 'a' in them. Similarly, the 'c' tree would start with the letter 'c' for those words which do not have 'a' and 'b' but have 'c'. My proposed direct approach seems simpler as it requires a one-time traversal of all the words in the dictionary, no?

1
@Srikant: The tree would likely require far less RAM than caching the entire dictionary to begin with. Are you really concerned about a few megabytes of RAM, anyway? BTW, there's only one tree, not many: they are all rooted at the empty word. Your approach, as I have understood it, requires multiple searches of the dictionary (up to 7! of them) on every iteration, making it impracticable as @shabbychef fears. It would help if you could elaborate on the algorithm you have in mind where you write "see if you can form a word": that hides a lot of important details!
whuber

@whuber: I realized the fact that there is only one tree after I posted my comment. Reg my approach- I agree that my monte carlo proposal is fuzzy and your answer fleshes out how one can actually implement monte carlo in this setting. I actually meant that the direct approach (see my answer) may actually be simpler as that approach requires a one-time operation on the dictionary unlike a monte carlo which requires several thousands of iterations on the tree. Just wondering on the relative merits of the approaches.

@Srikant I refrained from commenting on your direct approach because it I suspect it gets the wrong answers. It does not appear to account for the dictionary structure: that is, the subset relationships among words. For instance, would your formula get the correct answer of zero for all dictionaries that contain all the possible one-letter words?
whuber

@whuber hmmm good point. Perhaps, I am answering the wrong question!

2

Monte Carlo Approach

The quick and dirty approach is to do a monte carlo study. Draw k tiles m times and for each draw of k tiles see if you can form a word. Denote the number of times you could form a word by mw. The desired probability would be:

1mwm

Direct Approach

Let the number of words in the dictionary be given by S. Let ts be the number of ways in which we can form the sth word. Let the number of letters needed by the sth word be denoted by ma,mb,...,mz (i.e., the sth word needs ma number of 'a' letters etc). Denote the number of words we can form with all tiles by N.

N=(nk)

and

ts=(nama)(nbmb)...(nzmz)

(Including the impact of wildcard tiles is a bit trickier. I will defer that issue for now.)

Thus, the desired probability is:

1stsN

The quick and dirty approach may not be so quick! The dictionary may contain 100,000 words, and the search for a match of the given tiles could be a coding disaster.
shabbychef

@shabbychef This is something well done to suit spell checkers. See for instance n3labs.com/pdf/lexicon-squeeze.pdf

@shabbychef Reg monte-carlo- if the dictionary is sorted a match should be fairly quick no? In any case, the direct approach that I outlined earlier was flawed. I fixed it. The problem in my earlier solution was that the same word can be formed multiple ways (e.g., 'bat', 'b*t' etc).

1
@shabbychef On further reflection, I agree with you that the monte carlo approach will not work. One issue is that you need to figure out which words you can actually form with the k tiles and the second one is that you can form multiple words with the k tiles. Calculating these combinations from k tiles is probably not that easy.

1
@Srikant 감사합니다. 당신의 공식은 단어를 형성하기 위해 k 개의 문자를 모두 사용해야한다고 가정하는 것처럼 보이지만 OP가 요구하는 것은 아닙니다. 어쨌든 Scrabble이 재생되는 방식은 아닙니다. 암시 적으로 가정하면 올바른 길을 가고 있지만 알고리즘을 수정해야합니다. 사전에서 서로 치환되는 단어에 대한 계산을 반복해서는 안됩니다. 예를 들어 수식에서 t_ {stop} 및 t_ {post}를 모두 빼면 안됩니다. (이것은 구현하기 쉬운 수정입니다.)
whuber
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.