diff --git a/algorithms_project/algorithms/arrays/exponential_search.py b/algorithms_project/algorithms/arrays/exponential_search.py index 0fcf494..e85d39e 100644 --- a/algorithms_project/algorithms/arrays/exponential_search.py +++ b/algorithms_project/algorithms/arrays/exponential_search.py @@ -1,34 +1,107 @@ +""" +Este código implementa duas versões de busca exponencial em arrays ordenados, +uma usando acesso direto ao array e outra simulando o ArrayReader do LeetCode 702. -def binary_search(nums, n, low, high): - while low < high: - mid = int((low + high)/2) +Objetivo: +- A classe Solution implementa a busca exponencial diretamente em um array normal. +- A classe Solution1 implementa a busca exponencial em um array de tamanho desconhecido + usando a interface ArrayReader, combinando exponential search com binary search. +- A classe ArrayReader simula a interface usada no LeetCode, retornando um valor + muito grande caso o índice acessado esteja fora do limite. +""" - if nums[mid] == n: - return mid - elif nums[mid] < n: - low = mid+1 - else: - high = mid - return -1 +# Simula o ArrayReader do LeetCode +class ArrayReader: + def __init__(self, arr): + # Armazena o array interno + self.arr = arr + def get(self, index: int) -> int: + # Se o índice está dentro do array, retorna o valor correspondente + if 0 <= index < len(self.arr): + return self.arr[index] + # Caso contrário, retorna um valor muito grande (simulando índice fora do array) + return 2**31 -1 -def exponencial_search(arr, target): - if arr[0] == target: - return 0 - n = len(arr) - i = 1 - while i < n and arr[i] < target: - i *= 2 +# Implementação de Exponential Search com acesso direto ao array +class Solution(): + @staticmethod + def binary_search(nums, n, low, high): + """ + Busca binária em um array ordenado entre os índices low e high. + Retorna o índice do elemento n ou -1 se não encontrado. + """ + while low < high: + # Calcula o índice do meio do intervalo + mid = int((low + high)/2) - if arr[i] == target: - return i + if nums[mid] == n: + # Encontrou o elemento + return mid + elif nums[mid] < n: + # Elemento está à direita + low = mid + 1 + else: + # Elemento está à esquerda + high = mid + # Não encontrou o elemento + return -1 - return binary_search(arr, target, i//2, min(i, n-1)) + def exponencial_search(self, arr, target): + """ + Busca exponencial em um array ordenado. + Primeiro encontra um intervalo em que o target pode estar, + depois aplica busca binária nesse intervalo. + """ + # Caso o primeiro elemento seja o target + if arr[0] == target: + return 0 + n = len(arr) + i = 1 + # Dobrar o índice até ultrapassar o target ou o tamanho do array + while i < n and arr[i] < target: + i *= 2 -d = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40] -target = 14 -result = exponencial_search(d, target) + # Caso o elemento esteja exatamente no índice encontrado + if arr[i] == target: + return i -print(f"Element found at index {result}") + # Aplicar busca binária no intervalo encontrado + return Solution.binary_search(arr, target, i//2, min(i, n-1)) + + +# Implementação de Exponential Search usando ArrayReader (tamanho desconhecido) +class Solution1(): + def search(self, reader: ArrayReader, target: int) -> int: + # Caso base: verifica o primeiro elemento + if reader.get(0) == target: + return 0 + + # 1) Busca exponencial para encontrar o intervalo + i = 1 + while reader.get(i) < target: + # Dobrar o índice até encontrar valor >= target + i *= 2 + + # 2) Busca binária dentro do intervalo [i//2, i] + low, high = i // 2, i + while low <= high: + # Índice do meio do intervalo + mid = (low + high) // 2 + # Valor no índice mid + val = reader.get(mid) + + if val == target: + # Encontrou o target + return mid + elif val > target: + # Target está à esquerda + high = mid - 1 + else: + # Target está à direita + low = mid + 1 + + # Target não encontrado + return -1 diff --git a/algorithms_project/algorithms/arrays/len_last_word.py b/algorithms_project/algorithms/arrays/len_last_word.py index 3d9213a..7dbfd62 100644 --- a/algorithms_project/algorithms/arrays/len_last_word.py +++ b/algorithms_project/algorithms/arrays/len_last_word.py @@ -1,21 +1,52 @@ +""" +Este código implementa duas soluções diferentes para o problema +"Length of Last Word" (LeetCode 58). + +Objetivo: +Dada uma string que contém palavras e espaços, retornar o comprimento +da última palavra (sequência de caracteres não vazios separados por espaços). + +A classe Solution resolve o problema manualmente usando ponteiros (left e right). +A classe Solution2 resolve de forma mais simples usando o método split() do Python. +""" + + class Solution(): def lengthOfLastWord(self, string_word: str) -> int: """ :type s: str :rtype: int """ - left, right = 0, 0 + # Incializa os poneiros left e right em 0 + left, right = 0, 0 + # Lista para armazenar as palavras encontradas words = [] + # Loop percorre a string até o final while right < len(string_word): + # Se o caractere atual não for espaço, move o ponteiro da direita if string_word[right] != ' ': - right += 1 + right += 1 else: + # Caso encontre espaço, adiciona a palavra entre left e right words.append(string_word[left:right]) + # Avança o ponteiro right para pular o espaço right += 1 + # Atualiza o ponteiro left para o próximo inicio de palavra left = right - + # após o loop, adiciona a ultima palavra capturada words.append(string_word[left:right]) - + # Retorna o tamanho da última palavra capturada + return len(words[-1]) + + +class Solution2(): + def lengthOfLastWord(self, string_word: str) -> int: + """ + :type s: str + :rtype: int + """ + # Usa split() para separar a string em palavras igorando múltiplos espaços + words = string_word.split() + # Retorna o comprimento da última palavra return len(words[-1]) - diff --git a/algorithms_project/tests/test_arrays/test_exponential_search.py b/algorithms_project/tests/test_arrays/test_exponential_search.py new file mode 100644 index 0000000..423e9d9 --- /dev/null +++ b/algorithms_project/tests/test_arrays/test_exponential_search.py @@ -0,0 +1,20 @@ +import pytest +from algorithms_project.algorithms.arrays.exponential_search import Solution, ArrayReader + + +@pytest.mark.parametrize("array,target,expected", [ + ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40], 14, 13), +]) +def test_exponential_search(array, target, expected): + assert Solution().exponencial_search(array, target) == expected + +@pytest.mark.parametrize("array,target,expected", [ + ([-1, 0, 3, 5, 9, 12], 9, 4), + ([-1, 0, 3, 5, 9, 12], 2, -1), +]) +def test_exponential_search_unknown_size(array, target, expected): + reader = ArrayReader(array) + assert Solution().exponencial_search(array, target) == expected diff --git a/algorithms_project/tests/test_arrays/test_len_last_word.py b/algorithms_project/tests/test_arrays/test_len_last_word.py index 2e97716..e327619 100644 --- a/algorithms_project/tests/test_arrays/test_len_last_word.py +++ b/algorithms_project/tests/test_arrays/test_len_last_word.py @@ -1,5 +1,5 @@ import pytest -from algorithms.arrays.len_last_word import Solution +from algorithms.arrays.len_last_word import Solution, Solution2 @pytest.mark.parametrize("string_word,expected", [ @@ -7,3 +7,10 @@ ]) def test_lengthOfLastWord(string_word, expected): assert Solution().lengthOfLastWord(string_word) == expected + + +@pytest.mark.parametrize("string_word,expected", [ + ("Hello World", 5), +]) +def test_lengthOfLastWord1(string_word, expected): + assert Solution2().lengthOfLastWord(string_word) == expected