:PROPERTIES:
:ID:       93a43a24-6861-40c4-b45b-581977bb55cf
:END:
#+title: leetcode-arrays
#+filetags: :leetcode:notes:

* 217 - 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.

*Example 1:*

Input: nums = [1,2,3,1]

Output: true

Explanation: The element 1 occurs at the indices 0 and 3.

*Example 2:*

Input: nums = [1,2,3,4]

Output: false

Explanation: All elements are distinct.

*Example 3:*

Input: nums = [1,1,1,3,3,4,3,2,4,2]

Output: true

*Constraints:*

1 <= nums.length <= 105
-109 <= nums[i] <= 109

** Attempt:

Two loops
Outer loop will go through each element, inner loop will check if the element in outer loop is repeated in the array.

#+begin_src python
  class Solution(object):
    def containsDuplicate(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        for i in nums:
            for j in nums[i:len(nums)]:
                if i == j:
                    return True
        return False
      
#+end_src

Works? Yes, but there is a better solution

** Solution:

Use a [[id:3a41407c-661e-416a-80d2-4c7a137d153a][python-set]]. The reason is it does not allow for duplicates (it is unique). The solution is as follows:
We create a set from the array, then check if the length of the two are different, if they are then this indicates that there are duplicate values in the array. This is O(N) and is faster than the nested loops solution above.

#+begin_src python

  if len(set(nums)) == len(nums):
      return False
  else:
      return True

#+end_src

* 268 - Missing Number

Given an array `nums` containing `n` distinct numbers in the range [0, n], return the only number in the range that is missing from the array.

Example 1:
Input: nums = [3,0,1]

Output: 2
Explanation: n = 3 since there are 3 numbers, so all numbers are in the range [0,3]. 2 is the missing number in the range since it does not appear in nums.

Example 2:
Input: nums = [0,1]

Output: 2
Explanation: n = 2 since there are 2 numbers, so all numbers are in the range [0,2]. 2 is the missing number in the range since it does not appear in nums.

Example 3:
Input: nums = [9,6,4,2,3,5,7,0,1]

Output: 8
Explanation: n = 9 since there are 9 numbers, so all numbers are in the range [0,9]. 8 is the missing number in the range since it does not appear in nums.
 
Constraints:

    n == nums.length
    1 <= n <= 104
    0 <= nums[i] <= n
    All the numbers of nums are unique.

Follow up: Could you implement a solution using only O(1) extra space complexity and O(n) runtime complexity?

** Attempt
Sort the array, loop through it and check via the incrementor

#+begin_src python

  class Solution(object):
    def missingNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        nums.sort()
        for i in range(0, len(nums) + 1):
          if i not in nums:
            return i      

#+end_src

Problem here is that sort operation is O(nlogn) - too slow.

** Solution
One optimised solution:

#+begin_src python
  class Solution(object):
    def missingNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        nums.sort()
        n = len(nums)
        total_sum = n * (n + 1) // 2
        actual_sum = sum(nums)
        return total_sum - actual_sum
#+end_src

Another:
#+begin_src python
  class Solution(object):
      def missingNumber(self, nums):
          return sum(range(len(nums) + 1)) - sum(nums)
#+end_src

This is O(N)
len = O(1)
Range object creation is O(1)
sum is O(N)
+1 in range(n) because n would be excluded otherwise. ie if you did range(2) you get [0,1]

Some extra notes: 
[[id:125c81dc-c14f-4b4d-93c6-0a2b157735ac][python-dictionary]]

* 448 - Find all Numbers disappeared in an array
Given an array `nums` of `n` integers where `nums[i]` is in the range [1, n], return an array of all the integers in the range [1, n] that do not appear in nums.

Example 1:
Input: nums = [4,3,2,7,8,2,3,1]
Output: [5,6]

Example 2:
Input: nums = [1,1]
Output: [2]

Constraints:

n == nums.length
1 <= n <= 105
1 <= nums[i] <= n

Follow up: Could you do it without extra space and in O(n) runtime? You may assume the returned list does not count as extra space.

** Attempt
Create a set, loop through the set (it wont have duplicate values), if the counter is not equal to the value in the set, add it to a new list.

#+begin_src python
  class Solution(object):
      def findDisappearedNumbers(self, nums):
          """
          :type nums: List[int]
          :rtype: List[int]
          """
          new_set = set(nums)
          print(new_set)
          new_list = []
          for i in range(1, len(nums) + 1):
              if i not in new_set:
                  new_list.append(i)
          return new_list                  
#+end_src

Time: O(N) as iterating through the range and appending to new list if not in given list. O(N) space.

* 1 - Two Sum

Given an array of integers `nums` and an integer `target`, return indices of the two numbers such that they add up to target.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

You can return the answer in any order.

Example 1:
Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Explanation: Because nums[0] + nums[1] == 9, we return [0, 1].

Example 2:
Input: nums = [3,2,4], target = 6
Output: [1,2]

Example 3:
Input: nums = [3,3], target = 6
Output: [0,1]

Constraints:

    2 <= nums.length <= 104
    -109 <= nums[i] <= 109
    -109 <= target <= 109
    Only one valid answer exists.

Follow-up: Can you come up with an algorithm that is less than O(n2) time complexity?

** Attempt
Outer loop and inner loop

#+begin_src python
  class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        ret = []
        for i in range(0, len(nums) ):
          for j in range(i + 1, len(nums) ):
            if nums[i] + nums[j] == target:
              ret.append(nums[i])
              ret.append(nums[j])
        return ret

#+end_src

Bad as its O(N^2)

** Solution
Use a hashmap and loop once

After looking through the logic:
#+begin_src python
  class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        hm = {}
        ret = []
        for i in range(0, len(nums)):
          if (target - nums[i]) not in hm:
            hm.update({nums[i]: i})
          else:
            ret.append(i)
            ret.append(hm.get(target - nums[i]))
        return ret
        
#+end_src

[[~/master-folder/org_files/org_roam/assets/swappy-20250805-152411.png]]

Youtube solution:
#+begin_src python

  hash_map = {}
  for i , v in enumerate(nums):
      if target - v in hash_map:
          return i, hash_map[target - v]
      else:
          hash_map[v] = i

#+end_src

#+begin_src python

  hashMap = {}
  for indx, val in enumerate(nums):
      diff = target - val
      if diff in hashMap:
          return [indx, hashMap[diff]]
      hashMap[val] = indx

#+end_src

* 1365 - How Many Numbers Are Smaller Than the Current Number

Given the array `nums`, for each `nums[i]` find out how many numbers in the array are smaller than it. That is, for each `nums[i]` you have to count the number of valid j's such that j != i and nums[j] < nums[i].

Return the answer in an array.

Example 1:

Input: nums = [8,1,2,2,3]
Output: [4,0,1,1,3]
Explanation: 
For nums[0]=8 there exist four smaller numbers than it (1, 2, 2 and 3). 
For nums[1]=1 does not exist any smaller number than it.
For nums[2]=2 there exist one smaller number than it (1). 
For nums[3]=2 there exist one smaller number than it (1). 
For nums[4]=3 there exist three smaller numbers than it (1, 2 and 2).

Example 2:

Input: nums = [6,5,4,8]
Output: [2,1,0,3]

Example 3:

Input: nums = [7,7,7,7]
Output: [0,0,0,0]

Constraints:

    2 <= nums.length <= 500
    0 <= nums[i] <= 100

    #+begin_src python
      def smallerNumbersThanCurrent(nums):
      """
      :type nums: List[int]
      :rtype: List[int]
      """

      temp = sorted(nums)
      d = {}

      for i, num in enumerate(temp):
          if num not in d:
              d[num] = i
      ret = []

      for i in nums: 
          ret.append(d[i])
      return ret
      
    #+end_src
