diff --git a/algorithms/binarySearch.py b/algorithms/binarySearch.py index 425fd77..f95efae 100644 --- a/algorithms/binarySearch.py +++ b/algorithms/binarySearch.py @@ -22,3 +22,21 @@ def binarySearch(sortedArray,target): a=[1,2,3,4,5,6,7,8,9,10,11,12] print(binarySearch(a,9)) + + +def search(sortedArray, v) -> bool: + m = len(sortedArray) + if m == 0: + return False + idx = m//2 + print(f"a={sortedArray[idx]} and {sortedArray} and i:{idx}") + if sortedArray[idx] == v: + return True + elif sortedArray[idx] < v: + # search in [idx+1, m] + return search(sortedArray[idx+1:m],v) + else: + # search in [0, idx-1] + return search(sortedArray[0:idx],v) + +print(search(a,9)) diff --git a/algorithms/duplicates_in.py b/algorithms/duplicates_in.py new file mode 100644 index 0000000..99217c2 --- /dev/null +++ b/algorithms/duplicates_in.py @@ -0,0 +1,28 @@ +""" +Contains Duplicate +Given an integer array nums, return true if any value appears at least +twice in the array, and return false if every element is distinct. +Input: nums = [1,2,3,1] +Output: true + +Input: nums = [1,2,3,4] +Output: false + +Input: nums = [1,1,1,3,3,4,3,2,4,2] +Output: true +""" + +def duplicate_in(nums)-> bool: + encounters = [] + for i in nums: + if i not in encounters: + encounters.append(i) + else: + return True + return False + +assert duplicate_in([1,2,3,1]) + +assert not duplicate_in([1,2,3,4]) + +assert duplicate_in([1,1,1,3,3,4,3,2,4,2]) diff --git a/algorithms/max_subarray.py b/algorithms/max_subarray.py new file mode 100644 index 0000000..1539ff2 --- /dev/null +++ b/algorithms/max_subarray.py @@ -0,0 +1,71 @@ +""" +Given an integer array nums, find the +subarray with the largest sum, and return its sum. + +what is a subarray? it can be the array itself, or contiguous number from 1 to n elements +n <= len(array) + +Given nums = [-2,1,-3,4,-1,2,1,-5,4] +sub_array=[-2] sum=-2 +sub_array=[-2,1] sum=-1 +sub_array=[-2,1,-3] +sub_array=[4,-1,2,1] sum=6 will be the biggest +""" + + +def sum_array(nums: []) -> int: + """ + return the sum of the int within the given array + """ + sum = 0 + for i in nums: + sum+=i + return sum + +def build_sub_array(nums: [],i,j)-> []: + return nums[i:j] + +def max_subarray(nums: []) -> int: + """ + brut force method, build the contiguous sub array, compute the sum of sub array and + compare to the current max + """ + max = -10000 + subarray=[] + for i in range(0,len(nums)): + for j in range(i+1,len(nums)+1): + s_a=build_sub_array(nums,i,j) + sum_s_a=sum_array(s_a) + if sum_s_a> max: + max = sum_s_a + subarray=s_a + return (subarray,max) + +def better_sol(nums: []) -> int: + """ + For O(n) we need one loop and when current sum is < 0 then we change sub array + """ + max = -10000 + current_sum =0 + subarray=[] + new_idx=0 + for i in range(0,len(nums)): + current_sum +=nums[i] + if current_sum < 0: + current_sum = 0 + subarray=[] + new_idx=i+1 + else: + if current_sum > max: + max=current_sum + subarray=nums[new_idx:i+1] + + return (subarray,max) + +nums=[-2,1,-3,4,-1,2,1,-5,4] + +print(max_subarray(nums)) +assert ([4, -1, 2, 1], 6) == max_subarray(nums) +print(max_subarray([1])) +print(max_subarray([5,4,-1, 7, 8])) +print(better_sol(nums)) \ No newline at end of file diff --git a/algorithms/palindrome.py b/algorithms/palindrome.py new file mode 100644 index 0000000..26cd1b0 --- /dev/null +++ b/algorithms/palindrome.py @@ -0,0 +1,77 @@ +""" +Given an integer x, return true if x is a +palindrome, and false otherwise. + +palindrome a number or string that can be read from both direction. + +Could you solve it without converting the integer to a string? +""" +import math +def length(n: int) -> int: + l=1 + if (n < 0): + n=-n + while n >= 10: + n=n//10 + l+=1 + return l + +def is_palindrome(n: int) -> bool: + if n < 0: + return False + l = [] + nb_digits : int = length(n) + z=n + e=nb_digits-1 + while len(l) < nb_digits: + div = math.pow(10,e) + r = z % div + a = z // div + l.append(a) + z=r + e-=1 + print(div, a, r) + print(l) + i=0 + j=nb_digits-1 + while i<=j: + if l[i] != l[j]: + return False + i+=1 + j-=1 + return True + +def better_sol(n: int) -> bool: + """ + reverse the number and reversed and n should be the same. + To reverse the number add the rest of div / 10 to current reversed number * 10 + t=121 reversed = 1 + t=12 reversed = 12 + t=1 reversed = 121 + """ + if n < 0: + return False + reversed = 0 + temp = n + while temp != 0: + r = temp % 10 + reversed = reversed * 10 + r + temp //=10 + return reversed == n + +assert length(1) == 1 +assert length(12) == 2 +assert length(212) == 3 +assert length(-212) == 3 +assert length(3142) == 4 + +assert is_palindrome(1) +assert is_palindrome(11) +assert is_palindrome(121) +assert not is_palindrome(-121) +assert not is_palindrome(1341) +assert is_palindrome(1234321) +assert better_sol(1234321) + + + diff --git a/algorithms/remove_el.py b/algorithms/remove_el.py new file mode 100644 index 0000000..7a7cd5a --- /dev/null +++ b/algorithms/remove_el.py @@ -0,0 +1,65 @@ +""" +Remove element + +Given an integer array nums and an integer val, remove all occurrences of val +in nums in-place. +The order of the elements may be changed. Then return the number of elements +in nums which are not equal to val + +nums +""" +from typing import List + +def remove_element_1(nums: List[int],val: int) -> (int,List[int]): + c=0 + for i in range(0,len(nums)): + if nums[i] == val: + nums[i]=None + c+=1 + for k in range(0,len(nums)): + if nums[k] == None: + for j in range(k,len(nums)): + if nums[j] != None: + nums[k] = nums[j] + nums[j] = None + break + return (len(nums)-c,nums) + +def remove_element(nums: List[int],val: int) -> (int,List[int]): + c=0 + for i in range(0,len(nums)): + if nums[i] == val: + nums[i]= None + for k in range(len(nums)-1,i,-1): + if nums[k] != val and nums[k] != None: + nums[i]=nums[k] + nums[k]=None + break + c+=1 + return (len(nums)-c,nums) + +def better_sol(nums: List[int],val: int) -> (int,List[int]): + """ + use index of the non target element + """ + idx = 0 + for i in range(len(nums)): + if nums[i] != val: + nums[idx]= nums[i] + idx+=1 + return (idx,nums) + +nums=[3,2,2,3] +val=3 +expected_num=[2,2,None,None] + +k,en = remove_element(nums,val) +print(k,en) +assert k == 2 +assert expected_num == en +nums = [0,1,2,2,3,0,4,2] +val = 2 +k,en = better_sol(nums,val) +print(k,en) +assert k == 5 +assert en[0:k] == [0,1,3,0,4] diff --git a/algorithms/roman_to_int.py b/algorithms/roman_to_int.py new file mode 100644 index 0000000..caedc3d --- /dev/null +++ b/algorithms/roman_to_int.py @@ -0,0 +1,54 @@ +""" +Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M. +matching values 1,5,10,50,100,500,1000 +Roman numerals are usually written largest to smallest from left to right. + +Some rules to respect: +I can be placed before V (5) and X (10) to make 4 and 9. +X can be placed before L (50) and C (100) to make 40 and 90. +C can be placed before D (500) and M (1000) to make 400 and 900. + +Approach: parse roman number representation char by char and match the char read +to a k in a dict to get matching value. +""" + +symbols = { 'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000} + + +def roman_to_int(roman: str) -> int: + n=0 + i = 0 + previous = '' + while i < len(roman): + c = roman[i] + if (c == 'V' or c == 'X') and previous == 'I': + n=n+symbols[c]-2 + elif (c == 'L' or c == 'C') and previous == 'X': + n=n+symbols[c]-20 + elif (c == 'D' or c == 'M') and previous == 'C': + n=n+symbols[c]-200 + else: + n=n+symbols[c] + previous=c + i+=1 + return n + + +def better_sol(roman: str) -> int: + ans = 0 + + for i in range(len(roman)): + if i < len(roman) - 1 and symbols[roman[i]] < symbols[roman[i+1]]: + ans -= symbols[roman[i]] + else: + ans += symbols[roman[i]] + + return ans + +assert roman_to_int("III") == 3 +assert roman_to_int("IV") == 4 +assert roman_to_int("IX") == 9 +assert roman_to_int("XL") == 40 +assert roman_to_int("XC") == 90 +assert roman_to_int("LVII") == 57 +assert better_sol("MCMXCIV") == 1994 diff --git a/algorithms/two_sum.py b/algorithms/two_sum.py new file mode 100644 index 0000000..9e3b197 --- /dev/null +++ b/algorithms/two_sum.py @@ -0,0 +1,54 @@ +""" +Given an array of integers nums and an integer target, return indices +of the two numbers such that they add up to target. + +numbers are > 0, nums is not sorted, we can have the same number multiple times in nums + +Input: nums = [2,7,11,15], target = 9 +Output: [0,1] + +Input: nums = [3,2,4], target = 6 +Output: [1,2] + +O(log N) +""" +from typing import List + +def two_sum_O2(nums, target) -> (int, int): + """ + brute force is to loop over the array and look at the numbers above to find + the complement and return the first match + """ + for i in range(0,len(nums)-1): + for j in range(i+1,len(nums)): + if nums[i] + nums[j] == target: + return (i,j) + return (-1,-1) + + +def two_sum(nums: List[int], target: int) -> (int, int): + """ + loop over the list in one shot. + use a list of complement from current number to the target if there is no + one existing in the complements already + O(log(n)) + """ + complements=[] + for i in range(0,len(nums)): + # do we have a complement + comp = target-nums[i] + for j in range(0,len(complements)): + p_i, c = complements[j] + if nums[i] == c: + return (p_i,i) + if nums[i] < target: + complements.append((i,comp)) + return (-1,-1) + +a,b= two_sum([2,7,11,15],9) + +print(a,b) + +print(two_sum([3,2,4],6)) +print(two_sum([3,2,4],8)) +print(two_sum([3,3],6))