Permutacje – wersja z blankami

Jeżeli kogoś zainteresował poprzedni wpis o wyszukiwaniu wszystkich słówek polskich z zadanego zestawu siedmiu liter, dziś dorzucam wisienkę do tego tortu. Wisienka jest niestety spasiona jak wieprz, ale co mi tam.

Udało mi się mianowicie dodać możliwość używania blanków (blank zastępuje dowolną literę). Blanki podajemy w postaci znaków zapytania, może ich być maksymalnie dwa.

Początek skryptu jest w zasadzie bez zmian w stosunku do poprzedniej wersji. Dodałem tabelę z literami alfabetu (przyda się później do wygenerowania wszystkich podstawień blanków). Dodałem dwie zmienne liczbowe @qmpos1 i @qmpos2 (reprezentujące pozycje, na których w zadanym zestawie liter pojawiają się blanki). Gęste zaczyna się po początkowym wypełnieniu tabeli [permutacje]. Najpierw znajdujemy pierwszy i drugi znak zapytania, zamieniamy pierwszy na # a drugi na $ (potrzebujemy odróżnić jeden ? od drugiego przy generowaniu wszystkich kombinacji w następnych krokach).

Następnie, w zależności od ilości znaków zapytania, generujemy dodatkowe rekordy do tabeli [permutacje] – w przypadku dwóch pytajników używamy iloczynu kartezjańskiego z dwóch instancji tabeli [alfabet].

Na koniec usuwamy wpisy z # lub $ (o ile takowe istnieją) i generujemy listę wyników (w podobny sposób jak poprzednio).

Niestety, przy dwóch znakach zapytania ilość kombinacji rośnie do ponad pięciu milionów (a więc kombinacji jest prawie dwa razy więcej niż słów w słowniku), co znacznie wydłuża proces. Udało mi się zejść z czasem wykonania do 24 sekund, ale wiem, że można szybciej.

A oto i skrypt. Jak się komuś nudzi, niech spróbuje go ulepszyć – głównie pod kątem szybkości.

USE slowa;

GO

DROP TABLE permutacje;

GO

DROP TABLE alfabet;

GO

CREATE TABLE alfabet(litera char(1) not null);

INSERT alfabet

SELECT ‘a’ UNION SELECT ‘ą’ UNION SELECT ‘b’ UNION SELECT ‘c’ UNION SELECT ‘ć’ UNION SELECT ‘d’

UNION SELECT ‘e’ UNION SELECT ‘ę’ UNION SELECT ‘f’ UNION SELECT ‘g’ UNION SELECT ‘h’ UNION SELECT ‘i’

UNION SELECT ‘j’ UNION SELECT ‘k’ UNION SELECT ‘l’ UNION SELECT ‘ł’ UNION SELECT ‘m’ UNION SELECT ‘n’

UNION SELECT ‘ń’ UNION SELECT ‘o’ UNION SELECT ‘ó’ UNION SELECT ‘p’ UNION SELECT ‘r’ UNION SELECT ‘s’

UNION SELECT ‘ś’ UNION SELECT ‘t’ UNION SELECT ‘u’ UNION SELECT ‘w’ UNION SELECT ‘y’ UNION SELECT ‘z’

UNION SELECT ‘ź’ UNION SELECT ‘ż’

ALTER TABLE alfabet ADD CONSTRAINT PK_alfabet PRIMARY KEY CLUSTERED (litera);

CREATE TABLE permutacje(s char(7) NOT NULL);

DECLARE @s VARCHAR(7)= ‘o?mi?na’, @qmpos1 int, @qmpos2 int;

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;

SELECT @qmpos1 = charindex(‘?’, @s);

SELECT @qmpos2 = charindex(‘?’, @s, @qmpos1 + 1);

IF @qmpos1 > 0 update permutacje set s=left(s, charindex(‘?’, s)-1) + ‘#’ + right(s, len(s)-charindex(‘?’, s));

IF @qmpos2 > 0 update permutacje set s=left(s, charindex(‘?’, s)-1) + ‘$’ + right(s, len(s)-charindex(‘?’, s));

IF @qmpos2 > 0 BEGIN;

INSERT permutacje

SELECT REPLACE(REPLACE(p.s, ‘#’, a1.litera), ‘$’, a2.litera) AS perm

FROM

alfabet a1,

alfabet a2,

permutacje p;

END ELSE IF @qmpos1 > 0 BEGIN;

INSERT permutacje

SELECT REPLACE(p.s, ‘#’, a.litera) AS perm

FROM

alfabet a,

permutacje p;

END;

DELETE permutacje WHERE s like ‘%[#$]%’;

SELECT DISTINCT slowo

FROM words

JOIN permutacje ON words.slowo=permutacje.s;


Zapisz się
Powiadom o
guest
9 komentarzy
Inline Feedbacks
Zobacz wszystkie komentarze
9
0
Zapraszam do skomentowania wpisu.x
()
x