29.12
2024
Já vi essa questão em uma entrevista de emprego. E confesso que pra desapontamento do entrevistador eu resolvi primeiro do jeito que ele não esperava e depois do jeito que ele esperava. A questão é a seguinte: Dado um número natural troque todas as ocorrências de um dado dígito, por um outra dado dígito. Ou seja, dado o int 1234138, troque os dígitos 3 por dígitos 5, resultando no int 1254158. Uma função assim:
int replace(int original, int from, int to);
Resolução Esperada
A resolução esperada, obviamente é utilização de matemática, e conhecimento de padrão da linguagem. Assim o esperado é que o candidato consiga utilizar potenciação para adicionar e remover o dígido individualmente.
Dessa forma o resultado seria:
#include <ctype.h>
#include <libgen.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int isnatural(char* s) {
while(*s) {
if (!isdigit(*s++))
return 0;
}
return 1;
}
int replace(int original, int from, int to) {
// sanity
if (original < 0 || from < 0 || from > 9 || to < 0 || to > 9)
return -1;
// 32bits ints -> 10 digits
int result = 0;
for (int ctdigit = 10; ctdigit--; ) {
int digit = original % (int)pow(10, ctdigit + 1) / pow(10, ctdigit);
if (digit == from)
digit = to;
result += digit * pow(10, ctdigit);
}
return result;
}
int main(int argc, char* argv[]) {
// arguments
if (argc < 4) {
fprintf(stderr, "%s: insuficient arguments\n", basename(argv[0]));
fprintf(stderr, "Usage: %s <ORIGINAL> <DIGIT-FROM> <DIGIT-TO>\n\n", basename(argv[0]));
return 1;
}
// arguments sanity
if (!isnatural(argv[1]) || !isnatural(argv[2]) || !isnatural(argv[3])) {
fprintf(stderr, "%s: invalid arguments, use only natural numbers\n", basename(argv[0]));
fprintf(stderr, "Usage: %s <ORIGINAL> <DIGIT-FROM> <DIGIT-TO>\n\n", basename(argv[0]));
return 1;
}
int numresult = replace(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]));
printf("%d\n", numresult);
return 0;
}
Testando na prática:
$ gcc -x c -o numericreplace numericreplace.c -lm
$ ./numericreplace 1234138 3 5
1254158
$
Resolução Alternativa
Essa resolução causou certo desapontamento ao entrevistador, e ele mesmo disse que não esperava tal solução. Porém a resolução alternativa é mais eficiente e mais simples que a esperada.
Ao invés de apelar pra matemática, eu simplesmente utilizei duas funções simples, sprintf e atoi. Primeiro eu converti de int para string, fiz a substituição de maneira bem rápida, e em seguida voltei a string pra int. Mais simples, mais rápido, e com menos código.
A solução ficou assim:
#include <ctype.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
int isnatural(char* s) {
while(*s) {
if (!isdigit(*s++))
return 0;
}
return 1;
}
int replace(int original, int from, int to) {
// sanity
if (original < 0 || from < 0 || from > 9 || to < 0 || to > 9)
return -1;
char szoriginal[12] = "";
char cfrom = '0' + from;
char cto = '0' + to;
sprintf(szoriginal, "%d", original);
char* s = szoriginal;
while(*s) {
if (*s == cfrom)
*s = cto;
s++;
}
return atoi(szoriginal);
}
int main(int argc, char* argv[]) {
// arguments
if (argc < 4) {
fprintf(stderr, "%s: insuficient arguments\n", basename(argv[0]));
fprintf(stderr, "Usage: %s <ORIGINAL> <DIGIT-FROM> <DIGIT-TO>\n\n", basename(argv[0]));
return 1;
}
// arguments sanity
if (!isnatural(argv[1]) || !isnatural(argv[2]) || !isnatural(argv[3])) {
fprintf(stderr, "%s: invalid arguments, use only natural numbers\n", basename(argv[0]));
fprintf(stderr, "Usage: %s <ORIGINAL> <DIGIT-FROM> <DIGIT-TO>\n\n", basename(argv[0]));
return 1;
}
int strresult = replace(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]));
printf("%d\n", strresult);
return 0;
}
E na prática:
$ gcc -x c -o stringreplace stringreplace.c
$ ./stringreplace 1234138 3 5
1254158
$
Profissionalmente
No caso da entrevista a solução falou a meu favor, o entrevistador afirmou que eu pensei fora da caixa para apresentar uma solução mais performática.
Mas no dia-a-dia profissional, o desenvolvedor tem que estar atento para não se ater 100% à solução esperada. O mais importante é o código correto, simples e fácil de manter. Uutilizar pequenas distorções para obter o mesmo resultado pode trazer soluções inesperadas e inovadoras.
Saber disso é muito importante, principalmente quando o cliente, ou o analista, gosta de definir como o código deve ser implementado, essa resposta é prerrogativa do programador, ou do arquiteto do código, em raríssimos casos do analista ou mesmo do cliente.
Sugestões dos Leitores
Também recebemos sugestões dos leitores. No caso abaixo o leitor Thiago Adams mandou uma solução diferente, utilizando aritmética. Veja a solução abaixo:
#include <assert.h>
#include <limits.h>
unsigned int replace(int original, int old_digit, int new_digit) {
// pre requisitos
assert(original >= 0);
assert(old_digit >= 0 && old_digit <= 10);
assert(new_digit >= 0 && new_digit <= 10);
if (original < 10) {
/* caso de um digito */
return (original == old_digit) ? new_digit : original;
}
unsigned int answer = 0;
unsigned int factor = 1;
while (original > 0) {
unsigned int r = original % 10;
if (r == old_digit)
r = new_digit;
answer = r * factor + answer;
original = original / 10;
factor = factor * 10;
}
return answer;
}
int main() {
assert(replace(0, 0, 1) == 1);
assert(replace(10, 0, 1) == 11);
assert(replace(2147483647, 7, 8) == 2148483648);
assert(replace(123, 3, 1) == 121);
assert(replace(123, 2, 5) == 153);
assert(replace(123, 1, 2) == 223);
assert(replace(1233, 3, 1) == 1211);
}