Minha Estratégia para Estudar LeetCode

Sumário

Antes de tudo, não se pressione. Foque no longo prazo, fazendo um pouco todos os dias ou encaixando isso na sua agenda e seguindo o plano, combinado?

Com isso em mente, esta é minha estratégia para estudar LeetCode.

1. Comece pelo básico

No momento, estou estudando o básico de algoritmos, com foco em manipulação de strings no LeetCode, filtrando pelos problemas fáceis. Neste post, vou mostrar passo a passo o exercício 125. Valid Palindrome do LeetCode.

2. Estude o problema

Neste ponto, você deve ler e entender o problema. Você pode ver o problema aqui.

3. Escreva o código

Agora vou começar a explicar como estudo no LeetCode. Primeiro, foco em simplesmente resolver o problema, sem me preocupar em encontrar a solução mais otimizada. O objetivo é só ter uma solução que funcione, combinado?

Neste exemplo, começo resolvendo o problema com o seguinte código:

func isPalindrome(s string) bool {
    var reversed string
	var newS string

	for _, v := range s {
		if unicode.IsLetter(v) || unicode.IsDigit(v) {
			reversed += strings.ToLower(string(v))
			newS = strings.ToLower(string(v)) + newS
		}
	}
	return reversed == newS
}

Percebi que esta solução leva 1067 ms e usa 80,2 MB de memória. Nesse ponto, começo a procurar formas de melhorá-la.

4. Otimize o código

Aqui, trabalho para deixar a solução mais rápida e mais eficiente em memória:

func isPalindrome(s string) bool {
    var stringReversed string
	var sNew string
	lenString := len(s)
	count := 0

	for count != lenString {
		if unicode.IsLetter(rune(s[count])) || unicode.IsDigit(rune(s[count])) {
			sNew += strings.ToLower(string(s[count]))
			stringReversed = strings.ToLower(string(s[count])) + stringReversed
		}
		count++
	}

	return sNew == stringReversed
}

Notei que a solução atualizada agora leva 976 ms e usa 48,5 MB de memória. Nesse ponto, continuo refinando para ver se ainda dá para melhorar.

5. A última melhoria

Então percebi que, para validar um palíndromo, não preciso guardar nada em memória; só preciso comparar os caracteres em posições específicas. Com essa abordagem, minha solução melhorou muito.

func isPalindrome(s string) bool {
    for i, j := 0, len(s)-1; i < j; {
		if !isAlphaNumeric(s[i]) {
			i++
		} else if !isAlphaNumeric(s[j]) {
			j--
		} else if strings.ToLower(string(s[i])) != strings.ToLower(string(s[j])) {
			return false
		} else {
			i++
			j--
		}
	}
	return true
}


func isAlphaNumeric(s byte) bool {
	return (s >= 'a' && s <= 'z') || (s >= 'A' && s <= 'Z') || (s >= '0' && s <= '9')
}

Vi que esta solução otimizada agora leva 0 ms e usa apenas 4,5 MB de memória. Nesse ponto, vejo se ainda há espaço para melhorias, embora a solução já seja muito eficiente.

Aqui está um print das soluções no LeetCode:

Leetcode

6. Conclusão

Nestes passos, mostrei minha forma de estudar no LeetCode:

Primeiro, resolvo o problema sem me preocupar em encontrar a solução ideal, focando só em fazê-lo funcionar. Depois, tento refinar a solução para usar menos memória e rodar mais rápido. Por fim, penso em simplificações adicionais. Por exemplo, para validar um palíndromo, percebi que não preciso guardar nada em memória; só preciso comparar posições específicas dos caracteres. Essa abordagem melhorou muito minha solução. Esse método tem me ajudado a escrever código melhor no dia a dia, e espero que ajude você também!

Bons códigos! 🚀