From 3d4d3c1b4537a11cc5adab20629d1b7eba55629b Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 30 Nov 2025 04:30:42 -0600 Subject: [PATCH] adding algo --- .../round_5/k_free_subsets.py | 110 ++++++++++++++++++ ...kids_with_the_greates_number_of_candies.py | 7 ++ .../majority_element.py | 20 ++++ .../rotate_array.py | 15 +++ .../test_majority_element_round_22.py | 17 +++ .../test_rotate_array_round_22.py | 11 ++ 6 files changed, 180 insertions(+) create mode 100644 src/my_project/interviews/amazon_high_frequency_23/round_5/k_free_subsets.py create mode 100644 src/my_project/interviews/amazon_high_frequency_23/round_5/kids_with_the_greates_number_of_candies.py create mode 100644 src/my_project/interviews/top_150_questions_round_22/majority_element.py create mode 100644 src/my_project/interviews/top_150_questions_round_22/rotate_array.py create mode 100644 tests/test_150_questions_round_22/test_majority_element_round_22.py create mode 100644 tests/test_150_questions_round_22/test_rotate_array_round_22.py diff --git a/src/my_project/interviews/amazon_high_frequency_23/round_5/k_free_subsets.py b/src/my_project/interviews/amazon_high_frequency_23/round_5/k_free_subsets.py new file mode 100644 index 00000000..fac52973 --- /dev/null +++ b/src/my_project/interviews/amazon_high_frequency_23/round_5/k_free_subsets.py @@ -0,0 +1,110 @@ +from typing import List, Union, Collection, Mapping, Optional +from collections import defaultdict + +class Solution: + def countTheNumOfKFreeSubsets(self, nums: List[int], k: int) -> int: + """ + Count k-Free subsets using dynamic programming. + + Approach: + 1. Group elements by (num % k) to find independent groups + 2. Within each group, sort and build chains where elements differ by k + 3. For each chain, use House Robber DP to count valid subsets + 4. Multiply results across all independent chains + + Time: O(n log n), Space: O(n) + """ + # Group numbers by their remainder when divided by k + groups = defaultdict(list) + for num in nums: + groups[num % k].append(num) + + res = 1 + + # Process each group independently + for group in groups.values(): + group.sort() + + # Build chains within this group + i = 0 + while i < len(group): + chain = [group[i]] + j = i + 1 + + # Build chain where each element is exactly k more than previous + while j < len(group) and group[j] == chain[-1] + k: + chain.append(group[j]) + j += 1 + + # House Robber DP for this chain + m = len(chain) + if m == 1: + chain_res = 2 # {} or {chain[0]} + else: + take = 1 # Take first element + skip = 1 # Skip first element + + for idx in range(1, m): + new_take = skip # Can only take current if we skipped previous + new_skip = take + skip # Can skip current regardless + take, skip = new_take, new_skip + + chain_res = take + skip + + res *= chain_res + i = j + + return res + + + + +''' +Detailed Algorithm Explanation +Part 1: Why Group by num % k? +Two numbers can have a difference of exactly k only if they have the same remainder when divided by k. + +Mathematical proof: + +If a - b = k, then a = b + k +Therefore: a % k = (b + k) % k = b % k +Example: nums = [2, 3, 5, 8], k = 5 + +num | num % 5 | group +----|---------|------- +2 | 2 | Group A +3 | 3 | Group B +5 | 0 | Group C +8 | 3 | Group B + + +Why this matters: Elements from different groups can never differ by k, so they're independent. We can combine any subset from Group A with any subset from Group B. + +Part 2: Building Chains +Within each group, we sort and find chains where consecutive elements differ by exactly k. + +Example with Group B: [3, 8] + +Sorted: [3, 8] +Check: 8 - 3 = 5 ✓ +Chain: 3 → 8 + +Another example: nums = [1, 6, 11, 21], k = 5 (all have remainder 1) + +Sorted: [1, 6, 11, 21] +Check: 6-1=5 ✓, 11-6=5 ✓, 21-11=10 ✗ +Chains: [1 → 6 → 11], [21] + + +Part 3: House Robber DP - The Core Logic +For a chain like [3 → 8], we can't pick both 3 and 8 (they differ by k). This is the House Robber problem: count all subsets where we don't pick adjacent elements. + +DP State Variables +take = number of valid subsets that INCLUDE the current element +skip = number of valid subsets that EXCLUDE the current element + +DP Transitions +new_take = skip # To take current, we MUST have skipped previous +new_skip = take + skip # To skip current, we can take or skip previous + +''' \ No newline at end of file diff --git a/src/my_project/interviews/amazon_high_frequency_23/round_5/kids_with_the_greates_number_of_candies.py b/src/my_project/interviews/amazon_high_frequency_23/round_5/kids_with_the_greates_number_of_candies.py new file mode 100644 index 00000000..7df648c7 --- /dev/null +++ b/src/my_project/interviews/amazon_high_frequency_23/round_5/kids_with_the_greates_number_of_candies.py @@ -0,0 +1,7 @@ +from typing import List, Union, Collection, Mapping, Optional +from abc import ABC, abstractmethod + +class Solution: + def kidsWithCandies(self, candies: List[int], extraCandies: int) -> List[bool]: + max_candies = max(candies) + return [candy + extraCandies >= max_candies for candy in candies] diff --git a/src/my_project/interviews/top_150_questions_round_22/majority_element.py b/src/my_project/interviews/top_150_questions_round_22/majority_element.py new file mode 100644 index 00000000..63cc12d5 --- /dev/null +++ b/src/my_project/interviews/top_150_questions_round_22/majority_element.py @@ -0,0 +1,20 @@ +from typing import List, Union, Collection, Mapping, Optional +from abc import ABC, abstractmethod + +class Solution: + def majorityElement(self, nums: List[int]) -> int: + + dic_answer = dict() + len_nums = len(nums) + + for i in range(len_nums): + + if nums[i] not in dic_answer: + dic_answer[nums[i]] = 1 + else: + dic_answer[nums[i]] += 1 + + if dic_answer[nums[i]] > len_nums//2: + return nums[i] + + return -1 \ No newline at end of file diff --git a/src/my_project/interviews/top_150_questions_round_22/rotate_array.py b/src/my_project/interviews/top_150_questions_round_22/rotate_array.py new file mode 100644 index 00000000..bc78d905 --- /dev/null +++ b/src/my_project/interviews/top_150_questions_round_22/rotate_array.py @@ -0,0 +1,15 @@ +from typing import List, Union, Collection, Mapping, Optional +from abc import ABC, abstractmethod + +class Solution: + def rotate(self, nums: List[int], k: int) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + + len_nums = len(nums) + k = k % len_nums + + nums[:] = nums[len_nums-k:] + nums[:len_nums-k] + + return nums diff --git a/tests/test_150_questions_round_22/test_majority_element_round_22.py b/tests/test_150_questions_round_22/test_majority_element_round_22.py new file mode 100644 index 00000000..d64c9011 --- /dev/null +++ b/tests/test_150_questions_round_22/test_majority_element_round_22.py @@ -0,0 +1,17 @@ +import unittest +from src.my_project.interviews.top_150_questions_round_22\ +.majority_element import Solution + +class MajorityElementTestCase(unittest.TestCase): + + def test_is_major_element(self): + solution = Solution() + output = solution.majorityElement(nums=[3,2,3]) + target = 3 + self.assertEqual(output, target) + + def test_is_no_major_element(self): + solution = Solution() + output = solution.majorityElement(nums = [1,2,3]) + target = -1 + self.assertEqual(output, target) \ No newline at end of file diff --git a/tests/test_150_questions_round_22/test_rotate_array_round_22.py b/tests/test_150_questions_round_22/test_rotate_array_round_22.py new file mode 100644 index 00000000..275983d0 --- /dev/null +++ b/tests/test_150_questions_round_22/test_rotate_array_round_22.py @@ -0,0 +1,11 @@ +import unittest +from src.my_project.interviews.top_150_questions_round_22\ +.rotate_array import Solution + +class RotateArrayTestCase(unittest.TestCase): + + def test_rotate_array_i(self): + solution = Solution() + output = solution.rotate(nums = [1,2,3,4,5,6,7], k = 3) + target = [5,6,7,1,2,3,4] + self.assertEqual(output, target) \ No newline at end of file