Google+ (Google Plus)

Ajude a divulgar o MyTraceLog clicando no botão +1.

15 de agosto de 2011

Resolvendo a provinha de programação do Google Developer Day Brasil 2011



O Google Developer Day é um evento de um dia que traz conteúdo avançado, técnico e funcional, sobre as plataformas e produtos do Google. No Brasil, o evento será realizado dia 16 de setembro de 2011 em São Paulo, e apresentará o seguinte assuntos: Android, Chrome & HTML5, Cloud/Geo, Tech Talk/General e Orkut. Apesar de ser um evento gratuito, as vagas são limitadas.

As inscrições foram abertas no dia 8 de agosto e vai até dia 19, e pode ser feita através do site oficial. A provinha de programação faz parte do processo de inscrição e servirá como um critério de seleção caso haja mais inscrições do que vagas disponíveis no evento. Responder a provinha não é obrigatório, mas caso não haja vagas suficientes para todos os inscritos, será utilizado o resultado da provinha como critério de classificação.

Para fazer a provinha, acesse o Developer Quiz.

Bom apesar de não ir participar do evento, achei a provinha muito interessante. Inicialmente eu ia resolver em Delphi 7, mas pensando melhor, resolvi fazer em PL/SQL no Oracle 11g R2. A provinha é composta por 5 questões. É apresentado o idioma Googlon, idioma até então desconhecido, arqueólogos encontram dois pergaminhos, baseado em um dos pergaminhos, nós temos que descobrir informações do outro.

Quando li as 3 primeiras questões vi que a solução era aplicar Expressão Regular, foi por isso que abandonei a ideia de fazer em Delphi 7, o mesmo não possui suporte nativo a Expressão Regular, que coisa não ? A quarta questão envolve ordenação, coisa que o Oracle faz brincando, a última é a que dá um maior trabalho que envolve conversão de letra para número, de acordo com algumas regras específicas, a numeração Goonglon é base 20.

Gostaria de propor o desafio a todos os desenvolvedores para a realização desta provinha, a solução pode envolver qualquer tipo de linguagem: .NET, ASP, C, C++, C#, Delphi, Java, Javascript, Pascal, Perl, PHP, PL/SQL, Phyton, Rubby, Visual Basic, ou a linguagem que você mais domina. O desafio consiste em resolver a provinha, e publicar a solução, da mesma forma que estou fazendo agora. O desafio é interessante, pois não impõe o uso de uma determinada linguagem, dando liberdade ao desenvolvedor. Como diz o ditado "Não existe bala de prata!", desta forma podemos ver o potencial de cada linguagem, e o mais importante, o potencial do desenvolvedor. Ao que aceitarem o desafio, por favor, deixem um comentário neste artigo apresentando a solução.

O desafio inicia hoje (15/08/2011) vai até sexta-feira (19/08/2011) teoricamente. Teoricamente é porque sexta-feira termina as inscrições do evento. Provavelmente o Quiz Developer não estará mais disponível. Mas por isso, guardei uma cópia da minha provinha, que pode ser utilizada no desafio.

Segue a cópia da provinha, em seguida, irei apresentar a solução aplicada em cada questão.

Provinha de Programação - Google Developer Day Brasil 2011

Instruções
Responda à provinha preenchendo os campos apropriados dessa página.A correção é feita inteiramente por máquina, portanto você deve responder exatamente ao que se pede, sem colocar nenhum dado adicional, explicação ou formatação. Você pode (e deve) escrever programas para ajudar a calcular as respostas das questões, mas o seu código-fonte não deve ser enviado.

Nas respostas que pedem texto, espaços e tabulações em excesso serão desconsideradas, portanto não se preocupe caso você digite espaços ou tabulações a mais, mas tome cuidado para não cortar ou juntar palavras. Em outras palavras, qualquer número de espaços em branco é equivalente a um espaço em branco, e espaços em branco no início ou final da resposta não serão considerados.

Quando uma resposta for um número, por favor utilize a notação decimal pura, usando só digitos e sem separadores ou outros caracteres embutidos. Por exemplo, digite 16384 (e nunca 16.384 ou 16 384).

Atenção ao comprimento máximo de alguns campos e certifique-se de que sua resposta está corretamente representada.

Esta página não salva respostas, portanto preencha-a completamente de uma única vez. Caso precise guardar suas respostas para continuar a prova posteriormente, você deve fazê-lo por conta própria (num arquivo por exemplo).

Importante: os resultados de correção da provinha não serão divulgados e não haverá revisão ou vista de provas.
Questões
Arqueólogos encontraram um pergaminho com os seguintes textos:

Texto A


Texto B



Esses pergaminhos estão no antigo e misterioso idioma Googlon. Após muitos anos de estudo, os linguistas já conhecem algumas características desse idioma.

Primeiramente, as letras Googlon são classificadas em dois grupos: as letras v, k, b, p e s são chamadas "letras tipo foo", enquanto que as demais são conhecidas como "letras tipo bar".

Os linguistas descobriram que as preposições em Googlon são as palavras de 5 letras que terminam numa letra tipo bar, mas onde não ocorre a letra w. Portanto, é fácil ver que existem 56 preposições no Texto A. E no Texto B, quantas preposições existem?

Resposta: Existem preposições no Texto B.

Um outro fato interessante descoberto pelos linguistas é que, no Googlon, os verbos sempre são palavras de 6 ou mais letras que terminam numa letra tipo foo. Além disso, se um verbo começa com uma letra tipo foo, o verbo está em primeira pessoa.

Assim, lendo o Texto A, é possível identificar 72 verbos no texto, dos quais 16 estão em primeira pessoa.

Já no Texto B, quantos são os verbos?

Resposta: verbos no Texto B.

E quantos verbos do Texto B estão em primeira pessoa?

Resposta: verbos em primeira pessoa no Texto B.

Um professor universitário utilizará os textos A e B para ensinar o Googlon aos alunos. Para ajudar os alunos a compreender o texto, esse professor precisa criar uma lista de vocabulário para cada texto, isto é, uma lista ordenada (e sem repetições) das palavras que aparecem em cada um dos textos.

Essas listas devem estar ordenadas e não podem conter repetições de palavras. No Googlon, assim como no nosso alfabeto, as palavras são ordenadas lexicograficamente, mas o problema é que no Googlon, a ordem das letras no alfabeto é diferente da nossa. O alfabeto Googlon, em ordem, é: dcxkjsmvrlgftwpqznbh. Assim, ao fazer essas listas, o professor deve respeitar a ordem alfabética Googlon.

O professor preparou a lista de vocabulário para o Texto A:

Lista de vocabulário do Texto A


Como seria a lista de vocabulário do Texto B?

Lista de vocabulário do Texto B

Mas como os Googlons escrevem números? Bem, no Googlon, as palavras também são números dados em base 20, onde cada letra é um dígito, e os dígitos são ordenados do menos significativo para o mais significativo (o inverso do nosso sistema). Ou seja, a primeira posição é a unidade, a segunda posição vale 20, a terceira vale 400, e assim por diante. Os valores das letras são dados pela ordem em que elas aparecem no alfabeto Googlon (que é diferente da nossa ordem, como vimos acima). Ou seja, a primeira letra do alfabeto Googlon representa o dígito 0, a segunda representa o dígito 1, e assim por diante.

Por exemplo, a palavra wsnmx tem o valor numérico de 374913.

OBS: os números nesse problema podem ser grandes, então se você está usando um tipo de dados de tamanho limitado, tenha cuidado com possíveis overflows.

Os Googlons consideram um número bonito se ele satizfaz essas duas propriedades:
  • é maior ou igual a 875106
  • é divisível por 4
Ao consideramos o Texto A como uma lista de números (isto é, interpretando cada palavra como um número usando a convenção explicada acima), notamos que existem 117 números bonitos distintos.

E no Texto B, quantos números bonitos distintos existem?

Resposta: No Texto B, há números bonitos distintos (atenção!).

Resolução da provinha de programação - Google Developer Day Brasil 2011

Agora vamos para a parte divertida, vamos resolver a provinha. Como adotei o PL/SQL para resolução do problema, será necessário criar algumas tabelas, sequências, e um pacote com procedimentos e funções. Tudo isso será criado no decorrer da provinha.

Para começar vamos criar a tabela PERGAMINHOS, será nossa principal tabela, nela vamos armazenar as respostas das questões.
CREATE TABLE PERGAMINHOS (
   PERGAMINHO_ID NUMBER NOT NULL,
   NOME VARCHAR2(8) NOT NULL,
   PERGAMINHO VARCHAR2(4000) NOT NULL,
   PREPOSICAO NUMBER,       
   VERBO NUMBER,
   VERBO_PRIMEIRA_PESSOA NUMBER,
   LISTA_VOCABULARIO VARCHAR2(4000),
   NUMERO_BONITO_DISTINTO NUMBER
);

Criando a chave primária PK_PERGAMINHOS:
ALTER TABLE PERGAMINHOS ADD CONSTRAINT PK_PERGAMINHOS PRIMARY KEY(PERGAMINHO_ID);

Criando a sequência PERGAMINHOS_SEQ:
CREATE SEQUENCE PERGAMINHOS_SEQ
MINVALUE 1
MAXVALUE 99999999
START WITH 1
INCREMENT BY 1
CACHE 20;

Analisando as 3 primeiras questões, a solução é aplicar Expressão Regular, mas para isso, temos uma pequena dificuldade inicial, as palavras dos textos estão em uma única linha, e separados por espaços, desta forma, nada adianta Expressão Regular. Vamos trabalhar um pouco com as informações para facilitar a vida. Tudo que precisamos é ter cada palavra em uma linha, mantendo a ordem das palavras para o caso de juntar as palavras de volta. Com cada palavra em uma linha, é só montar a Expressão Regular e utilizar REGEXP_LIKE pra fazer a consulta e retornar a contagem de palavras.

Criando a tabela PALAVRAS que irá armazenar as palavras dos PERGAMINHOS:
CREATE TABLE PALAVRAS (
   PALAVRA_ID NUMBER NOT NULL,
   PERGAMINHO_ID NUMBER NOT NULL,
   ORDEM NUMBER NOT NULL,
   PALAVRA VARCHAR2(8) NOT NULL
);

Criando a chave primária PK_PALAVRAS:
ALTER TABLE PALAVRAS ADD CONSTRAINT PK_PALAVRAS PRIMARY KEY(PALAVRA_ID);

Criando a chave estrangeira FK_PALAVRAS_PERGAMINHOS:
ALTER TABLE PALAVRAS ADD CONSTRAINT FK_PALAVRAS_PERGAMINHOS FOREIGN KEY(PERGAMINHO_ID) REFERENCES PERGAMINHOS(PERGAMINHO_ID);

Criando a sequência PALAVRAS_SEQ:
CREATE SEQUENCE PALAVRAS_SEQ
MINVALUE 1
MAXVALUE 99999999
START WITH 1
INCREMENT BY 1
CACHE 20;

Voltando com a ideia de ter cada palavra em uma linha, para isso temos que selecionar o pergaminho, contar o número de palavras que tem no pergaminho, percorrer um laço que irá caminhar de palavra em palavra, e inserir cada palavra na tabela PALAVRAS. Antes de implementar o procedimento PERGAMINHO_TO_PALAVRAS, vamos implementar a função COUNT_PALAVRAS:
FUNCTION COUNT_PALAVRAS(P_PERGAMINHO VARCHAR2, P_SEPARADOR VARCHAR2) RETURN NUMBER IS
   L_TOTAL_PALAVRAS    NUMBER;
   L_EXPRESSAO_REGULAR VARCHAR2(4);
BEGIN
   L_EXPRESSAO_REGULAR := '[^' || P_SEPARADOR || ']';
  
   EXECUTE IMMEDIATE 'SELECT LENGTH(REGEXP_REPLACE(:1,:2,NULL))+1 FROM DUAL'
      INTO L_TOTAL_PALAVRAS
      USING P_PERGAMINHO, L_EXPRESSAO_REGULAR;
  
   RETURN L_TOTAL_PALAVRAS;
   
   EXCEPTION
      WHEN OTHERS THEN
      BEGIN
         DBMS_OUTPUT.PUT_LINE(SQLERRM);
      END;
END;

A função COUNT_PALAVRAS utiliza Expressão Regular, a mesma funciona da seguinte forma. A Expressão Regular utilizada neste caso é [^ ], que é uma lista negada do carácter espaço, ou seja, ele casa qualquer carácter diferente de espaço. Espaço no caso, é o separador que é passado pelo parâmetro da função. REGEXP_REPLACE percorre o pergaminho, substituindo carácteres diferentes de espaço por NULL, ou seja, apaga o carácter, sobrando apenas os espaços, em seguida a função LENGTH retorna a quantidade de espaços. O número de palavras é igual ao número de espaço (separador) mais um.

Segue a implementação do procedimento PERGAMINHO_TO_PALAVRAS:
PROCEDURE PERGAMINHO_TO_PALAVRAS(P_PERGAMINHO_ID NUMBER) IS
   L_PERGAMINHO     VARCHAR2(4000);
   L_TOTAL_PALAVRAS NUMBER;
   L_PALAVRA        VARCHAR2(4000);
   L_INICIO         NUMBER;
BEGIN
   EXECUTE IMMEDIATE 'SELECT PERGAMINHO FROM PERGAMINHOS WHERE PERGAMINHO_ID = :1'
      INTO L_PERGAMINHO
      USING P_PERGAMINHO_ID;
  
   L_TOTAL_PALAVRAS := GOOGLE_DEV_DAY_BRASIL_2011.COUNT_PALAVRAS(L_PERGAMINHO, GOOGLE_DEV_DAY_BRASIL_2011.SEPARADOR);
  
   L_PERGAMINHO := L_PERGAMINHO || GOOGLE_DEV_DAY_BRASIL_2011.SEPARADOR;
   L_INICIO     := 1;
   FOR I IN 1 .. L_TOTAL_PALAVRAS LOOP
      L_PALAVRA := SUBSTR(L_PERGAMINHO, L_INICIO, INSTR(L_PERGAMINHO, GOOGLE_DEV_DAY_BRASIL_2011.SEPARADOR, 1, I) - L_INICIO);
      L_INICIO  := INSTR(L_PERGAMINHO, GOOGLE_DEV_DAY_BRASIL_2011.SEPARADOR, 1, I) + 1;
    
      INSERT INTO PALAVRAS(PALAVRA_ID, PERGAMINHO_ID, ORDEM, PALAVRA)
         VALUES(PALAVRAS_SEQ.NEXTVAL, P_PERGAMINHO_ID, I, L_PALAVRA);
   END LOOP;
  
   EXCEPTION
      WHEN OTHERS THEN
      BEGIN
         DBMS_OUTPUT.PUT_LINE(SQLERRM);
      END;
END;

GOOGLE_DEV_DAY_BRASIL_2011 é o pacote que agrupará todos os procedimentos e funções, mais na frente será mostrado a sua implementação. GOOGLE_DEV_DAY_BRASIL_2011.SEPARADOR é uma constante definida no pacote GOOGLE_DEV_DAY_BRASIL_2011.
Primeira Questão - Preposição
Primeiramente, as letras Googlon são classificadas em dois grupos: as letras v, k, b, p e s são chamadas "letras tipo foo", enquanto que as demais são conhecidas como "letras tipo bar".

Os linguistas descobriram que as preposições em Googlon são as palavras de 5 letras que terminam numa letra tipo bar, mas onde não ocorre a letra w.

Montamos a seguinte Expressão Regular:
^[^w]{4}[^wvkbps]$

Interpretando a Expressão Regular temos: As 4 primeiras letras não são w e o última letra não é v, k, b, p, s (letras tipo foo) e w. 4 + 1 = 5 letras.

Implementando o procedimento CALCULA_PREPOSICAO, o mesmo irá contar o número de preposições por meio de uma consulta que utiliza REGEXP_LIKE aplicando a Expressão Regular, em seguida irá armazenar o resultado na tabela PERGAMINHOS. A segunda e terceira questão também segue a mesma lógica.
PROCEDURE CALCULA_PREPOSICAO(P_PERGAMINHO_ID NUMBER) IS
   L_EXPRESSAO_REGULAR VARCHAR2(32) := '^[^w]{4}[^wvkbps]$';
BEGIN
   EXECUTE IMMEDIATE 'UPDATE PERGAMINHOS P
                      SET P.PREPOSICAO = (
                         SELECT COUNT(*)
                         FROM PALAVRAS
                         WHERE PERGAMINHO_ID = P.PERGAMINHO_ID
                         AND REGEXP_LIKE(PALAVRA,:1)       
                      )
                      WHERE PERGAMINHO_ID = :2'
   USING L_EXPRESSAO_REGULAR, P_PERGAMINHO_ID;

   EXCEPTION
      WHEN OTHERS THEN
      BEGIN
        DBMS_OUTPUT.PUT_LINE(SQLERRM);
      END;  
END;
Segunda Questão - Verbo
Um outro fato interessante descoberto pelos linguistas é que, no Googlon, os verbos sempre são palavras de 6 ou mais letras que terminam numa letra tipo foo.

Chegamos na Expressão Regular:
^.{5,7}[vkbps]$

Interpretando: 6 ou mais letras, analisando a maior palavra possui 8 letras. 5 + 1 = 6 letras. 6 + 1 = 7 letras. 7 + 1 = 8 letras. Termina com v, k, b, p, s (letras tipo foo).

Implementando o procedimento CALCULA_VERBO:
PROCEDURE CALCULA_VERBO(P_PERGAMINHO_ID NUMBER) IS
   L_EXPRESSAO_REGULAR VARCHAR2(32) := '^.{5,7}[vkbps]$';
BEGIN
   EXECUTE IMMEDIATE 'UPDATE PERGAMINHOS P
                      SET P.VERBO = (
                         SELECT COUNT(*)
                         FROM PALAVRAS
                         WHERE PERGAMINHO_ID = P.PERGAMINHO_ID
                         AND REGEXP_LIKE(PALAVRA,:1)       
                      )
                      WHERE PERGAMINHO_ID = :2'
   USING L_EXPRESSAO_REGULAR, P_PERGAMINHO_ID;

   EXCEPTION
      WHEN OTHERS THEN
      BEGIN
        DBMS_OUTPUT.PUT_LINE(SQLERRM);
      END;      
END;
Terceira Questão - Verbo em Primeira Pessoa
Além disso, se um verbo começa com uma letra tipo foo, o verbo está em primeira pessoa.

Expressão Regular:
^[vkbps].{4,6}[vkbps]$

Interpretando: Verbo que começa com v, k, b, p, e s (letra tipo foo). 1 + 4 + 1 = 6 letras, 1 + 5 + 1 = 7 letras. 1 + 6 + 1 = 8 letras.

Implementando o procedimento CALCULA_VERBO_PRIMEIRA_PESSOA:
PROCEDURE CALCULA_VERBO_PRIMEIRA_PESSOA(P_PERGAMINHO_ID NUMBER) IS
   L_EXPRESSAO_REGULAR VARCHAR2(32) := '^[vkbps].{4,6}[vkbps]$';
BEGIN
   EXECUTE IMMEDIATE 'UPDATE PERGAMINHOS P
                      SET P.VERBO_PRIMEIRA_PESSOA = (
                         SELECT COUNT(*)
                         FROM PALAVRAS
                         WHERE PERGAMINHO_ID = P.PERGAMINHO_ID
                         AND REGEXP_LIKE(PALAVRA,:1)       
                      )
                      WHERE PERGAMINHO_ID = :2'
   USING L_EXPRESSAO_REGULAR, P_PERGAMINHO_ID;

   EXCEPTION
      WHEN OTHERS THEN
      BEGIN
        DBMS_OUTPUT.PUT_LINE(SQLERRM);
      END;      
END;
Quarta Questão - Lista de vocabulário
A ordem do alfabeto Googlon é: dcxkjsmvrlgftwpqznbh. Foi solicitado uma lista ordenada sem repetição baseado nos pergaminhos.

Implementar a precedência das letras, e implementar a ordenação palavra por palavra, é um tanto trabalhoso. Ordenar palavras do nosso alfabeto o Oracle faz brincando, pena que ele não conhece inicialmente o alfabeto Googlon. A função TRANSLATE do Oracle 11g R2 x86_64 irá traduzir o alfabeto Google para o nosso alfabeto, então é só ordenar as palavras usando ORDER BY, simples não?

A ordenação foi resolvida, agora falta a ausência repetição. Na consulta que irá retornar as PALAVRAS, basta utilizar a cláusula DISTINCT no SELECT.

De modo geral, temos que fazer um procedimento que selecione as palavras excluindo as repetições e ordenando pelo alfabeto traduzido. Montar a lista de vocabulário, concatenando palavra por palavra separado por espaço. No final, armazenar a lista de vocabulário na tabela PERGAMINHOS.

Segue a implementação do procedimento PALAVRAS_TO_LISTA_VOCABULARIO:
PROCEDURE PALAVRAS_TO_LISTA_VOCABULARIO(P_PERGAMINHO_ID NUMBER) IS
   L_LISTA_VOCABULARIO  VARCHAR2(4000);
   L_ALFABETO_GOOGLON   VARCHAR2(20) := 'dcxkjsmvrlgftwpqznbh';
   L_ALFABETO_PORTUGUES VARCHAR2(20) := 'abcdefghijklmnopqrst';
BEGIN
   L_LISTA_VOCABULARIO := NULL;
  
   FOR REGISTRO IN (SELECT DISTINCT PALAVRA
                    FROM PALAVRAS
                    WHERE PERGAMINHO_ID = P_PERGAMINHO_ID
                    ORDER BY TRANSLATE(PALAVRA, L_ALFABETO_GOOGLON, L_ALFABETO_PORTUGUES)) LOOP

      L_LISTA_VOCABULARIO := L_LISTA_VOCABULARIO || REGISTRO.PALAVRA || GOOGLE_DEV_DAY_BRASIL_2011.SEPARADOR;
   END LOOP;
  
   UPDATE PERGAMINHOS
      SET LISTA_VOCABULARIO = L_LISTA_VOCABULARIO
    WHERE PERGAMINHO_ID = P_PERGAMINHO_ID;
  
   EXCEPTION
      WHEN OTHERS THEN
      BEGIN
        DBMS_OUTPUT.PUT_LINE(SQLERRM);
      END;
END;
Quinta Questão - Número Bonito Distinto
Para a quinta e última questão, vamos criar mais uma tabela e uma sequência. Como não é necessário saber quais são os números bonitos distintos, só foi solicitado a quantidade, decidi utilizar uma tabela temporária, desta forma, não é necessário apagar os registro da tabela toda vez que for calcular a quantidade de números bonitos distintos. Ao executar o COMMIT os registros são "removidos", as tabelas temporárias utilizam a tablespace TEMP.

Criando a tabela NUMEROS, tabela que irá armazenar números bonitos dado as PALAVRAS:
CREATE GLOBAL TEMPORARY TABLE NUMEROS (
       NUMERO_ID NUMBER NOT NULL,
       PERGAMINHO_ID NUMBER NOT NULL,
       ORDEM NUMBER NOT NULL,
       NUMERO NUMBER NOT NULL
) ON COMMIT DELETE ROWS;

Criando a chave primária PK_NUMEROS:
ALTER TABLE NUMEROS ADD CONSTRAINT PK_NUMEROS PRIMARY KEY(NUMERO_ID);

Detalhe, infelizmente tabelas temporárias não tem suporte a chave estrangeira. Caso tente criar a chave estrangeira, receberá o erro ORA-14455. Caso queira garantir a integridade, pode ser implementado uma trigger.

Criando a sequência NUMEROS_SEQ:
CREATE SEQUENCE NUMEROS_SEQ
MINVALUE 1
MAXVALUE 99999999
START WITH 1
INCREMENT BY 1
CACHE 20;

A lógica empregada nesta questão é a seguinte: Selecionar as palavras do pergaminho, percorrer por meio de um laço cada palavra, em cada palavra percorrer por um outro laço letra por letra da palavra, para cada letra, converter a letra em valor numérico, converter o número para base 20 e somar todos os valores da palavra, verificar se o número é bonito, e inserir na tabela NUMEROS. Após fazer o processo para todas as palavras do pergaminho, fazer uma contagem distinta dos números do pergaminho, e armazenar na tabela PERGAMINHOS.

Para converter a letra em valor numérico, utilize a função LETRA_TO_UNIDADE:
FUNCTION LETRA_TO_UNIDADE(P_LETRA CHAR) RETURN NUMBER IS
   L_UNIDADE NUMBER;
BEGIN
   SELECT DECODE(P_LETRA,
                'd',0,
                'c',1,
                'x',2,
                'k',3,
                'j',4,
                's',5,
                'm',6,
                'v',7,
                'r',8,
                'l',9,
                'g',10,
                'f',11,
                't',12,
                'w',13,
                'p',14,
                'q',15,
                'z',16,
                'n',17,
                'b',18,
                'h',19)
   INTO L_UNIDADE
   FROM DUAL;
   
   RETURN L_UNIDADE;
  
   EXCEPTION
      WHEN OTHERS THEN
      BEGIN
        DBMS_OUTPUT.PUT_LINE(SQLERRM);
      END;
END;

Para verificar se o número é bonito, foi implementado a função IS_NUMERO_BONITO:
FUNCTION IS_NUMERO_BONITO(P_NUMERO NUMBER) RETURN BOOLEAN IS
   L_LIMITE_INFERIOR NUMBER := 875106;
   L_DIVISOR         NUMBER := 4;
BEGIN
   RETURN (P_NUMERO >= L_LIMITE_INFERIOR) AND (P_NUMERO MOD L_DIVISOR = 0);
    
   EXCEPTION
      WHEN OTHERS THEN
      BEGIN
        DBMS_OUTPUT.PUT_LINE(SQLERRM);
      END;    
END;

Finalmente, a implementação do procedimento CALCULA_NUMERO_BONITO_DISTINTO:
PROCEDURE CALCULA_NUMERO_BONITO_DISTINTO(P_PERGAMINHO_ID NUMBER) IS
   L_ORDEM          NUMBER;
   L_LETRA          CHAR;
   L_UNIDADE        NUMBER;
   L_NUMERO         NUMBER;
   I                NUMBER;
BEGIN
   I := 1;
   L_ORDEM := 1;
   FOR REGISTRO IN (SELECT PALAVRA
                    FROM PALAVRAS
                    WHERE PERGAMINHO_ID = P_PERGAMINHO_ID) LOOP                               
      L_NUMERO := 0;
      FOR I IN 1 .. LENGTH(REGISTRO.PALAVRA) LOOP
         L_LETRA := SUBSTR(REGISTRO.PALAVRA, I, 1);
      
         L_UNIDADE := GOOGLE_DEV_DAY_BRASIL_2011.LETRA_TO_UNIDADE(L_LETRA);
      
         L_NUMERO := L_NUMERO + (L_UNIDADE * POWER(20, I - 1));
      END LOOP;
    
      IF GOOGLE_DEV_DAY_BRASIL_2011.IS_NUMERO_BONITO(L_NUMERO) THEN
         INSERT INTO NUMEROS(NUMERO_ID, PERGAMINHO_ID, ORDEM, NUMERO)
            VALUES(NUMEROS_SEQ.NEXTVAL, P_PERGAMINHO_ID, L_ORDEM, L_NUMERO);

        L_ORDEM := L_ORDEM + 1;
      END IF;

      I := I + 1;
      
    END LOOP;
  
    UPDATE PERGAMINHOS P
       SET P.NUMERO_BONITO_DISTINTO = (
            SELECT COUNT(DISTINCT NUMERO)
            FROM NUMEROS
            WHERE PERGAMINHO_ID = P.PERGAMINHO_ID)
     WHERE P.PERGAMINHO_ID = P_PERGAMINHO_ID;

   EXCEPTION
      WHEN OTHERS THEN
      BEGIN
        DBMS_OUTPUT.PUT_LINE(SQLERRM);
      END;     
END;
Concluindo
Agora com todos os procedimentos e funções implementadas, segue o pacote GOOGLE_DEV_DAY_BRASIL_2011:

Package:
CREATE OR REPLACE PACKAGE GOOGLE_DEV_DAY_BRASIL_2011 IS

    -- AUTHOR  : SAKAMOTO
    -- SITE    : MyTraceLog - Registro de um DBA
    -- URL     : http://mytracelog.blogspot.com
    -- CREATED : 14/08/2011 16:42:22
    -- PURPOSE : PROVINHA DE PROGRAMAÇÃO - GOOGLE DEVELOPER DAY BRASIL 2011
    -- VERSION : 1.0
    
  SEPARADOR CONSTANT CHAR := ' ';

  FUNCTION COUNT_PALAVRAS(P_PERGAMINHO VARCHAR2, P_SEPARADOR VARCHAR2) RETURN NUMBER;
  FUNCTION LETRA_TO_UNIDADE(P_LETRA CHAR) RETURN NUMBER;
  FUNCTION IS_NUMERO_BONITO(P_NUMERO NUMBER) RETURN BOOLEAN;
  
  PROCEDURE PERGAMINHO_TO_PALAVRAS(P_PERGAMINHO_ID NUMBER);
  PROCEDURE CALCULA_PREPOSICAO(P_PERGAMINHO_ID NUMBER);
  PROCEDURE CALCULA_VERBO(P_PERGAMINHO_ID NUMBER);
  PROCEDURE CALCULA_VERBO_PRIMEIRA_PESSOA(P_PERGAMINHO_ID NUMBER);
  PROCEDURE PALAVRAS_TO_LISTA_VOCABULARIO(P_PERGAMINHO_ID NUMBER);
  PROCEDURE CALCULA_NUMERO_BONITO_DISTINTO(P_PERGAMINHO_ID NUMBER);
END GOOGLE_DEV_DAY_BRASIL_2011;

Package Body:
CREATE OR REPLACE PACKAGE BODY GOOGLE_DEV_DAY_BRASIL_2011 IS

  -- AUTHOR  : SAKAMOTO
  -- SITE    : MyTraceLog - Registro de um DBA
  -- URL     : http://mytracelog.blogspot.com
  -- CREATED : 14/08/2011 16:42:22
  -- PURPOSE : PROVINHA DE PROGRAMAÇÃO - GOOGLE DEVELOPER DAY BRASIL 2011
  -- VERSION : 1.0

/*********************************************************************************/
  
FUNCTION COUNT_PALAVRAS(P_PERGAMINHO VARCHAR2, P_SEPARADOR VARCHAR2)
  RETURN NUMBER IS
  L_TOTAL_PALAVRAS    NUMBER;
  L_EXPRESSAO_REGULAR VARCHAR2(4);
BEGIN
  L_EXPRESSAO_REGULAR := '[^' || P_SEPARADOR || ']';
  
  EXECUTE IMMEDIATE 'SELECT LENGTH(REGEXP_REPLACE(:1,:2,NULL))+1 FROM DUAL'
    INTO L_TOTAL_PALAVRAS
    USING P_PERGAMINHO, L_EXPRESSAO_REGULAR;
  
  RETURN L_TOTAL_PALAVRAS;
  
EXCEPTION
  WHEN OTHERS THEN
    BEGIN
      DBMS_OUTPUT.PUT_LINE(SQLERRM);
    END;
END;

/*********************************************************************************/

FUNCTION LETRA_TO_UNIDADE(P_LETRA CHAR) RETURN NUMBER IS
  L_UNIDADE NUMBER;
BEGIN
  SELECT DECODE(P_LETRA,
                'd',0,
                'c',1,
                'x',2,
                'k',3,
                'j',4,
                's',5,
                'm',6,
                'v',7,
                'r',8,
                'l',9,
                'g',10,
                'f',11,
                't',12,
                'w',13,
                'p',14,
                'q',15,
                'z',16,
                'n',17,
                'b',18,
                'h',19)
    INTO L_UNIDADE
    FROM DUAL;
  RETURN L_UNIDADE;
  
EXCEPTION
  WHEN OTHERS THEN
    BEGIN
      DBMS_OUTPUT.PUT_LINE(SQLERRM);
    END;
END;

/*********************************************************************************/

FUNCTION IS_NUMERO_BONITO(P_NUMERO NUMBER) RETURN BOOLEAN IS
  L_LIMITE_INFERIOR NUMBER := 875106;
  L_DIVISOR         NUMBER := 4;
BEGIN
  RETURN(P_NUMERO >= L_LIMITE_INFERIOR) AND (P_NUMERO MOD L_DIVISOR = 0);
    
EXCEPTION
  WHEN OTHERS THEN
    BEGIN
      DBMS_OUTPUT.PUT_LINE(SQLERRM);
    END;    
END;

/*********************************************************************************/

PROCEDURE PERGAMINHO_TO_PALAVRAS(P_PERGAMINHO_ID NUMBER) IS
  L_PERGAMINHO     VARCHAR2(4000);
  L_TOTAL_PALAVRAS NUMBER;
  L_PALAVRA        VARCHAR2(4000);
  L_INICIO         NUMBER;
BEGIN
  EXECUTE IMMEDIATE 'SELECT PERGAMINHO FROM PERGAMINHOS WHERE PERGAMINHO_ID = :1'
    INTO L_PERGAMINHO
    USING P_PERGAMINHO_ID;
  
  L_TOTAL_PALAVRAS := GOOGLE_DEV_DAY_BRASIL_2011.COUNT_PALAVRAS(L_PERGAMINHO, GOOGLE_DEV_DAY_BRASIL_2011.SEPARADOR);
  
  L_PERGAMINHO := L_PERGAMINHO || GOOGLE_DEV_DAY_BRASIL_2011.SEPARADOR;
  L_INICIO     := 1;
  FOR I IN 1 .. L_TOTAL_PALAVRAS LOOP
    L_PALAVRA := SUBSTR(L_PERGAMINHO, L_INICIO, INSTR(L_PERGAMINHO, GOOGLE_DEV_DAY_BRASIL_2011.SEPARADOR, 1, I) - L_INICIO);

    L_INICIO  := INSTR(L_PERGAMINHO, GOOGLE_DEV_DAY_BRASIL_2011.SEPARADOR, 1, I) + 1;
    
    INSERT INTO PALAVRAS(PALAVRA_ID, PERGAMINHO_ID, ORDEM, PALAVRA)
      VALUES(PALAVRAS_SEQ.NEXTVAL, P_PERGAMINHO_ID, I, L_PALAVRA);
  END LOOP;
  
EXCEPTION
  WHEN OTHERS THEN
    BEGIN
      DBMS_OUTPUT.PUT_LINE(SQLERRM);
    END;
END;

/*********************************************************************************/

PROCEDURE CALCULA_PREPOSICAO(P_PERGAMINHO_ID NUMBER) IS
  L_EXPRESSAO_REGULAR VARCHAR2(32) := '^[^w]{4}[^wvkbps]$';
BEGIN
  EXECUTE IMMEDIATE 'UPDATE PERGAMINHOS P
                     SET P.PREPOSICAO = (
                        SELECT COUNT(*)
                        FROM PALAVRAS
                        WHERE PERGAMINHO_ID = P.PERGAMINHO_ID
                        AND REGEXP_LIKE(PALAVRA,:1)       
                     )
                     WHERE PERGAMINHO_ID = :2'
  USING L_EXPRESSAO_REGULAR, P_PERGAMINHO_ID;

EXCEPTION
  WHEN OTHERS THEN
    BEGIN
      DBMS_OUTPUT.PUT_LINE(SQLERRM);
    END;  
END;

/*********************************************************************************/

PROCEDURE CALCULA_VERBO(P_PERGAMINHO_ID NUMBER) IS
  L_EXPRESSAO_REGULAR VARCHAR2(32) := '^.{5,7}[vkbps]$';
BEGIN
  EXECUTE IMMEDIATE 'UPDATE PERGAMINHOS P
                     SET P.VERBO = (
                        SELECT COUNT(*)
                        FROM PALAVRAS
                        WHERE PERGAMINHO_ID = P.PERGAMINHO_ID
                        AND REGEXP_LIKE(PALAVRA,:1)       
                     )
                     WHERE PERGAMINHO_ID = :2'
  USING L_EXPRESSAO_REGULAR, P_PERGAMINHO_ID;

EXCEPTION
  WHEN OTHERS THEN
    BEGIN
      DBMS_OUTPUT.PUT_LINE(SQLERRM);
    END;      
END;

/*********************************************************************************/

PROCEDURE CALCULA_VERBO_PRIMEIRA_PESSOA(P_PERGAMINHO_ID NUMBER) IS
  L_EXPRESSAO_REGULAR VARCHAR2(32) := '^[vkbps].{4,6}[vkbps]$';
BEGIN
  EXECUTE IMMEDIATE 'UPDATE PERGAMINHOS P
                     SET P.VERBO_PRIMEIRA_PESSOA = (
                        SELECT COUNT(*)
                        FROM PALAVRAS
                        WHERE PERGAMINHO_ID = P.PERGAMINHO_ID
                        AND REGEXP_LIKE(PALAVRA,:1)       
                     )
                     WHERE PERGAMINHO_ID = :2'
  USING L_EXPRESSAO_REGULAR, P_PERGAMINHO_ID;

EXCEPTION
  WHEN OTHERS THEN
    BEGIN
      DBMS_OUTPUT.PUT_LINE(SQLERRM);
    END;      
END;

/*********************************************************************************/

PROCEDURE PALAVRAS_TO_LISTA_VOCABULARIO(P_PERGAMINHO_ID NUMBER) IS
  L_LISTA_VOCABULARIO  VARCHAR2(4000);
  L_ALFABETO_GOOGLON   VARCHAR2(20) := 'dcxkjsmvrlgftwpqznbh';
  L_ALFABETO_PORTUGUES VARCHAR2(20) := 'abcdefghijklmnopqrst';
BEGIN
  L_LISTA_VOCABULARIO := NULL;
  
  FOR REGISTRO IN (SELECT DISTINCT PALAVRA
                     FROM PALAVRAS
                    WHERE PERGAMINHO_ID = P_PERGAMINHO_ID
                    ORDER BY TRANSLATE(PALAVRA,
                                       L_ALFABETO_GOOGLON,
                                       L_ALFABETO_PORTUGUES)) LOOP
    L_LISTA_VOCABULARIO := L_LISTA_VOCABULARIO || REGISTRO.PALAVRA ||
                           GOOGLE_DEV_DAY_BRASIL_2011.SEPARADOR;
  END LOOP;
  
  UPDATE PERGAMINHOS
     SET LISTA_VOCABULARIO = L_LISTA_VOCABULARIO
   WHERE PERGAMINHO_ID = P_PERGAMINHO_ID;
  
EXCEPTION
  WHEN OTHERS THEN
    BEGIN
      DBMS_OUTPUT.PUT_LINE(SQLERRM);
    END;
END;

/*********************************************************************************/

PROCEDURE CALCULA_NUMERO_BONITO_DISTINTO(P_PERGAMINHO_ID NUMBER) IS
  L_ORDEM          NUMBER;
  L_LETRA          CHAR;
  L_UNIDADE        NUMBER;
  L_NUMERO         NUMBER;
  I                NUMBER;
BEGIN
  I := 1;
  L_ORDEM := 1;
  FOR REGISTRO IN (SELECT PALAVRA
                   FROM PALAVRAS
                   WHERE PERGAMINHO_ID = P_PERGAMINHO_ID) LOOP                               
    L_NUMERO := 0;
    FOR I IN 1 .. LENGTH(REGISTRO.PALAVRA) LOOP
      L_LETRA := SUBSTR(REGISTRO.PALAVRA, I, 1);
      
      L_UNIDADE := GOOGLE_DEV_DAY_BRASIL_2011.LETRA_TO_UNIDADE(L_LETRA);
      
      L_NUMERO := L_NUMERO + (L_UNIDADE * POWER(20, I - 1));
    END LOOP;
    
    IF GOOGLE_DEV_DAY_BRASIL_2011.IS_NUMERO_BONITO(L_NUMERO) THEN
      INSERT INTO NUMEROS(NUMERO_ID, PERGAMINHO_ID, ORDEM, NUMERO)
        VALUES(NUMEROS_SEQ.NEXTVAL, P_PERGAMINHO_ID, L_ORDEM, L_NUMERO);
      
      L_ORDEM := L_ORDEM + 1;
    END IF;

    I := I + 1;
      
  END LOOP;
  
  UPDATE PERGAMINHOS P
     SET P.NUMERO_BONITO_DISTINTO =
         (SELECT COUNT(DISTINCT NUMERO)
            FROM NUMEROS
           WHERE PERGAMINHO_ID = P.PERGAMINHO_ID)
   WHERE P.PERGAMINHO_ID = P_PERGAMINHO_ID;

EXCEPTION
  WHEN OTHERS THEN
    BEGIN
      DBMS_OUTPUT.PUT_LINE(SQLERRM);
    END;     
END;
  
/*********************************************************************************/
    
BEGIN
  NULL;
END GOOGLE_DEV_DAY_BRASIL_2011;

Daqui pra frente utilizaremos o sqlplus como cliente Oracle.

Antes de inserir os registros do pergaminho, é necessário alterar o parâmetro DEFERRED_SEGMENT_CREATION do Oracle 11g R2 x86_64. Por padrão, o parâmetro DEFERRED_SEGMENT_CREATION é TRUE.

Segundo a documentação oficial do Oracle 11g R2 x86_64:
DEFERRED_SEGMENT_CREATION specifies the semantics of deferred segment creation. If set to true, then segments for non-partitioned tables and their dependent objects (LOBs, indexes) will not be created until the first row is inserted into the table.

Before creating a set of tables, if it is known that a significant number of them will not be populated, then consider setting this parameter to true. This saves disk space and minimizes install time.

Desabilitando o parâmetro DEFERRED_SEGMENT_CREATION:
SQL> ALTER SYSTEM SET DEFERRED_SEGMENT_CREATION = FALSE SCOPE=MEMORY;
 
System altered

Caso não desabilite, a primeira inserção de cada tabela que utiliza sequência irá "falhar", em consequência é perdido a sequência 1, e o primeiro registro utilizará a sequência 2.

Agora vamos inserir os registros dos PERGAMINHOS:
SQL> INSERT INTO PERGAMINHOS(PERGAMINHO_ID,NOME,PERGAMINHO) VALUES(PERGAMINHOS_SEQ.NEXTVAL,'Texto A','wsnmx fvjxrdfd nqxhxs mlzlpk glrxnsh dlrbnkxq znsnkrfc kjdqxgm ddcf dghwxk wmx wrflj tlqx zhpmzrtf xfgm slgfdjl hzvqf vksfg tqz jmjq rfgcwcf ckggzsd wpnn jxhmhnhf mbbxzl pwctdf drnnzlr kqbtck ddrpbj dmsbns prfcvllg cckfsb xwqplnvv smnw cgqt lcdgwf wxhr pfh hqfqlzxp bnbftrf hkrw thsbxw xwsxlm ftzzzct tnqrkjjf gjkz gqdw lsr xcxjtpfn rblfvc wwfrgkj ttfjct xcdgbt kmszsfzw hrhmj gnlqwj ztkzbhz dcrplxs zgp qmq rppnmhtw qwbpchlg xrpqrgj mlz vnrhwv kptzcdbq qtx whjsms lmrtr xgtmm qzwjvwpp jtwtwvd rwdqbl pnrs gkp gjvnt tpk bbkcm npjsm jbccm qlrm jccrdqcc rwwcvl jvztkpk stdszmgx qvz tlcds fgrq xmf xrct tnbd bntr vvnhtp cccwsn lpvbwzvd cqc lnkx cxdcm znlnfhwn tvncrlp gnx csszngw pzczndn wgcm khzcrr xtzk tjhvvkn zkv dbnzpfd rrxsvsn ckhf xqqn zgpwvsw rdcphz bpmm qrf kngpvgn hsgfnpn btwqck kgh sqtjmwd zfhlkk ppxkr lwgwvv ndxxb gzrdtx drvpdrkx tbb ndsbv bzjtb sljgvv dmdmwpk ggdnqs cfvlqp fnp nzrppwnq mvcqqc hsfs tvqq wsxzwklg nqgqlsd bnb jbmrj cpzphpj mdqt tpd bgjsmmk cfnxqwxl wwvskkqt hlqdhcjt cdwr qgnkf mhhmfw kkwq ndd bqw mgnfbjjm fwmgdn vrznbw sgqvm zqkj zxxl fbzpvkpf sdrdv kwtkz pnt lmqfsc xdqg gtwp lbwfl twffjh bczhjrg mfnpgj lgnhnxt zldxgtz zmwm tppxrzvc qmhpsbwm zqz bjwjjk xbqhbjz srlfjjxl rztzw fthvzqc kjbc qfrshq bdhlsfn jdxfmflq xxcr nknfth ppcd fpfjg wnbjfpxb xlz xzh gjttmmr khkg nqhkg dhbk zqpxdt sjcvxvqx jrrr tpvh qwqnhwzg rmkcw gpbvbq dvcpx pgdzjczr dgq bnkkv dqqzqgp tpmfhn qtrxfg hlf xxvwd nmmkz fdfm zqkfphvr cmkgbcrk fphzmgq ttx rxxvt xcd gnvjq qkprlzx sfrlqck drlxrmz zbnxwtq ckn tfx flnxpp jsgc lbfb rvhkzrcg thb fkxdhfgx fmgz jtgkqcg jgbwfj fpmxvvwx qnrzhb zcbvwfv gzpkfzb tlgxktvn dnw vkc bcctnt xvqx ffzwtw sxdnxkrr xjgzcnkl mskkwvq wvdbdrb ncw kqfc bfcnmf tkftr wvmhqws tfwqg vhdbd kpn kzkppvdx hdsrg zjwh vdzr rxd bntfzzg dgfqtp wwxgmrs rlgkl ggx pgvh gvdqvj dwjx vpx zhxwsm hjfkd kmhbb tffxqwx ssxdlrlg xnkl vdj vvvqvkt dtzdr rsbkttr zsjrgx ndtcfzn krdtfdnx jbrbz dpnb kscmpcv hww ztlmfx xjgsznp nptvhk tjzf drcvhb qwzgd crj jrggwgd hhrv jgnw lcjbd rvqm sxgqszt qvfz pkzzxl vgqccdb jvckq gsjgx bssxsgl jjlkz grkrmwl gvbv dlcsq ksv sqhtp zsngs ktxwlzcv bfmsx srs qnzwn tqdpml jthvdxn tnlf qmfxb bpdjs gjdjpndt ftn pzs gzslct zdqgxvd rlbvs kmxrllff sktwbqrw xpd pnxdtfh qqwrhpd jfgbndbl fxbx cqn dwch zqlr mdml dmll sjnnjtg nmkkrgz cmwvdwb chzpssnm kbj nsjhnk rplxrvfc sxn bnxmbsnj cgpld xfzkm zbfrhgbd xbjfdl ccz kwfrhd tlpgt jqsgd ctbjhjzk sngcd jzsj pcx cqjmfg dxzf cnm kkk jlk gdpn tbk dvpmzkbv bvdd xzfc lzfsrvtw fbf vmqsznl jrbzthww mfwzkrbb ffrtkrkt nlsnjqlj clvjxr mvr sxdgsc pwn njqzb xmcj pjvvqzj sqx sgrsljpm vmqgbm zgfxhqwt xnhjtkq tslbxnxx cxtgzd slvn wrgg fvd pkjvvqc scjskc djqw vskkg ftqdrqdt gprhkqwf sps jptghq crfpwk drhsjmhg cldnplf tttlzxb cdq lzkjjp fcfr zdjgx ftkvgm wvrm fxq jzsmlhn mfttvnjj knt tgxcmdvv vxcgpjfs sbhrw tnr rwsnldxb fbksps wswnxhkm fwd hqmp zrl qjzztbfx wtw hcsj lswsxpz rgvpvjmr rxvtj vdwt vnlqn llvkn hdkngmbc jxlffh slksjkfm rjdd jfscrc kvfvxx dtrlx zvwvw ffdlv zfvtkwsb qnbhhrk mjfxvz lmdfzq sstqtkct qzws shq jbv rkkf wcwzl jvwwlfs dzwprncj zxk szqwm zjrmf zkhq kklnqffb cfvdl xxrzlsbg fxjpqgfd kqscnbc ntk hpvq jltncl bpg scwvd rdn rvbxbgwc xqgzvt kbbgqj bzx tmnxc sktnxsl dgh kmm nrsv djsr mzdbf jhcbfqj rtdwpp zzgzpjgc jngdxg bswwfhd vmc nmt bwgrqwd jjtfgdcq jrtfj mphx shlqssf hdtn kxgt nvk mpcgtpl plf snp nnr hcsflf bmmbvk rfwhxth kjcf lxzf dfkwrx jqmfzl lvbdd qgxcwgnk gqfm lkv gftlv qxnjfsj bsjjs xsslpth hdp lqzfpxph vxvphqx rwqfdbwm kclnh swrlw jwzhp fnrxlxxg bmrklrqn srmqwqs zskbckdx xqdxv ljkmt xdvlw pcrqh tmp tmflb bsmfg mmxvzcj smdlk mhbf xlvxb fcdrwcpp hwv ldfzv dkfxwc vwfqk bgf mcnmpwpk wfhv fqfkhwb srgrbxq qgs hbkttrkf mslmvwn nsgptg kdwbxjd bdj vph tsxtk qkq zhxkhb rmjqzcb mfndgn wqss hlcn xkkc ntsg rlzr rwvcmpxq rppkgkt hzfbz zxlxs qxz nwl bgzjldt pdznwv jgbqxf tvbpbns hmfdjb xcprbcsw sdn wvfp cxwsf lzg cqmdvd nmmvw lzlchc crs qtmj vtfpfhbf rtsmrtrs jctxt rjrcnd xlpcwb cdhtpzm dzlkthz sjtxszxc');
 
1 row inserted
SQL> INSERT INTO PERGAMINHOS(PERGAMINHO_ID,NOME,PERGAMINHO) VALUES(PERGAMINHOS_SEQ.NEXTVAL,'Texto B','fwkp cxlzh pbzkzz vgpkhp gwpw zggswp xnwm dhxhxs rjgdpwg zfwbqf lvxk rtrxmn ljz flmjks ssgcff wkgsjfjg rfz lfxn vwl jtf zcgtn qfqk crtfv hdlhx bxts cqqwf xnz wjrbkvx cxxwbj ktrpdnvg stlwv mkkkg gfrttnc rwmtlcgx tmlxw grrfzjdc gzsjbl ljgh fmq jgslrqgl crnt dzztc dhmlmx pjwhmzrb nsttfp wbqnsz kgpv bpglstfp xtlsgrnz qntwgqf vxhmj wjmgvjw bcxkx rtxhtwjk mmxvb mnzz bgp tcvhvk swqgwn tpt csm gzrprs xsd svsqdjn dtfbdxs rxc ctgs hcsdlxs bkqj rkz hpcf npw kbkk pdg zxcph qcjkmpm xbhjz dcr gdtkvl vstwzmz lmctnhvw pzj gkgxqcg jlrcjfxt vbvw xccx gcl lmnbh zncnwz jbqqt sff grdfmq ppdl wvfr rzd xvv mzgkk cqtkm chszh grvjwcgn wtdkw xkn xnvqkp zwxs ljnjgcvj rdbchr vxrrc hfwsz nqt wsmmdk vxzwvrzq rvtnzpmv pfpq pwxrw hzdhcz rvts wmnxmh gjr mvrxpz bzsbfn hsr llnxhl rdqzhbxn prczfgdv csdsf qzzmqgp wzhdj sdnts mkrgqr xvvjf jgs hrdbrj pxszszp mjjzb pxlcqp bmrjjs kstmxqm nltp vfbkpnl ccgrxc xlhdd xgsm khkttd jlhzkkc lfwhmqp pxdqjxsh bjmlgnfh kfl zjvmq wqtb fwx rwtznp gjpw nvmx wfx sntbbjg nbq rkpjgx pcml vvh khkfqx hmlccvl stbblb czt pql gsnmvrvt fdrxzkw gzb dfw srhpgsjg hfxjfqb vjwdmdtv wffb kwqxp sxlf qzfjc hss rzzcbvg zrvmhqvp lnmx wfbt jvjhm xmmwr hwb grz mzltffc mnwx zhckw dhxpf dkgvm vsl pcxhlqmv vpwdstmp fxjtrrw vvqv dgrscjmt ffkf qnkqn rppnvdd cvtrbq xrmn ktgb svj kkwqln lhrhkb qbjhjmx xvxcbbsc wvnt znxd dpl jkxb tlwc smrsmwvx ltsjd hvtrwhf lrf wwmbjbl xwwk bmqnl xxnjnzd cwvhx rxggdmcp mrqhjp lkmqjg chqnztk lpvjtl dmcb xlfvx zpgtdfkf ptbtgdj dsbl sghdnv gszq dgq fndf cjcjh rldsf fwjrrrxl rxcs tnmshg psfjs kfft kqxtnt hgf mxkkl lldwtfqr hzbnb flj htqlrvzm lcr rsmfxgm fmncl hlmjr qshfhtl bcvmdnbr qvvvd sqwsvzl ftscmjsf mwkddmwn ffjm hslpw mlmkj vlbkp tgfg xsqms bvbln sdcrstgl ljw bzxpt hlb zhkzr bfmhlcd gjbtkb msmjpx mxwp dlrzctzm hclr vgsk hgxfxcmg bkh jrqzh wlrcgxxm kqtpcfd rtxzvqf llqhm vppvmc tmxsgnsj kqrnx tsdlcxnx chcnzfg dnf vxjd xdlxdcjz fvjndb tqsfmdh cggdz sjlkqxwf tczrzmn pmhcxqtv qrlpsc jwfdtxcp wfbnwrk fjt njtzt hwzvpvx fqdpsv wjg qvgxfmmk sldn nmvplk smnbmsfm cbvcsjj npghjddw bxbhjfjx ccpfdqx kcrccmfr nglzt sjdllsz dkk dpmqvj wkd kgpjvg ckmmkc ptzk ntpw kzpgqlrk nrlxb pmbfvnhw cvhvr cvqmtj gmtpprwm lwvddwfk qbqx gdn bmrrwdk lnglzfk qmdsccfz ddbxbpj jrjrlknp wgvh tcd cbhvgp drpz bcl crh nsbcqv gwdr lpnxgzwd shnd rffqg krhxcxql vmw kqzf pxkclht lgbbddd hvqdmrjr thgvzsmq knsw vcfnbm vnwb mbrkbt xfjl dclrh sbdvkg xxz pmjzlx zshzfslz dqb qgg njxtd cljtsl cfchlpl szfpnsj cpsbqpcx drmjm hfzvbgx lfndmtx sxb fpmjv hhxpx jjtsxfwd tstlf ptxvvtk lkrlrwcs jfpsqx dth zvcqvgv gxjthhc wjrptcf smck bjtwkl sbxtbdp qnkm cmzq wrwkkkq bpmcd gpzvv xzlkln jrp wpt smqpzr wtdk bwvs jxg cst wrnk tdpxq xxdbdzcc kfswx grpjch svjnnh ncdvrvtn dgqg bmnjcp lhx bgj whrrj xfgsvgt vpmpnb pnlqpzd xvhrtp wwwcvgw gcb pmkrf rfzthjpn qwlnssn vdm hhhk vzhznghb tzhw dtbb wzkdhrpg mbt kgkpxz bdnjn gxpwmvtq rkhq rtwtcww wzvq xmr jjpdft mdq gmxnzt dgcsmlgb qtwmqgdb dlw mnq jmcgqqf mcjhb nqmtq ptr gbzcvmrw mdkgtq xtjxzwf zqtfjzdt dxw zvmsd rfsppg tlswss lfdbcd fwwkw mqkhvwq sqksrz mzbx vhnpcqb hdh vzpmq hqlfvjdj kprhfmd vnwmvdt bxjwdjv hnc mnbkngg bplcm vhxct vppptmg jplqsq zvxdgjnh lkxwwg zzrtjnn tvjlg lshpnb csnl fbng xqcd cff hqzn mbklxsbz sgjts pkbdgds khsxwrkz jqwklmch hgdx kwk qqb kzgmlxw nmpb vmpsqkh hrc hrlkpd flqrslr sxctxfkh dzh dbtnhf mtfxggk knww zsjpf fdgcmfhl zhrb jxqhtksl dswwbkgk tcdqwh wbwsgqs rfcmv rwfj lts dnwzzw tjpvsr cbvbtzsp mnmhnkpd mksxqjdh bznx mfcldzk rsqdpwg hpqlbqm qntkf xxgjw tpdxpj thll sqsgbjlc pmjbrnf glnlcs rxfbkc lsgwhgv vqkjwksd lqbbxk sddzcmjk mrbdhf qdpj dttgxb hjz mxblmt ntsdmc vmbnnmbs vfz qwtj jtllmwj shpbpcf lrglxfd ttlphm hpsll gsqnr gpsq vfbqhjdx szhxfxlk hmbxpwt ljpnhnq hbsv dzlwb gbnxh pjr nbrldqs cpd cxmjtx hgvvzl dplr kwb snfs sntt vkkjhcvw bmqtjhqz lwqfsfg gthdm phh drfwn pmcp rhx jwzzwcg xzzmrmz vzmfzcl nzs sdvtdxnl hxlktxf rqc vjmc fhpvpbq vmlgqgpp bfkzzkjw qrz mfmxdpwq rhqgvrx wmv thtgt mffwd kjll spc bbd mdjnthsg hzk pqlkbpz');
 
1 row inserted
 
SQL> COMMIT;
 
Commit complete

Conferindo o PERGAMINHO_ID dos pergaminhos:
SQL> SELECT PERGAMINHO_ID, NOME FROM PERGAMINHOS;
 
PERGAMINHO_ID NOME
------------- --------
            1 Texto A
            2 Texto B

Executando o procedimento PERGAMINHOS_TO_PALAVRAS:
SQL> EXEC GOOGLE_DEV_DAY_BRASIL_2011.PERGAMINHO_TO_PALAVRAS(1);
 
PL/SQL procedure successfully completed
 
SQL> EXEC GOOGLE_DEV_DAY_BRASIL_2011.PERGAMINHO_TO_PALAVRAS(2);
 
PL/SQL procedure successfully completed
 
SQL> COMMIT;
 
Commit complete

Conferindo a geração das PALAVRAS dado os PERGAMINHOS:
SQL> SELECT COUNT(*) TOTAL FROM PALAVRAS;
 
     TOTAL
----------
      1200

Respondendo a primeira questão - preposição:
SQL> EXEC GOOGLE_DEV_DAY_BRASIL_2011.CALCULA_PREPOSICAO(1);
 
PL/SQL procedure successfully completed
 
SQL> EXEC GOOGLE_DEV_DAY_BRASIL_2011.CALCULA_PREPOSICAO(2);
 
PL/SQL procedure successfully completed
 
SQL> COMMIT;
 
Commit complete
 
SQL> SELECT PERGAMINHO_ID, NOME, PREPOSICAO FROM PERGAMINHOS;
 
PERGAMINHO_ID NOME     PREPOSICAO
------------- -------- ----------
            1 Texto A          56
            2 Texto B          66

Respondendo a segunda questão - verbo:
SQL> EXEC GOOGLE_DEV_DAY_BRASIL_2011.CALCULA_VERBO(1);
 
PL/SQL procedure successfully completed
 
SQL> EXEC GOOGLE_DEV_DAY_BRASIL_2011.CALCULA_VERBO(2);
 
PL/SQL procedure successfully completed
 
SQL> COMMIT;
 
Commit complete
 
SQL> SELECT PERGAMINHO_ID, NOME, VERBO FROM PERGAMINHOS;
 
PERGAMINHO_ID NOME          VERBO
------------- -------- ----------
            1 Texto A          72
            2 Texto B          77

Respondendo a terceira questão - verbo em primeira pessoa:
SQL> EXEC GOOGLE_DEV_DAY_BRASIL_2011.CALCULA_VERBO_PRIMEIRA_PESSOA(1);
 
PL/SQL procedure successfully completed
 
SQL> EXEC GOOGLE_DEV_DAY_BRASIL_2011.CALCULA_VERBO_PRIMEIRA_PESSOA(2);
 
PL/SQL procedure successfully completed
 
SQL> COMMIT;
 
Commit complete
 
SQL> SELECT PERGAMINHO_ID, NOME, VERBO_PRIMEIRA_PESSOA FROM PERGAMINHOS;
 
PERGAMINHO_ID NOME     VERBO_PRIMEIRA_PESSOA
------------- -------- ---------------------
            1 Texto A                     16
            2 Texto B                     27

Respondendo a quarta questão - lista de vocabulário:
SQL> EXEC GOOGLE_DEV_DAY_BRASIL_2011.PALAVRAS_TO_LISTA_VOCABULARIO(1);
 
PL/SQL procedure successfully completed
 
SQL> EXEC GOOGLE_DEV_DAY_BRASIL_2011.PALAVRAS_TO_LISTA_VOCABULARIO(2);
 
PL/SQL procedure successfully completed
 
SQL> COMMIT;
 
Commit complete
 
SQL> SELECT PERGAMINHO_ID, NOME, LISTA_VOCABULARIO FROM PERGAMINHOS;
 
PERGAMINHO_ID NOME     LISTA_VOCABULARIO
------------- -------- --------------------------------------------------------------------------------
            1 Texto A  ddcf ddrpbj dcrplxs dxzf dkfxwc djsr djqw dmdmwpk dmsbns dmll dvcpx dvpmzkbv drc
            2 Texto B  ddbxbpj dcr dclrh dxw dkk dkgvm dswwbkgk dsbl dmcb drmjm drfwn drpz dlrzctzm dlw

Respondendo a quinta questão - número bonito distinto:
SQL> EXEC GOOGLE_DEV_DAY_BRASIL_2011.CALCULA_NUMERO_BONITO_DISTINTO(1);
 
PL/SQL procedure successfully completed
 
SQL> EXEC GOOGLE_DEV_DAY_BRASIL_2011.CALCULA_NUMERO_BONITO_DISTINTO(2);
 
PL/SQL procedure successfully completed
 
SQL> COMMIT;
 
Commit complete
 
SQL> SELECT PERGAMINHO_ID, NOME, NUMERO_BONITO_DISTINTO FROM PERGAMINHOS;
 
PERGAMINHO_ID NOME     NUMERO_BONITO_DISTINTO
------------- -------- ----------------------
            1 Texto A                     117
            2 Texto B                      91

Algumas curiosidade que percebi nesta provinha:
  • Cada pergaminho possui 3899 caracteres, provavelmente está armazenado em Oracle com VARCHAR2(4000).
  • Cada pergaminho possui 600 palavras.
  • A maior palavra dos pergaminhos possuem 8 caracteres, 2³ = 8. Algum aficionado em base 2.
  • A prova tente ao desenvolvimento orientado a teste, para cada questão é fornecido um teste.
  • Expressão Regular resolve 3 questões.

Termino por aqui esse artigo. Parabéns aos que acompanharam o artigo até o final, porque realmente ficou extenso. Espero ter sido claro nas explicações, peço que divulguem o desafio, pois quanto mais pessoas participando, mais divertido fica. Caso tenha alguma sugestão para a implementação, fique a vontade em comentar.

Gostou do artigo? Ajude a divulgá-lo clicando no botão +1

9 comentários:

  1. Em PL/SQL folgou hein, por essa eu não esperava, muito bom.
    Não pensei em utilizar expressão regular, tem uma biblioteca bem simples de usar pra delphi, http://regexpstudio.com/TRegExpr/TRegExpr.html.

    Abraços.

    ResponderExcluir
  2. Pois é Fabricio !

    Quando vi as 3 primeira questões já me veio a ideia de usar Expressão Regular.

    Primeiro fiz testes utilizando o grep em CentOS, salvei em arquivo os pergaminhos, e editei deixando cada palavra em uma linha. Depois implementei em PL/SQL.

    Att,

    Sakamoto

    MyTraceLog - Registro de um DBA
    http://mytracelog.blogspot.com

    ResponderExcluir
  3. Em SQL foi extremamente épico! Caralho. Meus Parabéns!
    Espero ver você por lá :D
    A minha fiz em PHPsinho básico mesmo

    ResponderExcluir
  4. Uli Oreggia,

    Infelizmente não vou participar do evento, quem sabe ano que vem...

    Você vai publicar a sua solução em PHP? Já programei em PHP também, sei que é possível fazer soluções fantásticas! Mas atualmente estou treinando PL/SQL.

    Obrigado pela visita!

    Att,

    Sakamoto

    MyTraceLog - Registro de um DBA
    http://mytracelog.blogspot.com

    ResponderExcluir
  5. Kra, bem legal esse teu post. Eu achei bem interessante a prova. Meio que empaquei na 4, mas foi. Coloquei o projetículo Java lá no GitHub https://github.com/Belzebul/Google-Developer-Day-2011 (tentem fazer primeiro, não saiam copiando... ;-)). (Tb usei regex pra resolver as 3 primeiras).

    ResponderExcluir
  6. Olá FF!

    Primeiro, obrigado pela visita e pelo comentário!

    Analisando as suas Expressões Regulares, reparei que

    ^[^w]{4}[^w|^v|^k|^b|^p|^s]$ = ^[^w]{4}[^wvkbps]$

    Vou aproveitar para refatorar as minhas...

    Legal a solução em Java, mais uma solução diferente!

    Encontrei uma solução em Python, segue a solução:

    http://blog.viniciuscainelli.com/post/8723132144/resposta-google-developer-day-2011

    Att,

    Sakamoto

    MyTraceLog - Registro de um DBA
    http://mytracelog.blogspot.com

    ResponderExcluir
  7. fiz em python, é muito mais simples

    ResponderExcluir
  8. QUESTÃO D:

    ordem_zerg = 'tshjmpnzwlrcbxkqvdgf'ordem_normal = 'abcdefghijklmnopqrstuvxz'lista = []for x in txtB:    lista.append(x)lista_nova = []palavra_nova = ''for palavra in lista:    x = 0    palavra_nova = ''    while x < len(palavra):        palavra_nova = palavra_nova + ordem_normal[ordem_zerg.index(palavra[x])]        x = x + 1    lista_nova.append(palavra_nova)lista_nova = sorted(lista_nova) lista_nova2 = []palavra_nova2 = ''for palavra in lista_nova:    x = 0    palavra_nova2 = ''    while x < len(palavra):        palavra_nova2 = palavra_nova2 + ordem_zerg[ordem_normal.index(palavra[x])]        x = x + 1    lista_nova2.append(palavra_nova2)print(lista_nova2)

    ResponderExcluir

Gostou do artigo ? Então comente...

Related Posts Plugin for WordPress, Blogger...
 

FeedBurner

 
Voltar ao Topo