OraQA

Oracle Question and Answer

  • Do you have a solution to a problem? Do you have an unanswered question? Login and share it with the Oracle community. More...

Oracle News


Entries RSS feed

Comments RSS feed

How to find the shortest possible palindromic pangram in a SQL statement

July 11th, 2007 By Frank Zhou

The following is an interesting puzzle posted by ItaSofware on the web.

A palindrome is a sequence of words that uses the same letters reading backwards as forwards. A palindromic pangram is a multi-word palindrome that includes all 26 letters of the alphabet.

Write a program to find a palindromic pangram. Use this dictionary: WORD.LST (1.66MB). find the shortest possible palindromic pangram in terms of the total number of words or letters used.

The following SQL patterns can be used to find the shortest possible palindromic pangram in a single SQL statement.

10G Solution:

Copy the word.lst from the web to a word.txt file on the database server ( /tmp directory). You can select directly from the external table or insert the data to a real table and then selecting from the table instead.

create or replace directory tmp as '/tmp'

CREATE  TABLE words (str VARCHAR2(38))
     ORGANIZATION EXTERNAL
     (
       TYPE ORACLE_LOADER
       DEFAULT DIRECTORY tmp
       ACCESS PARAMETERS
       (
         records delimited by newline
    fields terminated by whitespace
    missing field values are null
         ( str
         )
       )
       LOCATION ('word.txt')
     )
     REJECT LIMIT UNLIMITED;

Shortest possible palindromic pangram in terms of the total number of letters

SELECT LENGTH(REPLACE(fin_str,' ')) Letter_cnt,
       LENGTH(fin_str)-LENGTH(REPLACE(fin_str,' ', ''))+1
       as word_cnt,
       CASE WHEN REPLACE(fin_str,' ') = REVERSE(REPLACE(fin_str,' '))
     THEN 'Forward_Matches_backward!'
     ELSE 'NO' END AS flag_match,
       fin_str
FROM
(SELECT str, re, fin_str
   FROM(
WITH BASE AS (
SELECT str, REVERSE(str) as rev, SUBSTR(str,1,1) as ch FROM Words
),
data_pair AS
(SELECT str, rev, ch
 FROM ( SELECT str, rev, ch,
               CASE WHEN COUNT(*) OVER (PARTITION BY
                    GREATEST(str, rev),LEAST(str,rev))  -
               COUNT(*) OVER (PARTITION BY str,rev)= 1
         THEN 'T'
            ELSE 'F'
     END AS flag
        FROM BASE
      )
 WHERE flag = 'T'
),
DATA AS (
SELECT str, re, cnt, ch
FROM (SELECT str, re, cnt, ch,
             MIN(str) OVER (PARTITION BY ch) min_str
      FROM(SELECT str, rev re, cnt, ch,
                  MIN(cnt) OVER (PARTITION BY ch) min_len
           FROM (SELECT str, rev, ch,
    COUNT(DISTINCT SUBSTR(str,LEVEL,1)) cnt
                 FROM (SELECT str, rev, ch FROM data_pair)
                 CONNECT BY PRIOR str = str
                 AND LEVEL <= LENGTH(str)
                 AND PRIOR DBMS_RANDOM.STRING ('p',10) IS NOT NULL
                 GROUP BY ch,str, rev
                )
          )
          WHERE cnt = min_len
     )
WHERE str = min_str
),
miss_ch AS (
SELECT CHR(ASCII('a')+LEVEL-1) AS ch
FROM dual CONNECT BY LEVEL <ASCII('z') - ASCII('a') + 2
MINUS
SELECT ch FROM data_pair
),
miss_data AS (
SELECT str, (SELECT ch FROM miss_ch WHERE ROWNUM = 1) ||re AS re , cnt
  FROM (SELECT str, re, COUNT(DISTINCT SUBSTR(str,LEVEL,1)) cnt
  FROM (SELECT w2.str, w2.rev AS re
                    FROM BASE w1, BASE w2
                    WHERE w1.ch IN (SELECT ch FROM miss_ch)
     AND w2.str = SUBSTR(w1.rev,1,LENGTH(w1.rev)-1)
    )
   CONNECT BY PRIOR str = str
             AND LEVEL <= LENGTH(str)
             AND PRIOR DBMS_RANDOM.STRING ('p',10) IS NOT NULL
             GROUP BY str, re
             ORDER BY cnt DESC
       )
  WHERE ROWNUM =1
)
SELECT str, re, cnt, to_number(null) as flag FROM data
UNION ALL
SELECT str, re, cnt, 1  FROM miss_data
)
MODEL
DIMENSION BY (ROW_NUMBER( ) OVER (ORDER BY cnt DESC, str DESC) id )
MEASURES
(CAST(NULL AS VARCHAR2(3999)) tmp_str, str, re,
CAST(NULL AS VARCHAR2(3999)) fin_str, flag )
RULES
(tmp_str[ANY] ORDER BY id  =
CASE WHEN str[cv()-1] IS NULL
     THEN str[cv()]||'#'||re[cv()]
  ELSE CASE WHEN flag[cv()] =1
            THEN substr(tmp_str[cv()-1],1,
                      instr(tmp_str[cv()-1],'#')-1)||' '||str[cv()]
                      ||' '||re[cv()]||' ' ||
                      substr(tmp_str[cv()-1],
                      instr(tmp_str[cv()-1],'#')+1)
                 ELSE CASE WHEN instr(tmp_str[cv()-1],
                                SUBSTR(str[cv()],1,1))<1
                           THEN str[cv()]||' '||tmp_str[cv()-1]||
                                 ' '||re[cv()]
            ELSE tmp_str[cv()-1]
                 END
       END
END,
fin_str[ANY] ORDER BY id = CASE WHEN str[cv()+1] IS NULL
                                THEN tmp_str[cv()]
       END
 )
)
WHERE fin_str IS NOT NULL;

LETTER_CNT   WORD_CNT       FLAG_MATCH                FIN_STR

-----------  ------------   -----------               --------------

77           28             Forward_Matches_backward!
de ha la na wo cam fer gab jar kay vat xis zaps piu
quip spaz six tav yak raj bag ref mac ow an al ah ed

Shortest possible palindromic pangram in terms of the total number of words

SELECT LENGTH(REPLACE(fin_str,' ')) Letter_cnt,
       LENGTH(fin_str)-LENGTH(REPLACE(fin_str,' ', ''))+1
       as word_cnt,
       CASE WHEN REPLACE(fin_str,' ') = REVERSE(REPLACE(fin_str,' '))
            THEN 'Forward_Matches_backward!'
     ELSE 'NO' END AS flag_match,
      fin_str
FROM
(SELECT str, re, fin_str
   FROM(
WITH BASE AS (
SELECT str, REVERSE(str) as rev, SUBSTR(str,1,1) as ch FROM Words
),
data_pair AS
(SELECT b2.str, b2.rev, b2.ch
   FROM BASE b1, BASE b2
   WHERE b1.rev =b2.str
   AND   b1.str != b2.str
),
DATA AS (
SELECT str, re, cnt, ch
FROM (SELECT str, re, cnt, ch,
             MIN(str) OVER (PARTITION BY ch) min_str
      FROM(SELECT str, rev re, cnt, ch,
                  MAX(cnt) OVER (PARTITION BY ch) max_len
           FROM (SELECT str, rev, ch,
    COUNT(DISTINCT SUBSTR(str,LEVEL,1)) cnt
                 FROM (SELECT str, rev, ch FROM data_pair)
                 CONNECT BY PRIOR str = str
                 AND LEVEL <= LENGTH(str)
                 AND PRIOR DBMS_RANDOM.STRING ('p',10) IS NOT NULL
                 GROUP BY ch,str, rev
                )
          )
          WHERE cnt = max_len
     )
WHERE str = min_str
),
miss_ch AS (
SELECT CHR(ASCII('a')+LEVEL-1) AS ch
FROM dual CONNECT BY LEVEL <ASCII('z') - ASCII('a') + 2
MINUS
SELECT ch FROM data_pair
),
miss_data AS (
SELECT str, (SELECT ch FROM miss_ch WHERE ROWNUM = 1) ||re AS re, cnt
  FROM (SELECT str, re, COUNT(DISTINCT SUBSTR(str,LEVEL,1)) cnt
  FROM (SELECT w2.str, w2.rev re
                    FROM BASE w1, BASE w2
                    WHERE w1.ch IN (SELECT ch FROM miss_ch)
     AND w2.str = SUBSTR(w1.rev,1,LENGTH(w1.rev)-1)
       )
   CONNECT BY PRIOR str = str
             AND LEVEL <= LENGTH(str)
             AND PRIOR DBMS_RANDOM.STRING ('p',10) IS NOT NULL
             GROUP BY str, re
             ORDER BY cnt
       )
  WHERE ROWNUM =1
)
SELECT str, re, cnt, to_number(null) as flag FROM data
UNION ALL
SELECT str, re, cnt, 1  FROM miss_data
)
MODEL
DIMENSION BY (ROW_NUMBER( ) OVER (ORDER BY cnt DESC, str DESC) id )
MEASURES
(CAST(NULL AS VARCHAR2(3999)) tmp_str, str, re,
 CAST(NULL AS VARCHAR2(3999)) fin_str, flag)
RULES
(tmp_str[ANY] ORDER BY id  =
CASE WHEN str[cv()-1] IS NULL
     THEN str[cv()]||'#'||re[cv()]
  ELSE CASE WHEN flag[cv()] =1
            THEN substr(tmp_str[cv()-1],1,
                      instr(tmp_str[cv()-1],'#')-1)
       ||' '||str[cv()]||' '||re[cv()]||' '
                 ||substr(tmp_str[cv()-1],
                      instr(tmp_str[cv()-1],'#')+1)
                 ELSE CASE WHEN instr(tmp_str[cv()-1],
                                SUBSTR(str[cv()],1,1))<1
                           THEN str[cv()]||' '||tmp_str[cv()-1]
                                ||' '||re[cv()]
            ELSE tmp_str[cv()-1]
                  END
       END
END,
fin_str[ANY] ORDER BY id = CASE WHEN str[cv()+1] IS NULL
                                THEN tmp_str[cv()]
       END
 )
)
WHERE fin_str IS NOT NULL;

LETTER_CNT  WORD_CNT    FLAG_MATCH                      FIN_STR
----------- --------    -------------------------         --------
111         24          Forward_Matches_backward!
jar vat xis yaps zaps habus pacer degami gateman wolfer stinker ta
qat reknits reflow nametag imaged recap subah spaz spay six tav raj

Leave a Reply

You must be logged in to post a comment.

RSS feed for comments on this question