Obtenha 100 números palíndromos

7

Sou novo em scripts e tenho essa tarefa, que é encontrar 100 palíndromo números com o seguinte algoritmo:

  1. Obter um número aleatório de dois dígitos (maior que 10)
  2. Reverter o número
  3. Soma o número e seu reverso
  4. Se o resultado da soma for um número palíndromo, imprima-o. Caso contrário, volte para o passo 2

Por exemplo:

  • Número inicial: 75
  • O reverso é de 57
  • A soma é 75 + 57 = 132

Como 132 não é um número de palíndromo, volte para a etapa 2:

  • O reverso é de 321
  • 132 + 321 = 363
  • 363 é um número palíndromo. Imprima para stdout!

E assim por diante até imprimir 100 desses números.

Isso é o que eu tenho até agora:

#! /bin/bash

CONT=0
while [ $CONT -lt 100 ] 
do
    NUM= $RANDOM
    while [ $SUM -ne $SUMINV ] 
    do

        echo $NUM > file.txt
        INV= rev file.txt
        SUM= 'expr[ $NUM + $INV ]'
        echo $SUM > file2.txt
        SUMINV= rev file2.txt
        NUM= $SUM
    done
    echo $NUM
    CONT='expr $CONT + 1'
done

Procurando soluções e ajuda com este script!

    
por Panaman 07.11.2014 / 17:32

3 respostas

1

Pelo que entendi, primeiro você precisa receber um número de dois dígitos que

  • maior 10 e menos 100
  • não dividido por 10 (não 20; 30; etc)
  • não é palindrom (não 22; 33; etc)

Para que você possa alcançá-lo por

while :
do
  a=$[$RANDOM%10]
  b=$[$RANDOM%10]
  if [ $a -ne $b -a $a -ne 0 -a $b -ne 0 ]
  then
    NUM="$a$b"
    RNUM="$b$a"
    break
  fi
done

Próximo passo para verificar a soma do número e sua reversão

while :
do
  NUM=$[$NUM+$RNUM]
  RNUM=$(printf "%d" $NUM | rev)
  if [ $NUM -eq $RNUM ]
  then
    echo $NUM
    break
  fi
done
    
por 07.11.2014 / 18:07
1

Houve vários erros de sintaxe no seu script original. Por exemplo, foo= bar está errado, espaços são importantes no bash. Você precisa de foo=bar . Além disso, para obter a saída de um comando, você não pode fazer foo=command , você precisa colocar o comando em backticks ou, melhor, foo=$(command) . Aqui está uma versão de trabalho:

#!/usr/bin/env bash
CONT=0

## This array will hold the numbers we've seen
## uncomment this line for unique numbers
#declare -a seen;
while [ "$CONT" -lt 100 ] 
do
    ## Get a random number
    NUM=$RANDOM
    ## Make sure it is < 100
    let "NUM %= 100"
    ## Make sure the number is more than 10
    while [ "$NUM" -le 10 ]
    do
        NUM=$((NUM+1))
    done
    ## In case the addition made it longer than two digits
    NUM="${NUM:0:2}"
    ## Make sure the number does not end in 0
    ## If it does, we will get an error when
    ## attempting to add it. Bash doesn't
    ## like leading 0s. 
    [[ $NUM =~ 0$ ]] && let NUM++
    ## Sum the number and its reverse
    SUM=$((NUM+$(rev <<<$NUM)));

    ## Is this a palindrome?
    if [ "$SUM" = "$(rev <<<$SUM)" ]
    then
        ## You did not say if you wanted 100 different
        ## numbers. If so, uncomment these lines
        #let seen[$SUM]++
        ## If this number has not been seen before
        #if [ "${seen[$SUM]}" -eq 1 ]
        #   then
        ## print it
        echo $SUM
        ## increment the counter
        let CONT++
        #fi
    fi
done

Note que, como está, o script irá repetir números. Para obter números exclusivos, remova o comentário das linhas conforme descrito nos comentários do script.

    
por 07.11.2014 / 18:33
1

Este é divertido. Eu gosto dessa pergunta. Eu escrevi a seguinte função para executar a tarefa e fazer o trabalho.

palindromes() (
rev()   while getopts : o "-$1" ||
        ! r="${2#"${2%%[1-9]*}"}"
        do set -- "$1" "$OPTARG$2"
        done
rand()  { : & : "$(($1=$!))"; }

[ "$1" -gt 10 ] || exit
n=$1; set --
while OPTIND=1; rev "$n"
        case "$#.$n.$r"                              in
        (100.*) ! printf '%s\t%s\t%s\t%s\t%s\n' "$@" ;;
        (*.$r.$n) set -- "$@" "$n"; rand n           ;;
        (*)       n=$((${n#-}+${r%-}))               ;;
esac; do :; done
)

Há algumas coisas que são dignas de nota sobre isso. Em primeiro lugar, getopts é usado para inverter o número. A função primária de getopts é analisar as opções curtas que podem ou não estar todas juntas - e, portanto, é uma ferramenta conveniente para fazer o loop de todos os bytes de uma string.

Eu não gosto muito da função $RAND do bash shell, mas provavelmente é mais conservadora do que a minha função rand() que apenas faz uma tarefa no-op e atribui seu PID defunto a qualquer varname é armazenado em seu primeiro argumento. Muito barato, eu admito.

A construção case pode avaliar facilmente todas as facetas da sua tarefa em um teste simples. Eu faço:

case "$#.$n.$r" in 
(100*) all done; printf %s\n "$@";; 
(*$r.$n) palindrome; set -- "$@" "$n";;
(*) no luck; $n+$r; go again;;
esac

Eu tive muita dificuldade com isso no começo. No começo eu estava fazendo coisas como:

(*$r.$n) set -- ...; n=$((n+1))

Essa foi uma idéia ruim. A adição descontrolada imediatamente aumentou os números para tamanhos que a contagem de dígitos foi suficiente para afastar qualquer probabilidade de encontrar um palíndromo. Eu mexi com date +%S , mas achei que se eu fosse executar outro processo, eu poderia usar o PID. E esse processo, nesse caso, poderia ser apenas um nulo. De qualquer forma, o intervalo PID é pequeno o suficiente para reinar no fator runaway quase sempre, parece.

Por exemplo, vou executar isso agora e cole os resultados:

palindromes 76

OUTPUT

484     29292   49294   69296   89298
215512  50605   90609   446644  886688
123321  52625   92629   468864  663787366
134431  54645   94649   881585188       7667585634365857667
145541  23432   43434   63436   83438
147741  24442   44444   64446   84448
158851  25452   45454   65456   85458
169961  13231   46464   66466   86468
49985258994     27472   47474   67476   87478
14355341        28482   48484   68486   88488
395593  29492   49494   69496   89498
219912  121121  11244211        441144  881188
125521  165561  15522551        463364  7365409856589045637
136631  211112  17858768886785871       485584  893974888888479398
147741  23632   43634   63636   83638
149941  24642   44644   64646   84648
523325  25652   45654   65656   85658
567765  13331   46664   66666   86668
2358532 27672   47674   67676   87678
2236322 28682   48684   68686   88688

Existem provavelmente alguns enganados lá - isso acontece, aparentemente. Nao muitos. Eu não sei se isso é um problema para você ou não, mas isso é apenas um exemplo de como isso pode ser feito.

Uma última nota - executar isso em dash é muito mais rápido do que em bash ; embora a diferença pareça ser apenas um segundo ou mais. Em qualquer caso, se você usar , use dash para alterar a linha rev() set -- "$1" para set -- "${1#?}".

Acabei de perceber que há um requisito de dois dígitos - embora suspeite que essa regra específica seja uma tentativa de evitar que a tarefa seja muito difícil. De qualquer forma, obter apenas um subconjunto de uma string é muito fácil de fazer. Na verdade, é o que eu faço com r= quando eu:

r="${2#"${2%%[1-9]*}"}"

... que sempre atribui r um valor que não começa com zero.

Aqui está uma versão de rand() que sempre atribui um número de dois dígitos a $1 :

rand() { : & set -- "$1" "$!" "$(($!%100))"
         : "$(($1=($3>10?$3:${#2}$3)))"
}

Você pode aplicar a mesma lógica a bash $RAND , é claro. O operador $((var=(value)?(assign if true):(assign if false)))" ternary funcionará com praticamente qualquer conjunto inteiro. Aqui eu ou atribuo a ele o módulo de 100 (basicamente um percentil) se esse valor for maior que dez, senão eu atribuo isso como o segundo de dois dígitos onde o primeiro é uma contagem dos dígitos em $! .

Corra dessa forma e seus resultados são um pouco menos empolgantes:

333     66      484     1111    4884
77      88      99      121     121
363     484     77      4884    44044
88      99      121     121     363
484     1111    4884    88      8813200023188
99      121     121     363     484
1111    4884    44044   8813200023188   99
44      55      66      77      44
99      121     121     363     484
424     11      33      44      55
66      77      88      99      121
22      33      22      55      66
77      88      99      121     121
33      44      55      33      77
88      99      121     121     363
44      55      66      77      44
99      121     121     363     484
55      66      77      88      99
55      121     363     484     1111
66      77      88      99      121
    
por 08.11.2014 / 02:02