Niedawno pokaza艂em jak z bazy s艂贸w j臋zyka polskiego powyci膮ga膰 s艂owa z unikalnymi ko艅c贸wkami. Dzisiaj kontynuuj臋 zabaw臋 z t膮 sam膮 baz膮 s艂贸w, tym razem jednak poka偶臋 jak znale藕膰 wszystkie permutacje siedmioliterowe nale偶膮ce do s艂ownika. Innymi s艂owy, taki dopalacz do gry w Scrabble / Literaki, pomagaj膮cy znale藕膰 wszystkie siedmioliterowe (a wi臋c wysoko punktowane) s艂owa z danego zestawu liter.
Dla uproszczenia przyj膮艂em brak myde艂 (czyli pustych p艂ytek zwanych te偶 "blankami" lub "jokerami").
W pierwszej kolejno艣ci nale偶y przygotowa膰 sobie baz臋 ze s艂贸wkami, wed艂ug zalece艅 z tego wpisu. Nast臋pnie tworzymy pust膮 tabel臋, do kt贸rej b臋dziemy generowa膰 wszystkie permutacje siedmioliterowe (b臋dzie ich zawsze 5040). Tablica nazywa si臋 [permutacje] i tworzymy j膮 o tak:
CREATE TABLE permutacje(s char(7) NOT NULL);
Nast臋pnie deklarujemy i inicjalizujemy zmienn膮 reprezentuj膮c膮 s艂owo, kt贸re b臋dziemy permutowa膰:
DECLARE @s VARCHAR(7)= 'niemowa';
W kolejnym kroku zerujemy tabel臋 z permutacjami:
TRUNCATE TABLE permutacje;
No i teraz samo g臋ste, czyli wype艂niamy tabel臋 [permutacje] wszystkimi siedmioliterowymi permutacjami liter s艂owa 'niemowa':
WITH
n AS
(SELECT 1 AS liczba UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7),
perm AS
(SELECT
CAST(SUBSTRING(@s, liczba, 1) AS VARCHAR(7)) AS anagram,
CAST('.'+CAST(liczba AS CHAR(1))+'.' AS VARCHAR(13)) AS uklad,
CAST(1 AS INT) AS poziom
FROM n
UNION ALL
SELECT
CAST(anagram+SUBSTRING(@s, liczba, 1) AS VARCHAR(7)),
CAST(uklad+CAST(liczba AS CHAR(1))+'.' AS VARCHAR(13)),
p.poziom + 1
FROM
perm p
JOIN n
ON p.uklad NOT LIKE '%.'+CAST(liczba AS CHAR(1))+'.%'
AND p.poziom < 7
)
INSERT permutacje
SELECT DISTINCT anagram
FROM perm
WHERE poziom = 7
ORDER BY anagram;
W ostatnim kroku wy艣wietlamy wynik, czyli te permutacje, kt贸re s膮 s艂owami j臋zyka polskiego:
SELECT slowo FROM words JOIN permutacje ON words.slowo=permutacje.s;
Ca艂o艣膰 wykonuje si臋 bardzo szybko (poni偶ej jednej sekundy).
Wyniki: aminowe, emanowi, manowie, miewano, moweina, namowie, niemowa.
Je偶eli kt贸rykolwiek z Czytelnik贸w dotar艂 a偶 do tego miejsca bez b贸lu g艂owy, a jeszcze, nie daj Billu, zrozumia艂 spos贸b generowania permutacji, zapraszam do kolejnego wysi艂ku umys艂owego: jak do powy偶szej logiki doda膰 blanki? Przypominam, 偶e zar贸wno w Scrabble (TM) jak i w Literakach mo偶liwe s膮 maksymalnie dwa blanki.
je艣li blakni = char(32), to @s='nie mowa', rozszerzenie pól [zamian 7 na 8]. Od varcharów odchodzi膰 nie trzeba, bo blanki na ko艅cu si臋 nie licz膮.
Aczkolwiek nie wiem, czy ostatni join tego nie wytnie.
Nie mo偶e by膰 osiem – na stojaku zawsze jest siedem liter (z czego maksymalnie dwa blanki). W zale偶no艣ci od tego czy jest jeden blank czy dwa, ilo艣膰 mo偶liwych permutacji ro艣nie 32-krotnie lub 1024-krotnie (a wi臋c w najgorszym przypadku mamy troch臋 ponad 5 milionów permutacji).
Mam ju偶 dzia艂aj膮ce rozwi膮zanie, ale strasznie si臋 艣limaczy. 22 sekundy na wyszukanie wszystkich "legalnych" s艂ówek z dwoma blankami i jakie艣 3 sekundy z jednym.
Nie gram w Scramble czy inne sudoku z ca艂kami [jak mówi Kowalski], wi臋c musisz bardziej 艂opatologicznie wy艂o偶y膰 problem. Blank mo偶e zast膮pi膰 dowoln膮 liter臋?
Je艣li tak, to wynik bez blanków potraktowa艂bym jako materia艂 wej艣ciowy do kolejnej p臋tli a tam [x:1-7; dla ka偶dego z wyników]
SELECT slowo FROM words
where words.slowo like
permutacje ON like left(permutacje.s,x)+'_'+right(permutacje.s,6-x);
Zgrabnie. A co w przypadku dwóch blanków?
Nie chce mi sie myslec.
Ale mog臋 Ci podac sposób na siedem blznków 馃榾