diff --git a/contains-duplicate/dusunax.py b/contains-duplicate/dusunax.py new file mode 100644 index 000000000..fb9255c70 --- /dev/null +++ b/contains-duplicate/dusunax.py @@ -0,0 +1,23 @@ +''' +# Leetcode 217. Contains Duplicate + +use set to store distinct elements 🗂️ + +## Time and Space Complexity + +``` +TC: O(n) +SC: O(n) +``` + +### TC is O(n): +- iterating through the list just once to convert it to a set. + +### SC is O(n): +- creating a set to store the distinct elements of the list. +''' + +class Solution: + def containsDuplicate(self, nums: List[int]) -> bool: + return len(nums) != len(set(nums)) + diff --git a/house-robber/dusunax.py b/house-robber/dusunax.py new file mode 100644 index 000000000..38c238942 --- /dev/null +++ b/house-robber/dusunax.py @@ -0,0 +1,44 @@ +''' +# Leetcode 198. House Robber + +use **dynamic programming** to solve this problem. (bottom-up approach) 🧩 + +choose bottom-up approach for less space complexity. + +## DP relation + +``` +dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]) +``` + +- **dp[i - 1]:** skip and take the value from the previous house +- **dp[i - 2]:** rob the current house, add its value to the maximum money from two houses before + +## Time and Space Complexity + +``` +TC: O(n) +SC: O(n) +``` + +### TC is O(n): +- iterating through the list just once to calculate the maximum money. = O(n) + +### SC is O(n): +- using a list to store the maximum money at each house. = O(n) + +''' + +class Solution: + def rob(self, nums: List[int]) -> int: + if len(nums) == 1: + return nums[0] + + dp = [0] * len(nums) + dp[0] = nums[0] + dp[1] = max(nums[0], nums[1]) + + for i in range(2, len(nums)): + dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]) + + return dp[-1] diff --git a/longest-consecutive-sequence/dusunax.py b/longest-consecutive-sequence/dusunax.py new file mode 100644 index 000000000..b912c4807 --- /dev/null +++ b/longest-consecutive-sequence/dusunax.py @@ -0,0 +1,38 @@ +''' +# Leetcode 128. Longest Consecutive Sequence + +keep time complexity O(n) by iterating through the set and accessing elements in O(1) time. ⚖️ + +## Time and Space Complexity +``` +TC: O(n) +SC: O(n) +``` + +### TC is O(n): +- iterating through the set. O(n) +- accessing elements in the set. O(1) +- while loop incrementing `current_num` while `current_num + 1 in nums_set`. O(1) + +### SC is O(n): +- creating a set from the list of numbers. O(n) +''' + +class Solution: + def longestConsecutive(self, nums: List[int]) -> int: + nums_set = set(nums) # O(n) + longest_sequence = 0 + + for num in nums_set: # O(n) + if (num - 1) not in nums_set: + current_num = num + current_sequence = 1 + + while current_num + 1 in nums_set: # O(1) + current_num += 1 + current_sequence += 1 + + longest_sequence = max(current_sequence, longest_sequence) + + return longest_sequence + diff --git a/top-k-frequent-elements/dusunax.py b/top-k-frequent-elements/dusunax.py new file mode 100644 index 000000000..1e8ee7a4c --- /dev/null +++ b/top-k-frequent-elements/dusunax.py @@ -0,0 +1,69 @@ +''' +# Leetcode 347. Top K Frequent Elements + +use **Counter** to count the frequency of each element in the list 🚀 + +- **solution 1**: use **sorted()** to sort the elements by their frequency in descending order. +- **solution 2**: use **bucket sort** to sort the elements by their frequency in descending order. (efficient!) + +## Time and Space Complexity + +### solution 1: topKFrequent() + +``` +TC: O(n log n) +SC: O(n) +``` + +#### TC is O(n log n): +- iterating through the list just once to count the frequency of each element. = O(n) +- sorting the elements by their frequency in descending order. = O(n log n) + +#### SC is O(n): +- using a Counter to store the frequency of each element. = O(n) +- sorted() creates a new list that holds the elements of frequency_map. = O(n) +- result list that holds the top k frequent elements. = O(k) + +### solution 2: topKFrequentBucketSort() + +``` +TC: O(n) +SC: O(n) +``` + +#### TC is O(n): +- iterating through the list just once to count the frequency of each element. = O(n) +- creating **buckets** to store the elements by their frequency. = O(n) +- iterating through the buckets in reverse order to get only the top k frequent elements. = O(n) + +#### SC is O(n): +- using a Counter to store the frequency of each element. = O(n) +- using buckets to store the elements by their frequency. = O(n) +- result list that holds only the top k frequent elements. = O(k) +''' + +class Solution: + def topKFrequent(self, nums: List[int], k: int) -> List[int]: + frequency_map = Counter(nums) # TC: O(n), SC: O(n) + sorted_frequencies = sorted(frequency_map.items(), key=lambda x: x[1], reverse=True) # TC: O(n log n), SC: O(n) + + result = [] # SC: O(k) + for e in sorted_frequencies: # TC: O(k) + result.append(e[0]) + + return result[0:k] + + def topKFrequentBucketSort(self, nums: List[int], k: int) -> List[int]: + frequency_map = Counter(nums) + n = len(nums) + buckets = [[] for _ in range(n + 1)] + + for num, freq in frequency_map.items(): + buckets[freq].append(num) + + result = [] + for i in range(len(buckets) - 1, 0, -1): + for num in buckets[i]: + result.append(num) + if len(result) == k: + return result diff --git a/valid-palindrome/dusunax.py b/valid-palindrome/dusunax.py new file mode 100644 index 000000000..52ee0fd1a --- /dev/null +++ b/valid-palindrome/dusunax.py @@ -0,0 +1,31 @@ +''' +# Leetcode 125. Valid Palindrome + +use `isalnum()` to filter out non-alphanumeric characters 🔍 + +## Time and Space Complexity + +``` +TC: O(n) +SC: O(n) +``` + +### TC is O(n): +- iterating through the string just once to filter out non-alphanumeric characters. O(n) + +### SC is O(n): +- `s.lower()` creates a new string. O(n) +- creating a new string `converted_s` to store the filtered characters. O(n) +- `converted_s[::-1]` creates a new reversed string. O(n) +''' + +class Solution: + def isPalindrome(self, s: str) -> bool: + if s == " ": + return True + + s = s.lower() + converted_s = ''.join(c for c in s if c.isalnum()) + + return converted_s == converted_s[::-1] +