neetcode Flashcards

1
Q

Contains Duplicate:
Given an integer array nums, return true if any value appears more than once in the array, otherwise return false.

Example 1:

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

Output: true

Example 2:

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

Output: false

class Solution:
def hasDuplicate(self, nums: List[int]) -> bool:

A

class Solution:
def hasDuplicate(self, nums: List[int]) -> bool:
return len(set(nums)) < len(nums)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q
  1. Valid Anagram:
    Given two strings s and t, return true if t is an
    anagram
    of s, and false otherwise.

Example 1:

Input: s = “anagram”, t = “nagaram”

Output: true

Example 2:

Input: s = “rat”, t = “car”

Output: false

Constraints:

1 <= s.length, t.length <= 5 * 104
s and t consist of lowercase English letters.

Follow up: What if the inputs contain Unicode characters? How would you adapt your solution to such a case?

class Solution:
def isAnagram(self, s: str, t: str) -> bool:

A

class Solution:
def isAnagram(self, s: str, t: str) -> bool:
if len(s) != len(t):
return False

    count = [0] * 26
    for i in range(len(s)):
        count[ord(s[i]) - ord('a')] += 1
        count[ord(t[i]) - ord('a')] -= 1

    for val in count:
        if val != 0:
            return False

    return True
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Two Sum:
Given an array of integers nums and an integer target, return the indices i and j such that nums[i] + nums[j] == target and i != j.

You may assume that every input has exactly one pair of indices i and j that satisfy the condition.

Return the answer with the smaller index first.

Example 1:

Input:
nums = [3,4,5,6], target = 7

Output: [0,1]
Explanation: nums[0] + nums[1] == 7, so we return [0, 1].

Example 2:

Input: nums = [4,5,6], target = 10

Output: [0,2]
Example 3:

Input: nums = [5,5], target = 10

Output: [0,1]
Constraints:

2 <= nums.length <= 1000
-10,000,000 <= nums[i] <= 10,000,000
-10,000,000 <= target <= 10,000,000

class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:

A

class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
prevMap = {} #val->index

    for i, n in enumerate(nums):
        difference = target - n
        if difference in prevMap:
            return [prevMap[difference], i]
        prevMap[n] = i
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Group Anagrams
Given an array of strings strs, group all anagrams together into sublists. You may return the output in any order.

An anagram is a string that contains the exact same characters as another string, but the order of the characters can be different.

Example 1:

Input: strs = [“act”,”pots”,”tops”,”cat”,”stop”,”hat”]

Output: [[“hat”],[“act”, “cat”],[“stop”, “pots”, “tops”]]
Example 2:

Input: strs = [“x”]

Output: [[“x”]]
Example 3:

Input: strs = [””]

Output: [[””]]
Constraints:

1 <= strs.length <= 1000.
0 <= strs[i].length <= 100
strs[i] is made up of lowercase English letters.

class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:

A

class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
res = defaultdict(list) #map char count to list of anagrams

    for s in strs:
        count = [0] * 26 # a...z

        for c in s:
            count[ord(c) - ord("a")] += 1 #ascii values
        res[tuple(count)].append(s)

    return list(res.values())
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Top K Frequent Elements:
Given an integer array nums and an integer k, return the k most frequent elements within the array.

The test cases are generated such that the answer is always unique.

You may return the output in any order.

Example 1:

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

Output: [2,3]
Example 2:

Input: nums = [7,7], k = 1

Output: [7]
Constraints:

1 <= nums.length <= 10^4.
-1000 <= nums[i] <= 1000
1 <= k <= number of distinct elements in nums.

class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:

A

class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
#O(n) -> modified bucket sort, table example:
#i (count) : 0 1 2 …
#values : [10] [2] [4,2] …
#this is better because the i(count) row is always size of array, always
#bounded, never wasting time/space
count = {} #hashmap
frequencies = [[] for i in range(len(nums) + 1)] #size of input + 1

    for n in nums:
        count[n] = 1 + count.get(n,0)
    for n, c in count.items(): #for every number and count
        frequencies[c].append(n)

    result = []

    for i in range(len(frequencies) - 1, 0, -1): #descending order to find top k 
        for n in frequencies[i]:
            result.append(n) #append most freq
            if len(result) == k:
                return result
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Encode and Decode Strings:
Design an algorithm to encode a list of strings to a single string. The encoded string is then decoded back to the original list of strings.

Please implement encode and decode

Example 1:

Input: [“neet”,”code”,”love”,”you”]

Output:[“neet”,”code”,”love”,”you”]
Example 2:

Input: [“we”,”say”,”:”,”yes”]

Output: [“we”,”say”,”:”,”yes”]
Constraints:

0 <= strs.length < 100
0 <= strs[i].length < 200
strs[i] contains only UTF-8 characters.

class Solution:

def encode(self, strs: List[str]) -> str:

def decode(self, s: str) -> List[str]:
A

class Solution:

#make a list in the string itself INSTEAD OF SEPARATE DATA STRUCUTURE to store
#lengths of each element
#make a code w number length, then delimeter, then word, for all words
#e.g. "4#neet", "5#co#de", these all work and won't get confused
def encode(self, strs: List[str]) -> str:
    result = ""
    for s in strs:
        result += str(len(s)) + "#" + s #"4#neet"
    return result

def decode(self, s: str) -> List[str]:
    result = []
    i = 0 #ptr
    while i < len(s):
        j = i #find end of integer
        while s[j] != "#": #we're still at integer character
            j += 1 #increment until you reach pound delimeter
        length = int(s[i:j]) #from i to j, this is the string integer (convert)
        result.append(s[j + 1 : j + 1 + length])
        i = j + 1 + length #beginning of next string OR end of current string 
    return result
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Products of Array Except Self:
Given an integer array nums, return an array output where output[i] is the product of all the elements of nums except nums[i].

Each product is guaranteed to fit in a 32-bit integer.

Follow-up: Could you solve it in
O
(
n
)
O(n) time without using the division operation?

Example 1:

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

Output: [48,24,12,8]
Example 2:

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

Output: [0,-6,0,0,0]
Constraints:

2 <= nums.length <= 1000
-20 <= nums[i] <= 20

class Solution:

def productExceptSelf(self, nums: List[int]) -> List[int]:
A

class Solution:

#get the product of every value of left of value, then every value on right
#then multiply altogether
#compute all prefixes and postfixes (assume "1" if on very left/right)
#then, for each index, multiply prefix on left and postfix on right of element
def productExceptSelf(self, nums: List[int]) -> List[int]:
    result = [1] * len(nums)
    
    prefix = 1
    for i in range(len(nums)):
        result[i] = prefix
        prefix *= nums[i]

    postfix = 1
    for i in range(len(nums) - 1, -1, -1):
        result[i] *= postfix
        postfix *= nums[i]

    return result
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Longest Consecutive Sequence:
Given an array of integers nums, return the length of the longest consecutive sequence of elements that can be formed.

A consecutive sequence is a sequence of elements in which each element is exactly 1 greater than the previous element. The elements do not have to be consecutive in the original array.

You must write an algorithm that runs in O(n) time.

Example 1:

Input: nums = [2,20,4,10,3,4,5]

Output: 4
Explanation: The longest consecutive sequence is [2, 3, 4, 5].

Example 2:

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

Output: 7
Constraints:

0 <= nums.length <= 1000
-10^9 <= nums[i] <= 10^9

class Solution:

def longestConsecutive(self, nums: List[int]) -> int:
A

class Solution:
#group items by sequences, figure it out if there’s left neighbor
#e.g. in [100,4,200,1,3,2], sequences -> [1,2,3,4] , [100] , [200]
#notice how there’s no 0, 99, or 199 AKA one less than seq. AKA no left
#meaning that sequence ONLY STARTS if there’s no left value, so like at 4
#it isn’t start of sequence because there’s a 3 on the left
#O(n) time
def longestConsecutive(self, nums: List[int]) -> int:
numSet = set(nums)
longest_sequence = 0

    for n in nums:
        if (n -1) not in numSet: #check if start of sequence
            length = 0
            while (n + length) in numSet:
                length += 1
            longest_sequence = max(length, longest_sequence)
        
    return longest_sequence
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Valid Palindrome:
Given a string s, return true if it is a palindrome, otherwise return false.

A palindrome is a string that reads the same forward and backward. It is also case-insensitive and ignores all non-alphanumeric characters.

Example 1:

Input: s = “Was it a car or a cat I saw?”

Output: true
Explanation: After considering only alphanumerical characters we have “wasitacaroracatisaw”, which is a palindrome.

Example 2:

Input: s = “tab a cat”

Output: false
Explanation: “tabacat” is not a palindrome.

Constraints:

1 <= s.length <= 1000
s is made up of only printable ASCII characters.

class Solution:
def isPalindrome(self, s: str) -> bool:

A

class Solution:
def isPalindrome(self, s: str) -> bool:
newStr = ‘’
for c in s:
if c.isalnum():
newStr += c.lower()
return newStr == newStr[::-1]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

3Sum:
Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] where nums[i] + nums[j] + nums[k] == 0, and the indices i, j and k are all distinct.

The output should not contain any duplicate triplets. You may return the output and the triplets in any order.

Example 1:

Input: nums = [-1,0,1,2,-1,-4]

Output: [[-1,-1,2],[-1,0,1]]
Explanation:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0.
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0.
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0.
The distinct triplets are [-1,0,1] and [-1,-1,2].

Example 2:

Input: nums = [0,1,1]

Output: []
Explanation: The only possible triplet does not sum up to 0.

Example 3:

Input: nums = [0,0,0]

Output: [[0,0,0]]
Explanation: The only possible triplet sums up to 0.

Constraints:

3 <= nums.length <= 1000
-10^5 <= nums[i] <= 10^5

class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:

A

class Solution: #O(n^2)
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
res = []

    for i in range(len(nums) - 2):
        if i > 0 and nums[i] == nums[i-1]:
            continue
        l, r = i + 1, len(nums) - 1
        while l < r:
            s = nums[i] + nums[l] + nums[r]
            if s < 0:
                l += 1
            elif s > 0:
                r -= 1
            else:
                res.append([nums[i], nums[l], nums[r]])
                while l < r and nums[l] == nums[l+1]:
                    l += 1
                while l < r and nums[r] == nums[r-1]:
                    r -= 1
                l += 1
                r-= 1
                
    return res
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Container With Most Water:
You are given an integer array heights where heights[i] represents the height of the i-th bar.

You may choose any two bars to form a container. Return the maximum amount of water a container can store.

Example 1:

Input: height = [1,7,2,5,4,7,3,6]

Output: 36
Example 2:

Input: height = [2,2,2]

Output: 4
Constraints:

2 <= height.length <= 1000
0 <= height[i] <= 1000

class Solution:
def maxArea(self, heights: List[int]) -> int:

A

class Solution:
def maxArea(self, heights: List[int]) -> int:
left, right = 0, len(heights)-1
res = 0

    while left < right:
        area = min(heights[left], heights[right]) * (right-left)
        res = max(res,area)
        if heights[left] <= heights[right]:
            left += 1
        else:
            right -= 1
    
    return res
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Best Time to Buy and Sell Stock:
You are given an integer array prices where prices[i] is the price of NeetCoin on the ith day.

You may choose a single day to buy one NeetCoin and choose a different day in the future to sell it.

Return the maximum profit you can achieve. You may choose to not make any transactions, in which case the profit would be 0.

Example 1:

Input: prices = [10,1,5,6,7,1]

Output: 6
Explanation: Buy prices[1] and sell prices[4], profit = 7 - 1 = 6.

Example 2:

Input: prices = [10,8,7,5,2]

Output: 0
Explanation: No profitable transactions can be made, thus the max profit is 0.

Constraints:

1 <= prices.length <= 100
0 <= prices[i] <= 100

class Solution:

def maxProfit(self, prices: List[int]) -> int:
A

class Solution:
#init left ptr on day one, right ptr on day two
def maxProfit(self, prices: List[int]) -> int:
l, r = 0, 1 #left is buying, right is selling
max_profit = 0

    while r < len(prices):
        if prices[l] < prices[r]: #check if profitable
            profit = prices[r] - prices[l]
            max_profit = max(profit, max_profit)
        else:
            l = r #shift all the way to the right; we found the lowest price
        r += 1

    return max_profit
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Longest Substring Without Repeating Characters:
Given a string s, find the length of the longest substring without duplicate characters.

A substring is a contiguous sequence of characters within a string.

Example 1:

Input: s = “zxyzxyz”

Output: 3
Explanation: The string “xyz” is the longest without duplicate characters.

Example 2:

Input: s = “xxxx”

Output: 1
Constraints:

0 <= s.length <= 1000
s may consist of printable ASCII characters.

class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:

A

class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
char_set = set()
l = 0
result = 0

    for r in range(len(s)):
        while s[r] in char_set: #duplicate
            char_set.remove(s[l])
            l += 1
        char_set.add(s[r])
        result = max(result, r-l + 1)

    return result
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Longest Repeating Character Replacement:
You are given a string s consisting of only uppercase english characters and an integer k. You can choose up to k characters of the string and replace them with any other uppercase English character.

After performing at most k replacements, return the length of the longest substring which contains only one distinct character.

Example 1:

Input: s = “XYYX”, k = 2

Output: 4
Explanation: Either replace the ‘X’s with ‘Y’s, or replace the ‘Y’s with ‘X’s.

Example 2:

Input: s = “AAABABB”, k = 1

Output: 5
Constraints:

1 <= s.length <= 1000
0 <= k <= s.length

class Solution:
def characterReplacement(self, s: str, k: int) -> int:

A

class Solution:
#hashmap/array to count occurences of char
#do window length - count[each index] to figure out with window/substring, which
#needs to be replaced
def characterReplacement(self, s: str, k: int) -> int:
count = {}
res = 0

    l = 0
    maxf = 0
    for r in range(len(s)):
        count[s[r]] = 1 + count.get(s[r], 0)
        maxf = max(maxf, count[s[r]])

        while (r - l + 1) - maxf > k:
            count[s[l]] -= 1
            l += 1
        res = max(res, r - l + 1)

    return res
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Valid Parentheses:
You are given a string s consisting of the following characters: ‘(‘, ‘)’, ‘{‘, ‘}’, ‘[’ and ‘]’.

The input string s is valid if and only if:

Every open bracket is closed by the same type of close bracket.
Open brackets are closed in the correct order.
Every close bracket has a corresponding open bracket of the same type.
Return true if s is a valid string, and false otherwise.

Example 1:

Input: s = “[]”

Output: true
Example 2:

Input: s = “([{}])”

Output: true
Example 3:

Input: s = “[(])”

Output: false
Explanation: The brackets are not closed in the correct order.

Constraints:

1 <= s.length <= 1000

class Solution:
def isValid(self, s: str) -> bool:

A

O(n^2)

class Solution:
def isValid(self, s: str) -> bool:
while ‘()’ in s or ‘{}’ in s or ‘[]’ in s:
s = s.replace(‘()’, ‘’)
s = s.replace(‘{}’, ‘’)
s = s.replace(‘[]’, ‘’)
return s == ‘’

class Solution:
def isValid(self, s: str) -> bool:
stack = []
# Create a mapping of closing parentheses to opening parentheses
mapping = {‘)’: ‘(‘, ‘}’: ‘{‘, ‘]’: ‘[’}

    for char in s:
        if char in mapping:
            # If the stack is empty or the top of the stack doesn't match the corresponding opening parenthesis
            top_element = stack.pop() if stack else '#'
            if top_element != mapping[char]:
                return False
        else:
            # Push the opening parenthesis onto the stack
            stack.append(char)
    
    # If the stack is empty, all parentheses are valid
    return not stack #O(n)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Find Minimum in Rotated Sorted Array:
You are given an array of length n which was originally sorted in ascending order. It has now been rotated between 1 and n times. For example, the array nums = [1,2,3,4,5,6] might become:

[3,4,5,6,1,2] if it was rotated 4 times.
[1,2,3,4,5,6] if it was rotated 6 times.
Notice that rotating the array 4 times moves the last four elements of the array to the beginning. Rotating the array 6 times produces the original array.

Assuming all elements in the rotated sorted array nums are unique, return the minimum element of this array.

A solution that runs in O(n) time is trivial, can you write an algorithm that runs in O(log n) time?

Example 1:

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

Output: 1
Example 2:

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

Output: 0
Example 3:

Input: nums = [4,5,6,7]

Output: 4
Constraints:

1 <= nums.length <= 1000
-1000 <= nums[i] <= 1000

class Solution:

def findMin(self, nums: List[int]) -> int:
A

class Solution:

#binary search -> O(log n)
#nums[m] >= nums[l]: search right
#else: search left
def findMin(self, nums: List[int]) -> int:
    l,r = 0, len(nums)-1

    while l < r:
        m = l + (r-l) // 2
        if nums[m] < nums[r]:
            r = m
        else:
            l = m +1
    return nums[l]
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

Search in Rotated Sorted Array:
You are given an array of length n which was originally sorted in ascending order. It has now been rotated between 1 and n times. For example, the array nums = [1,2,3,4,5,6] might become:

[3,4,5,6,1,2] if it was rotated 4 times.
[1,2,3,4,5,6] if it was rotated 6 times.
Given the rotated sorted array nums and an integer target, return the index of target within nums, or -1 if it is not present.

You may assume all elements in the sorted rotated array nums are unique,

A solution that runs in O(n) time is trivial, can you write an algorithm that runs in O(log n) time?

Example 1:

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

Output: 4
Example 2:

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

Output: -1
Constraints:

1 <= nums.length <= 1000
-1000 <= nums[i] <= 1000
-1000 <= target <= 1000

class Solution:
def search(self, nums: List[int], target: int) -> int:

A

class Solution:
def search(self, nums: List[int], target: int) -> int:
l, r = 0, len(nums) - 1

    while l <= r: #we do <= if array size is just one
        mid = (l + r) // 2
        if target == nums[mid]:
            return mid

        #check if we're in left portion
        if nums[l] <= nums[mid]:
            if target > nums[mid] or target < nums[l]:
                l = mid + 1
            else: #less than m but > l
                r = mid - 1
             
        #check if we're in right portion   
        else:
            if target < nums[mid] or target > nums[r]:
                r = mid - 1
            else:
                l = mid + 1
    return -1
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

class ListNode:

Reverse Linked List:
Given the beginning of a singly linked list head, reverse the list, and return the new beginning of the list.

Example 1:

Input: head = [0,1,2,3]

Output: [3,2,1,0]
Example 2:

Input: head = []

Output: []
Constraints:

0 <= The length of the list <= 1000.
-1000 <= Node.val <= 1000

Definition for singly-linked list.
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next

class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:

A

class ListNode:

Definition for singly-linked list.
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next

class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
previous = None
current = head
while current:
next_node = current.next
current.next = previous
previous = current
current = next_node
return previous

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

Merge Two Sorted Linked Lists:
You are given the heads of two sorted linked lists list1 and list2.

Merge the two lists into one sorted linked list and return the head of the new sorted linked list.

The new list should be made up of nodes from list1 and list2.

Example 1:

Input: list1 = [1,2,4], list2 = [1,3,5]

Output: [1,1,2,3,4,5]
Example 2:

Input: list1 = [], list2 = [1,2]

Output: [1,2]
Example 3:

Input: list1 = [], list2 = []

Output: []
Constraints:

0 <= The length of the each list <= 100.
-100 <= Node.val <= 100

Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next

class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:

A

Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next

class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
temp = ListNode()
node = ListNode()
temp = node

        while list1 and list2:
            if list1.val < list2.val:
                node.next = list1
                list1 = list1.next
            else:
                node.next = list2
                list2 = list2.next
            node = node.next

        node.next = list1 or list2

        return temp.next
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

Linked List Cycle Detection:
Given the beginning of a linked list head, return true if there is a cycle in the linked list. Otherwise, return false.

There is a cycle in a linked list if at least one node in the list that can be visited again by following the next pointer.

Internally, index determines the index of the beginning of the cycle, if it exists. The tail node of the list will set it’s next pointer to the index-th node. If index = -1, then the tail node points to null and no cycle exists.

Note: index is not given to you as a parameter.

Example 1:

Input: head = [1,2,3,4], index = 1

Output: true
Explanation: There is a cycle in the linked list, where the tail connects to the 1st node (0-indexed).

Example 2:

Input: head = [1,2], index = -1

Output: false
Constraints:

1 <= Length of the list <= 1000.
-1000 <= Node.val <= 1000
index is -1 or a valid index in the linked list.

Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next

class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:

A

Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next

class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
current = head
visited = []
while current:
if current.next in visited:
return True
else:
visited.append(current)
current = current.next
return False

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

Reorder Linked List:
You are given the head of a singly linked-list.

The positions of a linked list of length = 7 for example, can intially be represented as:

[0, 1, 2, 3, 4, 5, 6]

Reorder the nodes of the linked list to be in the following order:

[0, 6, 1, 5, 2, 4, 3]

Notice that in the general case for a list of length = n the nodes are reordered to be in the following order:

[0, n-1, 1, n-2, 2, n-3, …]

You may not modify the values in the list’s nodes, but instead you must reorder the nodes themselves.

Example 1:

Input: head = [2,4,6,8]

Output: [2,8,4,6]
Example 2:

Input: head = [2,4,6,8,10]

Output: [2,10,4,8,6]
Constraints:

1 <= Length of the list <= 1000.
1 <= Node.val <= 1000

Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next

class Solution:
def reorderList(self, head: Optional[ListNode]) -> None:

A

Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next

class Solution:
def reorderList(self, head: Optional[ListNode]) -> None:
if not head:
return

    nodes = []
    cur = head
    while cur:
        nodes.append(cur)
        cur = cur.next
    
    i, j = 0, len(nodes) - 1
    while i < j:
        nodes[i].next = nodes[j]
        i += 1
        if i >= j:
            break
        nodes[j].next = nodes[i]
        j -= 1
    
    nodes[i].next = None
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

Remove Node From End of Linked List:
You are given the beginning of a linked list head, and an integer n.

Remove the nth node from the end of the list and return the beginning of the list.

Example 1:

Input: head = [1,2,3,4], n = 2

Output: [1,2,4]
Example 2:

Input: head = [5], n = 1

Output: []
Example 3:

Input: head = [1,2], n = 2

Output: [2]
Constraints:

The number of nodes in the list is sz.
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz

Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next

class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:

A

Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next

class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummy_node = ListNode(0, head) # insert dummy at beginning pointing to head
left = dummy_node
right = head
#right = head + n
while n > 0 and right:
right = right.next
n -= 1 #keep shifting right

    while right: #end
        left = left.next
        right = right. next

    #delete
    left.next = left.next.next

    return dummy_node.next #dont include the dummy node but do next (back to OG head)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

Invert Binary Tree:
You are given the root of a binary tree root. Invert the binary tree and return its root.

Example 1:

Input: root = [1,2,3,4,5,6,7]

Output: [1,3,2,7,6,5,4]
Example 2:

Input: root = [3,2,1]

Output: [3,1,2]
Example 3:

Input: root = []

Output: []
Constraints:

0 <= The number of nodes in the tree <= 100.
-100 <= Node.val <= 100

Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right

class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:

A

dfs, use recursion

Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right

class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root: #if root null
return None

    #swap children otherwise
    temp = root.left
    root.left = root.right
    root.right = temp

    self.invertTree(root.left)
    self.invertTree(root.right)
    return root
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

Maximum Depth of Binary Tree:
Given the root of a binary tree, return its depth.

The depth of a binary tree is defined as the number of nodes along the longest path from the root node down to the farthest leaf node.

Example 1:

Input: root = [1,2,3,null,null,4]

Output: 3
Example 2:

Input: root = []

Output: 0
Constraints:

0 <= The number of nodes in the tree <= 100.
-100 <= Node.val <= 100

Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right

class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:

A

Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right

class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0

    return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
Same Binary Tree: Given the roots of two binary trees p and q, return true if the trees are equivalent, otherwise return false. Two binary trees are considered equivalent if they share the exact same structure and the nodes have the same values. Example 1: Input: p = [1,2,3], q = [1,2,3] Output: true Example 2: Input: p = [4,7], q = [4,null,7] Output: false Example 3: Input: p = [1,2,3], q = [1,3,2] Output: false Constraints: 0 <= The number of nodes in both trees <= 100. -100 <= Node.val <= 100 Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool:
Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool: if not p and not q: return True if p and q and p.val == q.val: return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right) else: return False
26
Subtree of Another Tree: Given the roots of two binary trees root and subRoot, return true if there is a subtree of root with the same structure and node values of subRoot and false otherwise. A subtree of a binary tree tree is a tree that consists of a node in tree and all of this node's descendants. The tree tree could also be considered as a subtree of itself. Example 1: Input: root = [1,2,3,4,5], subRoot = [2,4,5] Output: true Example 2: Input: root = [1,2,3,4,5,null,null,6], subRoot = [2,4,5] Output: false Constraints: 0 <= The number of nodes in both trees <= 100. -100 <= root.val, subRoot.val <= 100 Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def isSubtree(self, root: Optional[TreeNode], subRoot: Optional[TreeNode]) -> bool:
Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def isSubtree(self, root: Optional[TreeNode], subRoot: Optional[TreeNode]) -> bool: if not subRoot: return True if not root: return False if self.sameTree(root, subRoot): return True return (self.isSubtree(root.left, subRoot) or self.isSubtree(root.right, subRoot)) def sameTree(self, root: Optional[TreeNode], subRoot: Optional[TreeNode]) -> bool: if not root and not subRoot: return True if root and subRoot and root.val == subRoot.val: return (self.sameTree(root.left, subRoot.left) and self.sameTree(root.right, subRoot.right)) return False
27
Lowest Common Ancestor in Binary Search Tree: Given a binary search tree (BST) where all node values are unique, and two nodes from the tree p and q, return the lowest common ancestor (LCA) of the two nodes. The lowest common ancestor between two nodes p and q is the lowest node in a tree T such that both p and q as descendants. The ancestor is allowed to be a descendant of itself. Example 1: Input: root = [5,3,8,1,4,7,9,null,2], p = 3, q = 8 Output: 5 Example 2: Input: root = [5,3,8,1,4,7,9,null,2], p = 3, q = 4 Output: 3 Explanation: The LCA of nodes 3 and 4 is 3, since a node can be a descendant of itself. Constraints: 2 <= The number of nodes in the tree <= 100. -100 <= Node.val <= 100 p != q p and q will both exist in the BST. Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode: if not root or not p or not q: return None if (max(p.val, q.val) < root.val): return self.lowestCommonAncestor(root.left, p, q) elif (min(p.val, q.val) > root.val): return self.lowestCommonAncestor(root.right, p, q) else: return root
28
Binary Tree Level Order Traversal: Given a binary tree root, return the level order traversal of it as a nested list, where each sublist contains the values of nodes at a particular level in the tree, from left to right. Example 1: Input: root = [1,2,3,4,5,6,7] Output: [[1],[2,3],[4,5,6,7]] Example 2: Input: root = [1] Output: [[1]] Example 3: Input: root = [] Output: [] Constraints: 0 <= The number of nodes in both trees <= 1000. -1000 <= Node.val <= 1000 Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]: res = [] q = collections.deque() q.append(root) while q: qLen = len(q) level = [] for i in range(qLen): node = q.popleft() if node: level.append(node.val) q.append(node.left) q.append(node.right) if level: res.append(level) return res
29
Valid Binary Search Tree: Given the root of a binary tree, return true if it is a valid binary search tree, otherwise return false. A valid binary search tree satisfies the following constraints: The left subtree of every node contains only nodes with keys less than the node's key. The right subtree of every node contains only nodes with keys greater than the node's key. Both the left and right subtrees are also binary search trees. Example 1: Input: root = [2,1,3] Output: true Example 2: Input: root = [1,2,3] Output: false Explanation: The root node's value is 1 but its left child's value is 2 which is greater than 1. Constraints: 1 <= The number of nodes in the tree <= 1000. -1000 <= Node.val <= 1000 Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def isValidBST(self, root: Optional[TreeNode]) -> bool:
Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def isValidBST(self, root: Optional[TreeNode]) -> bool: if not root: return True q = deque([(root, float("-inf"), float("inf"))]) while q: node, left, right = q.popleft() if not (left < node.val < right): return False if node.left: q.append((node.left, left, node.val)) if node.right: q.append((node.right, node.val, right)) return True
30
Kth Smallest Integer in BST: Given the root of a binary search tree, and an integer k, return the kth smallest value (1-indexed) in the tree. A binary search tree satisfies the following constraints: The left subtree of every node contains only nodes with keys less than the node's key. The right subtree of every node contains only nodes with keys greater than the node's key. Both the left and right subtrees are also binary search trees. Example 1: Input: root = [2,1,3], k = 1 Output: 1 Example 2: Input: root = [4,3,5,2,null], k = 4 Output: 5 Constraints: 1 <= k <= The number of nodes in the tree <= 1000. 0 <= Node.val <= 1000 Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: #instead of recursive, use iterative dfs def kthSmallest(self, root: Optional[TreeNode], k: int) -> int: stack = [] curr = root while stack or curr: while curr: stack.append(curr) curr = curr.left curr = stack.pop() k -= 1 if k == 0: return curr.val curr = curr.right
31
Construct Binary Tree from Preorder and Inorder Traversal: You are given two integer arrays preorder and inorder. preorder is the preorder traversal of a binary tree inorder is the inorder traversal of the same tree Both arrays are of the same size and consist of unique values. Rebuild the binary tree from the preorder and inorder traversals and return its root. Example 1: Input: preorder = [1,2,3,4], inorder = [2,1,3,4] Output: [1,2,3,null,null,null,4] Example 2: Input: preorder = [1], inorder = [1] Output: [1] Constraints: 1 <= inorder.length <= 1000. inorder.length == preorder.length -1000 <= preorder[i], inorder[i] <= 1000 Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: if not preorder or not inorder: return None root = TreeNode(preorder[0]) mid = inorder.index(preorder[0]) root.left = self.buildTree(preorder[1 : mid + 1], inorder[:mid]) root.right = self.buildTree(preorder[mid + 1 :], inorder[mid + 1 :]) return root
32
Combination Sum: You are given an array of distinct integers nums and a target integer target. Your task is to return a list of all unique combinations of nums where the chosen numbers sum to target. The same number may be chosen from nums an unlimited number of times. Two combinations are the same if the frequency of each of the chosen numbers is the same, otherwise they are different. You may return the combinations in any order and the order of the numbers in each combination can be in any order. Example 1: Input: nums = [2,5,6,9] target = 9 Output: [[2,2,5],[9]] Explanation: 2 + 2 + 5 = 9. We use 2 twice, and 5 once. 9 = 9. We use 9 once. Example 2: Input: nums = [3,4,5] target = 16 Output: [[3,3,3,3,4],[3,3,5,5],[4,4,4,4],[3,4,4,5]] Example 3: Input: nums = [3] target = 5 Output: [] Constraints: All elements of nums are distinct. 1 <= nums.length <= 20 2 <= nums[i] <= 30 2 <= target <= 30 class Solution: def combinationSum(self, nums: List[int], target: int) -> List[List[int]]:
class Solution: def combinationSum(self, nums: List[int], target: int) -> List[List[int]]: res = [] nums.sort() def dfs(i, cur, total): if total == target: res.append(cur.copy()) return for j in range(i, len(nums)): if total + nums[j] > target: return cur.append(nums[j]) dfs(j, cur, total + nums[j]) cur.pop() dfs(0, [], 0) return res
33
Word Search: Given a 2-D grid of characters board and a string word, return true if the word is present in the grid, otherwise return false. For the word to be present it must be possible to form it with a path in the board with horizontally or vertically neighboring cells. The same cell may not be used more than once in a word. Example 1: Input: board = [ ["A","B","C","D"], ["S","A","A","T"], ["A","C","A","E"] ], word = "CAT" Output: true Example 2: Input: board = [ ["A","B","C","D"], ["S","A","A","T"], ["A","C","A","E"] ], word = "BAT" Output: false Constraints: 1 <= board.length, board[i].length <= 5 1 <= word.length <= 10 board and word consists of only lowercase and uppercase English letters. class Solution: def exist(self, board: List[List[str]], word: str) -> bool:
class Solution: def exist(self, board: List[List[str]], word: str) -> bool: ROWS, COLS = len(board), len(board[0]) def dfs(r, c, i): if i == len(word): return True if (r < 0 or c < 0 or r >= ROWS or c >= COLS or word[i] != board[r][c] or board[r][c] == "#"): return False board[r][c] = '#' res = (dfs(r + 1, c, i + 1) or dfs(r - 1, c, i + 1) or dfs(r, c + 1, i + 1) or dfs(r, c - 1, i + 1)) board[r][c] = word[i] return res for r in range(ROWS): for c in range(COLS): if dfs(r, c, 0): return True return False
34
class PrefixTree: def __init__(self): def insert(self, word: str) -> None: def search(self, word: str) -> bool: def startsWith(self, prefix: str) -> bool:
class TrieNode: def __init__(self): self.children = {} self.endOfWord = False class PrefixTree: #a-z, 26 char total def __init__(self): self.root = TrieNode() #create nodes for each character in word/string, all should be child #e.g. a->p->p->l->e (mark "e" is end) #e.g. inserting "ape" in "apple" should mean do a->p->p, e (don't make) #separate a->p->e node list as you can reuse nodes by making e direct child # of first "p" #make a big "tree" first like ROOT->a, b, c, ..., z (26 children) def insert(self, word: str) -> None: curr = self.root for c in word: #for every char in word if c not in curr.children: #if this character isn't in our hashmap yet curr.children[c] = TrieNode() curr = curr.children[c] #move to that char if it is already present curr.endOfWord = True #now we have an end of a word, mark True #search the nodes and see if the words match all childrens consecutively #mark beginning and end of word w nodes #e.g. "app" should be False in "apple" as they do not start + end in same char #use hashmap in o(n) def search(self, word: str) -> bool: #similar to insert, but use "opposite" logic curr = self.root for c in word: if c not in curr.children: return False curr = curr.children[c] return curr.endOfWord #this should be True by default, meaning it ended in #char AND THAT it matches with the word #opposite of search, True if there is consecutive nodes that start + end in #same char def startsWith(self, prefix: str) -> bool: curr = self.root for c in prefix: if c not in curr.children: return False curr = curr.children[c] return True #automatically can return without checking if ending matched #with word
35
Design Add and Search Word Data Structure: Design a data structure that supports adding new words and searching for existing words. Implement the WordDictionary class: void addWord(word) Adds word to the data structure. bool search(word) Returns true if there is any string in the data structure that matches word or false otherwise. word may contain dots '.' where dots can be matched with any letter. Example 1: Input: ["WordDictionary", "addWord", "day", "addWord", "bay", "addWord", "may", "search", "say", "search", "day", "search", ".ay", "search", "b.."] Output: [null, null, null, null, false, true, true, true] Explanation: WordDictionary wordDictionary = new WordDictionary(); wordDictionary.addWord("day"); wordDictionary.addWord("bay"); wordDictionary.addWord("may"); wordDictionary.search("say"); // return false wordDictionary.search("day"); // return true wordDictionary.search(".ay"); // return true wordDictionary.search("b.."); // return true Constraints: 1 <= word.length <= 20 word in addWord consists of lowercase English letters. word in search consist of '.' or lowercase English letters. class WordDictionary: def __init__(self): def addWord(self, word: str) -> None: def search(self, word: str) -> bool:
class TrieNode: def __init__(self): self.children = {} self.word = False class WordDictionary: def __init__(self): self.root = TrieNode() def addWord(self, word: str) -> None: cur = self.root for c in word: if c not in cur.children: cur.children[c] = TrieNode() cur = cur.children[c] cur.word = True def search(self, word: str) -> bool: def dfs(j, root): cur = root for i in range(j, len(word)): c = word[i] if c == ".": for child in cur.children.values(): if dfs(i + 1, child): return True return False else: if c not in cur.children: return False cur = cur.children[c] return cur.word return dfs(0, self.root)
36
Number of Islands: Given a 2D grid grid where '1' represents land and '0' represents water, count and return the number of islands. An island is formed by connecting adjacent lands horizontally or vertically and is surrounded by water. You may assume water is surrounding the grid (i.e., all the edges are water). Example 1: Input: grid = [ ["0","1","1","1","0"], ["0","1","0","1","0"], ["1","1","0","0","0"], ["0","0","0","0","0"] ] Output: 1 Example 2: Input: grid = [ ["1","1","0","0","1"], ["1","1","0","0","1"], ["0","0","1","0","0"], ["0","0","0","1","1"] ] Output: 4 Constraints: 1 <= grid.length, grid[i].length <= 100 grid[i][j] is '0' or '1'. class Solution: def numIslands(self, grid: List[List[str]]) -> int:
class Solution: def numIslands(self, grid: List[List[str]]) -> int: if not grid: return 0 rows, cols = len(grid), len(grid[0]) visited = set() islands = 0 #count number of islands def bfs(r,c): #iterative, NOT RECURSIVE queue = collections.deque() #normally used for bfs visited.add((r,c)) queue.append((r,c)) while queue: #while queue not empty/not at end row, col = queue.popleft() #if you change to just pop, it'll be dfs directions = [[1, 0], [-1, 0], [0, 1], [0, -1]] #right,left,up,down for dr, dc in directions: #for row, col in directions r, c = row + dr, col + dc if (r in range(rows) #check if in range of rows and c in range(cols) #check if in range of cols and grid[r][c] == "1" #check if this is a land position and (r, c) not in visited): #check if not visited already queue.append((r,c)) visited.add((r,c)) for r in range(rows): #iterate rows for c in range(cols): #iterate cols if grid[r][c] == "1" and (r,c) not in visited: #not visited yet, #avoids repetition bfs(r, c) islands += 1 return islands
37
Clone Graph: Given a node in a connected undirected graph, return a deep copy of the graph. Each node in the graph contains an integer value and a list of its neighbors. class Node { public int val; public List neighbors; } The graph is shown in the test cases as an adjacency list. An adjacency list is a mapping of nodes to lists, used to represent a finite graph. Each list describes the set of neighbors of a node in the graph. For simplicity, nodes values are numbered from 1 to n, where n is the total number of nodes in the graph. The index of each node within the adjacency list is the same as the node's value (1-indexed). The input node will always be the first node in the graph and have 1 as the value. Example 1: Input: adjList = [[2],[1,3],[2]] Output: [[2],[1,3],[2]] Explanation: There are 3 nodes in the graph. Node 1: val = 1 and neighbors = [2]. Node 2: val = 2 and neighbors = [1, 3]. Node 3: val = 3 and neighbors = [2]. Example 2: Input: adjList = [[]] Output: [[]] Explanation: The graph has one node with no neighbors. Example 3: Input: adjList = [] Output: [] Explanation: The graph is empty. Constraints: 0 <= The number of nodes in the graph <= 100. 1 <= Node.val <= 100 There are no duplicate edges and no self-loops in the graph. """ # Definition for a Node. class Node: def __init__(self, val = 0, neighbors = None): self.val = val self.neighbors = neighbors if neighbors is not None else [] """ class Solution: def cloneGraph(self, node: Optional['Node']) -> Optional['Node']:
""" # Definition for a Node. class Node: def __init__(self, val = 0, neighbors = None): self.val = val self.neighbors = neighbors if neighbors is not None else [] """ #make a hashmap w key "old" and val "new" to make copy and keep track of nodes #keep track of neighbors to connect undirected nodes #O(n) = E+V (edges plus vertices) class Solution: def cloneGraph(self, node: Optional['Node']) -> Optional['Node']: oldToNew = {} def dfs(node): if node in oldToNew: #if node exists already/already mapped return oldToNew[node] copy = Node(node.val) #copy OG node value oldToNew[node] = copy for neighbor in node.neighbors: #iterate through neighbors copy.neighbors.append(dfs(neighbor)) return copy return dfs(node) if node else None
38
Pacific Atlantic Water Flow Solved You are given a rectangular island heights where heights[r][c] represents the height above sea level of the cell at coordinate (r, c). The islands borders the Pacific Ocean from the top and left sides, and borders the Atlantic Ocean from the bottom and right sides. Water can flow in four directions (up, down, left, or right) from a cell to a neighboring cell with height equal or lower. Water can also flow into the ocean from cells adjacent to the ocean. Find all cells where water can flow from that cell to both the Pacific and Atlantic oceans. Return it as a 2D list where each element is a list [r, c] representing the row and column of the cell. You may return the answer in any order. Example 1: Input: heights = [ [4,2,7,3,4], [7,4,6,4,7], [6,3,5,3,6] ] Output: [[0,2],[0,4],[1,0],[1,1],[1,2],[1,3],[1,4],[2,0]] Example 2: Input: heights = [[1],[1]] Output: [[0,0],[0,1]] Constraints: 1 <= heights.length, heights[r].length <= 100 0 <= heights[r][c] <= 1000 class Solution: def pacificAtlantic(self, heights: List[List[int]]) -> List[List[int]]:
class Solution: #pacific is above top and to the left of grid #atlantic is below and right of grid #we want to include a cell if it can reach pacific and atlantic #but ONLY if water flows (this means that adj cells all have to be decreasing/ #increasing from prev or equal) def pacificAtlantic(self, heights: List[List[int]]) -> List[List[int]]: ROWS, COLS = len(heights), len(heights[0]) pacific, atlantic = set(), set() #1st row is pacific def dfs(r, c, visit, previousHeight): if ((r,c) in visit or r<0 or c<0 or r==ROWS or c==COLS or heights[r][c] < previousHeight): #if alr visited, or out of bounds, or too small return visit.add((r,c)) #go to all four neighbors of current position dfs(r+1, c, visit, heights[r][c]) dfs(r-1, c, visit, heights[r][c]) dfs(r, c+1, visit, heights[r][c]) dfs(r, c-1, visit, heights[r][c]) for c in range(COLS): #first and last row dfs(0, c, pacific, heights[0][c]) dfs(ROWS-1, c, atlantic, heights[ROWS-1][c]) for r in range(ROWS): #first and last col dfs(r, 0, pacific, heights[r][0]) dfs(r, COLS-1, atlantic, heights[r][COLS-1]) res = [] for r in range(ROWS): for c in range(COLS): if (r,c) in pacific and (r,c) in atlantic: res.append([r,c]) return res
39
Course Schedule: You are given an array prerequisites where prerequisites[i] = [a, b] indicates that you must take course b first if you want to take course a. The pair [0, 1], indicates that must take course 1 before taking course 0. There are a total of numCourses courses you are required to take, labeled from 0 to numCourses - 1. Return true if it is possible to finish all courses, otherwise return false. Example 1: Input: numCourses = 2, prerequisites = [[0,1]] Output: true Explanation: First take course 1 (no prerequisites) and then take course 0. Example 2: Input: numCourses = 2, prerequisites = [[0,1],[1,0]] Output: false Explanation: In order to take course 1 you must take course 0, and to take course 0 you must take course 1. So it is impossible. Constraints: 1 <= numCourses <= 1000 0 <= prerequisites.length <= 1000 All prerequisite pairs are unique. class Solution: def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
class Solution: #just do dfs to see if the "end" node doesn't point to anything (cycle detection) #use adj list -> for each course, list all prereqs #basically, look thru adj list and see if the "end" has empty prereq list #then, that means we can complete it #also, use set to store current visited node (for cycles) def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool: preMap = {i: [] for i in range(numCourses)} for courses, prereq in prerequisites: preMap[courses].append(prereq) #add data to map #visitSet stores all courses along the current DFS path visitSet = set() def dfs(course): if course in visitSet: #cycle detected, course cannot be completed return False if preMap[course] == []: #can be taken return True visitSet.add(course) for prereq in preMap[course]: if not dfs(prereq): #if return false return False visitSet.remove(course) preMap[course] = [] #update adj list return True for course in range(numCourses): #now call dfs if not dfs(course): return False return True
40
Graph Valid Tree: Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), write a function to check whether these edges make up a valid tree. Example 1: Input: n = 5 edges = [[0, 1], [0, 2], [0, 3], [1, 4]] Output: true Example 2: Input: n = 5 edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]] Output: false Note: You can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges. Constraints: 1 <= n <= 100 0 <= edges.length <= n * (n - 1) / 2 class Solution: def validTree(self, n: int, edges: List[List[int]]) -> bool:
class Solution: #trees have a root and children, but cannot have cycles/loops, every node needs #to be connected -> use adj list #use hashset "visit" and recursively go thru nodes, compare and return true if #"visit" set equals number of nodes, false if not (cycle detected) #O(E + V) def validTree(self, n: int, edges: List[List[int]]) -> bool: if not n: #empty graph = technically valid tree return True adj = {i:[] for i in range(n)} for n1, n2 in edges: adj[n1].append(n2) adj[n2].append(n1) visit = set() def dfs(i, prev): #i = node if i in visit: return False visit.add(i) for j in adj[i]: if j == prev: continue if not dfs(j, i): return False return True return dfs(0, -1) and n == len(visit) #every node is connected and dfs works
41
Number of Connected Components in an Undirected Graph: There is an undirected graph with n nodes. There is also an edges array, where edges[i] = [a, b] means that there is an edge between node a and node b in the graph. The nodes are numbered from 0 to n - 1. Return the total number of connected components in that graph. Example 1: Input: n=3 edges=[[0,1], [0,2]] Output: 1 Example 2: Input: n=6 edges=[[0,1], [1,2], [2,3], [4,5]] Output: 2 Constraints: 1 <= n <= 100 0 <= edges.length <= n * (n - 1) / 2 class Solution: def countComponents(self, n: int, edges: List[List[int]]) -> int:
class Solution: #basically how many "pieces" of connected nodes are there #use union find -> have a "parent" array and 1st make each node a parent of itself #then keep updated parents when you see links, and constantly merge and make #unions of pieces, also use a "rank" array for each component to store each #size of components/pieces (initially all should be 1 ) def countComponents(self, n: int, edges: List[List[int]]) -> int: parent = [i for i in range(n)] rank = [1] * n def find(n1): res = n1 while res != parent[res]: #we stop searching when node is its own parent, #then we're at itself and at the very root parent[res] = parent[parent[res]] #set to grandparent res = parent[res] #go up, to parent return res def union(n1, n2): p1, p2 = find(n1), find(n2) #parents if p1 == p2: return 0 #no union find if rank[p2] > rank[p2]: parent[p1] = p2 rank[p2] += rank[p1] else: parent[p2] = p1 rank[p1] += rank[p2] return 1 #successful union res = n for n1, n2 in edges: res -= union(n1, n2) return res #result will give us the component count
42
Climbing Stairs: You are given an integer n representing the number of steps to reach the top of a staircase. You can climb with either 1 or 2 steps at a time. Return the number of distinct ways to climb to the top of the staircase. Example 1: Input: n = 2 Output: 2 Explanation: 1 + 1 = 2 2 = 2 Example 2: Input: n = 3 Output: 3 Explanation: 1 + 1 + 1 = 3 1 + 2 = 3 2 + 1 = 3 Constraints: 1 <= n <= 30 class Solution: def climbStairs(self, n: int) -> int:
class Solution: #dynamic programming -> store an array "dp" to store how mnay ways we can take #steps to result/last step, go right to left and store in each index (last two #indices will always be one because only one step to goal, and goal is at itself), #basically then keep adding every 2 right values to get current index #kinda like fibonacci seq def climbStairs(self, n: int) -> int: one, two = 1, 1 for i in range(n-1): temp = one one = one + two two = temp return one
43
House Robber: You are given an integer array nums where nums[i] represents the amount of money the ith house has. The houses are arranged in a straight line, i.e. the ith house is the neighbor of the (i-1)th and (i+1)th house. You are planning to rob money from the houses, but you cannot rob two adjacent houses because the security system will automatically alert the police if two adjacent houses were both broken into. Return the maximum amount of money you can rob without alerting the police. Example 1: Input: nums = [1,1,3,3] Output: 4 Explanation: nums[0] + nums[2] = 1 + 3 = 4. Example 2: Input: nums = [2,9,8,3,6] Output: 16 Explanation: nums[0] + nums[2] + nums[4] = 2 + 8 + 6 = 16. Constraints: 1 <= nums.length <= 100 0 <= nums[i] <= 100 class Solution: def rob(self, nums: List[int]) -> int:
class Solution: #basically, split into subproblems -> e.g. rob = max(arr[0] + rob[2:n], #rob[1:n]) def rob(self, nums: List[int]) -> int: rob1, rob2 = 0, 0 for n in nums: #e.g. [rob1, rob2, n, n+1, ...] temp = max(n + rob1, rob2) #n + rob1 = curr, next rob1 = rob2 rob2 = temp return rob2 #rob2 will equal last value, and equal max
44
House Robber II: You are given an integer array nums where nums[i] represents the amount of money the ith house has. The houses are arranged in a circle, i.e. the first house and the last house are neighbors. You are planning to rob money from the houses, but you cannot rob two adjacent houses because the security system will automatically alert the police if two adjacent houses were both broken into. Return the maximum amount of money you can rob without alerting the police. Example 1: Input: nums = [3,4,3] Output: 4 Explanation: You cannot rob nums[0] + nums[2] = 6 because nums[0] and nums[2] are adjacent houses. The maximum you can rob is nums[1] = 4. Example 2: Input: nums = [2,9,8,3,6] Output: 15 Explanation: You cannot rob nums[0] + nums[2] + nums[4] = 16 because nums[0] and nums[4] are adjacent houses. The maximum you can rob is nums[1] + nums[4] = 15. Constraints: 1 <= nums.length <= 100 0 <= nums[i] <= 100 class Solution: def rob(self, nums: List[int]) -> int:
class Solution: #kinda reuse robber 1 solution #in this you cannot rob both "head" and "tail"/1st and last of arr #run the helper function of different parts of subarrays -> O(n) def rob(self, nums: List[int]) -> int: return max(nums[0], self.helper(nums[1:]), self.helper(nums[:-1])) #edge cases -> if arr has one element, skip 1st #house, skip last index def helper(self, nums): #sol from robber1 rob1, rob2 = 0, 0 for n in nums: newRob = max(rob1 + n, rob2) #skip rob2, we cannot add rob1 and rob2 #together bc they're adjacent rob1 = rob2 rob2 = newRob #this will contain max amount from entire arr return rob2
45
Longest Palindromic Substring: Given a string s, return the longest substring of s that is a palindrome. A palindrome is a string that reads the same forward and backward. If there are multiple palindromic substrings that have the same length, return any one of them. Example 1: Input: s = "ababd" Output: "bab" Explanation: Both "aba" and "bab" are valid answers. Example 2: Input: s = "abbc" Output: "bb" Constraints: 1 <= s.length <= 1000 s contains only digits and English letters. class Solution: def longestPalindrome(self, s: str) -> str:
class Solution: #go thru each char using each as center letter, and use left and right ptrs #and see if they're equal, keep expanding outwards until you can find longest #palindrome, this works for odd numbered words but need edge case for even def longestPalindrome(self, s: str) -> str: resIdx = 0 resLen = 0 for i in range(len(s)): # odd length l, r = i, i while l >= 0 and r < len(s) and s[l] == s[r]: #check if palindrome if (r - l + 1) > resLen: resIdx = l resLen = r - l + 1 l -= 1 r += 1 # even length l, r = i, i + 1 while l >= 0 and r < len(s) and s[l] == s[r]: if (r - l + 1) > resLen: resIdx = l resLen = r - l + 1 l -= 1 r += 1 return s[resIdx : resIdx + resLen]
46
Palindromic Substrings: Given a string s, return the number of substrings within s that are palindromes. A palindrome is a string that reads the same forward and backward. Example 1: Input: s = "abc" Output: 3 Explanation: "a", "b", "c". Example 2: Input: s = "aaa" Output: 6 Explanation: "a", "a", "a", "aa", "aa", "aaa". Note that different substrings are counted as different palindromes even if the string contents are the same. Constraints: 1 <= s.length <= 1000 s consists of lowercase English letters. class Solution: def countSubstrings(self, s: str) -> int:
class Solution: #in "abc", "a" "b" and "c" are palindromes since they're itself, but "abc" #altogether would not be #you loop thru each char, then go thru all substrings where curr char is middle #initialize left and right ptrs to curr char first (e.g. "a" is palindrome) then #keep expanding out and find all possibilities #then, to get all even-numbered palindromes -> start w left pointer at beginning #and right at beginning+1, keep expanding again similarly, but move over every #two indicies (e.g. in "aaab" start with first "aa" then next "aa" then "ab") def countSubstrings(self, s: str) -> int: res = 0 for i in range(len(s)): #odd l, r = i, i while l >= 0 and r < len(s) and s[l] == s[r]: res += 1 l -= 1 r += 1 #even l, r = i, i+1 while l >= 0 and r < len(s) and s[l] == s[r]: res += 1 l -= 1 r += 1 return res
47
Decode Ways: A string consisting of uppercase english characters can be encoded to a number using the following mapping: 'A' -> "1" 'B' -> "2" ... 'Z' -> "26" To decode a message, digits must be grouped and then mapped back into letters using the reverse of the mapping above. There may be multiple ways to decode a message. For example, "1012" can be mapped into: "JAB" with the grouping (10 1 2) "JL" with the grouping (10 12) The grouping (1 01 2) is invalid because 01 cannot be mapped into a letter since it contains a leading zero. Given a string s containing only digits, return the number of ways to decode it. You can assume that the answer fits in a 32-bit integer. Example 1: Input: s = "12" Output: 2 Explanation: "12" could be decoded as "AB" (1 2) or "L" (12). Example 2: Input: s = "01" Output: 0 Explanation: "01" cannot be decoded because "01" cannot be mapped into a letter. Constraints: 1 <= s.length <= 100 s consists of digits class Solution: def numDecodings(self, s: str) -> int:
class Solution: #cannot start with any string starting with "0..." #subproblems -> starting from some index to end, how many ways can we decode? def numDecodings(self, s: str) -> int: dp = { len(s) : 1} #base case -> return 1 if empty string def dfs(i): if i in dp: #already been cashed, or end of str return dp[i] if s[i] == "0": #invalid, can't decode any str starting with "0" return 0 res = dfs(i + 1) #subproblem if (i+1 < len(s) and (s[i] == "1" or s[i] == "2" and s[i+1] in "0123456")): #if we have 2nd char after curr/if there's double digits #we can have 10-19, but only 20-26 res += dfs(i+2) dp[i] = res #cache this return res return dfs(0)
48
Coin Change: You are given an integer array coins representing coins of different denominations (e.g. 1 dollar, 5 dollars, etc) and an integer amount representing a target amount of money. Return the fewest number of coins that you need to make up the exact target amount. If it is impossible to make up the amount, return -1. You may assume that you have an unlimited number of each coin. Example 1: Input: coins = [1,5,10], amount = 12 Output: 3 Explanation: 12 = 10 + 1 + 1. Note that we do not have to use every kind coin available. Example 2: Input: coins = [2], amount = 3 Output: -1 Explanation: The amount of 3 cannot be made up with coins of 2. Example 3: Input: coins = [1], amount = 0 Output: 0 Explanation: Choosing 0 coins is a valid way to make up 0. Constraints: 1 <= coins.length <= 10 1 <= coins[i] <= 2^31 - 1 0 <= amount <= 10000 class Solution: def coinChange(self, coins: List[int], amount: int) -> int:
class Solution: #you can use the coins arr unlimited time (e.g. in [1,2] you can do 2*6 if the #amount if 12) #use cache "dp" to avoid doing calculations more than once def coinChange(self, coins: List[int], amount: int) -> int: dp = [amount+1] * (amount+1) #we want 0....amount dp[0]=0 for a in range(1, amount+1): #bottom-up for c in coins: if a - c >= 0: dp[a]= min(dp[a], 1+dp[a-c]) #e.g. if coin is 4 and amount is 7, then dp[7] = 1 + dp[3], #because 7-4=3 so its a possible solution return dp[amount] if dp[amount] != amount + 1 else -1 #if value isn't #default if amount == 0: return 0
49
Maximum Product Subarray: Given an integer array nums, find a subarray that has the largest product within the array and return it. A subarray is a contiguous non-empty sequence of elements within an array. You can assume the output will fit into a 32-bit integer. Example 1: Input: nums = [1,2,-3,4] Output: 4 Example 2: Input: nums = [-2,-1] Output: 2 Constraints: 1 <= nums.length <= 1000 -10 <= nums[i] <= 10 class Solution: def maxProduct(self, nums: List[int]) -> int:
class Solution: #store max and min subarrays and dynamically compute these and store, so that #in cases where there are negative numbers, you can potentially get an even #greater max (e.g. in [-1,-2,-3]) #edge case: if there's a 0, replace min and max with 1 as a "neutral"/ #placeholder value (bc max needs to be contiguous) def maxProduct(self, nums: List[int]) -> int: res = max(nums) #can't be 0, bc if we have arr that had [-1] then -1 would #be -1 curMin, curMax = 1, 1 #neutral value for n in nums: tmp = curMax*n curMax = max(n * curMax, n * curMin, n) curMin = min(tmp, n * curMin, n) res = max(res, curMax, curMin) return res
50
Word Break: Given a string s and a dictionary of strings wordDict, return true if s can be segmented into a space-separated sequence of dictionary words. You are allowed to reuse words in the dictionary an unlimited number of times. You may assume all dictionary words are unique. Example 1: Input: s = "neetcode", wordDict = ["neet","code"] Output: true Explanation: Return true because "neetcode" can be split into "neet" and "code". Example 2: Input: s = "applepenapple", wordDict = ["apple","pen","ape"] Output: true Explanation: Return true because "applepenapple" can be split into "apple", "pen" and "apple". Notice that we can reuse words and also not use all the words. Example 3: Input: s = "catsincars", wordDict = ["cats","cat","sin","in","car"] Output: false Constraints: 1 <= s.length <= 200 1 <= wordDict.length <= 100 1 <= wordDict[i].length <= 20 s and wordDict[i] consist of only lowercase English letters. class Solution: def wordBreak(self, s: str, wordDict: List[str]) -> bool:
class Solution: #basically use dp bottom up and do dp[index] = dp[index + len(word matched)] #and kinda split up all matched words def wordBreak(self, s: str, wordDict: List[str]) -> bool: dp = [False] * (len(s) + 1) dp[len(s)] = True #base case for i in range(len(s)-1, -1, -1): #reverse loop from right to left for w in wordDict: if (i + len(w)) <= len(s) and s[i:i + len(w)] == w: #enough/equal characters from s that we can compare dp[i] = dp[i+len(w)] if dp[i]: break #move onto new index return dp[0]
51
Longest Increasing Subsequence: Given an integer array nums, return the length of the longest strictly increasing subsequence. A subsequence is a sequence that can be derived from the given sequence by deleting some or no elements without changing the relative order of the remaining characters. For example, "cat" is a subsequence of "crabt". Example 1: Input: nums = [9,1,4,2,3,3,7] Output: 4 Explanation: The longest increasing subsequence is [1,2,3,7], which has a length of 4. Example 2: Input: nums = [0,3,1,3,2,3] Output: 4 Constraints: 1 <= nums.length <= 1000 -1000 <= nums[i] <= 1000 class Solution: def lengthOfLIS(self, nums: List[int]) -> int:
class Solution: #use bottom up dp, starting from end make count initally 1 #constantly make and compare subsequences and find the max, only if less than #e.g. in [1,2,4,3] find max from [2,4] as 2<4, cannot do the same for [4,3] def lengthOfLIS(self, nums: List[int]) -> int: LIS = [1] * len(nums) #cache for i in range(len(nums)-1, -1, -1): for j in range(i+1, len(nums)): if nums[i] < nums[j]: #is this increasing/is left < right? LIS[i] = max(LIS[i], 1 + LIS[j]) return max(LIS)
52
Unique Paths: There is an m x n grid where you are allowed to move either down or to the right at any point in time. Given the two integers m and n, return the number of possible unique paths that can be taken from the top-left corner of the grid (grid[0][0]) to the bottom-right corner (grid[m - 1][n - 1]). You may assume the output will fit in a 32-bit integer. Example 1: Input: m = 3, n = 6 Output: 21 Example 2: Input: m = 3, n = 3 Output: 6 Constraints: 1 <= m, n <= 100 class Solution: def uniquePaths(self, m: int, n: int) -> int:
class Solution: #0(m*n) def uniquePaths(self, m: int, n: int) -> int: row = [1] * n for i in range(m-1): newRow = [1] * n for j in range(n-2, -1, -1): #avoid checking out of bounds, from R to L newRow[j] = newRow[j+1] + row[j] row = newRow return row[0]
53
Longest Common Subsequence: Given two strings text1 and text2, return the length of the longest common subsequence between the two strings if one exists, otherwise return 0. A subsequence is a sequence that can be derived from the given sequence by deleting some or no elements without changing the relative order of the remaining characters. For example, "cat" is a subsequence of "crabt". A common subsequence of two strings is a subsequence that exists in both strings. Example 1: Input: text1 = "cat", text2 = "crabt" Output: 3 Explanation: The longest common subsequence is "cat" which has a length of 3. Example 2: Input: text1 = "abcd", text2 = "abcd" Output: 4 Example 3: Input: text1 = "abcd", text2 = "efgh" Output: 0 Constraints: 1 <= text1.length, text2.length <= 1000 text1 and text2 consist of only lowercase English characters. 123 class Solution: def longestCommonSubsequence(self, text1: str, text2: str) -> int: class Solution: def longestCommonSubsequence(self, text1: str, text2: str) -> int:
class Solution: #bottom up dynamic solution using 2d grid def longestCommonSubsequence(self, text1: str, text2: str) -> int: dp = [[0 for j in range(len(text2)+1)] for i in range(len(text1)+1)] for i in range(len(text1)-1, -1, -1): for j in range(len(text2)-1, -1, -1): if text1[i] == text2[j]: dp[i][j] = 1 + dp[i+1][j+1] #add one to the diagonal if they #match else: dp[i][j] = max(dp[i][j+1], dp[i+1][j]) #max of right and bottom return dp[0][0] #will always be in top left
54
Maximum Subarray: Given an array of integers nums, find the subarray with the largest sum and return the sum. A subarray is a contiguous non-empty sequence of elements within an array. Example 1: Input: nums = [2,-3,4,-2,2,1,-1,4] Output: 8 Explanation: The subarray [4,-2,2,1,-1,4] has the largest sum 8. Example 2: Input: nums = [-1] Output: -1 Constraints: 1 <= nums.length <= 1000 -1000 <= nums[i] <= 1000 class Solution: def maxSubArray(self, nums: List[int]) -> int:
class Solution: #kinda like a sliding window problem -> O(n) def maxSubArray(self, nums: List[int]) -> int: dp = [*nums] for i in range(1, len(nums)): dp[i] = max(nums[i], nums[i] + dp[i - 1]) return max(dp)
55
Jump Game: You are given an integer array nums where each element nums[i] indicates your maximum jump length at that position. Return true if you can reach the last index starting from index 0, or false otherwise. Example 1: Input: nums = [1,2,0,1,0] Output: true Explanation: First jump from index 0 to 1, then from index 1 to 3, and lastly from index 3 to 4. Example 2: Input: nums = [1,2,1,0,1] Output: false Constraints: 1 <= nums.length <= 1000 0 <= nums[i] <= 1000 class Solution: def canJump(self, nums: List[int]) -> bool:
class Solution: #greedy -> O(n) #change the goal from reverse order, so if we see [...1,4] we know for sure we #can get to last value "4" because prev index had "1" step that we can exactly #take to end, so then we'd update goal to "1" and keep going def canJump(self, nums: List[int]) -> bool: goal = len(nums)-1 #end for i in range(len(nums)-1, -1, -1): if i + nums[i] >= goal: #is jump length >= goal? then shift goal lefter goal = i return True if goal == 0 else False #0 means jump was able to be completed
56
Insert Interval: You are given an array of non-overlapping intervals intervals where intervals[i] = [start_i, end_i] represents the start and the end time of the ith interval. intervals is initially sorted in ascending order by start_i. You are given another interval newInterval = [start, end]. Insert newInterval into intervals such that intervals is still sorted in ascending order by start_i and also intervals still does not have any overlapping intervals. You may merge the overlapping intervals if needed. Return intervals after adding newInterval. Note: Intervals are non-overlapping if they have no common point. For example, [1,2] and [3,4] are non-overlapping, but [1,2] and [2,3] are overlapping. Example 1: Input: intervals = [[1,3],[4,6]], newInterval = [2,5] Output: [[1,6]] Example 2: Input: intervals = [[1,2],[3,5],[9,10]], newInterval = [6,7] Output: [[1,2],[3,5],[6,7],[9,10]] Constraints: 0 <= intervals.length <= 1000 newInterval.length == intervals[i].length == 2 0 <= start <= end <= 1000 123 class Solution: def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]: class Solution: def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]:
class Solution: #edge case -> [1,2] and [2,3] are overlapping def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]: res = [] for i in range(len(intervals)): #non-overlapping if newInterval[1] < intervals[i][0]: #if new value smaller than start res.append(newInterval) #everything that comes after non-overlaps return res + intervals[i:] elif newInterval[0] > intervals[i][1]: res.append(intervals[i]) else: #is overlapping newInterval = [ min(newInterval[0], intervals[i][0]), max(newInterval[1], intervals[i][1]), ] res.append(newInterval) return res
57
Merge Intervals: Given an array of intervals where intervals[i] = [start_i, end_i], merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input. You may return the answer in any order. Note: Intervals are non-overlapping if they have no common point. For example, [1, 2] and [3, 4] are non-overlapping, but [1, 2] and [2, 3] are overlapping. Example 1: Input: intervals = [[1,3],[1,5],[6,7]] Output: [[1,5],[6,7]] Example 2: Input: intervals = [[1,2],[2,3]] Output: [[1,3]] Constraints: 1 <= intervals.length <= 1000 intervals[i].length == 2 0 <= start <= end <= 1000 class Solution: def merge(self, intervals: List[List[int]]) -> List[List[int]]:
class Solution: #input arrays within the big intervals list might not be sorted #interval must be from 0...infinity #go thru the start indices, i.e. list[0][0], list[1][0], ..., list[4][0], ... #while at the same time oppositely comparing with end indices, i.e. list[-1][1] #O(n log n) def merge(self, intervals: List[List[int]]) -> List[List[int]]: intervals.sort(key = lambda i : i[0]) #sorting by all start interval values output = [intervals[0]] #avoid edge case for start, end in intervals[1:]: #skip first lastEnd = output[-1][1] #end value of most recent interval if start <= lastEnd: #overlapping output[-1][1] = max(lastEnd, end) #e.g. in [1,5] , [2,4] #we want to keep the 5 from the first when merging else: output.append([start,end]) #e.g. [1,5] , [7,8] = [1,5] , [7,8] -> equals itself, already sorted return output
58
Non-overlapping Intervals: Given an array of intervals intervals where intervals[i] = [start_i, end_i], return the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping. Note: Intervals are non-overlapping even if they have a common point. For example, [1, 3] and [2, 4] are overlapping, but [1, 2] and [2, 3] are non-overlapping. Example 1: Input: intervals = [[1,2],[2,4],[1,4]] Output: 1 Explanation: After [1,4] is removed, the rest of the intervals are non-overlapping. Example 2: Input: intervals = [[1,2],[2,4]] Output: 0 Constraints: 1 <= intervals.length <= 1000 intervals[i].length == 2 -50000 <= starti < endi <= 50000 class Solution: def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
class Solution: #use L R points, greedy approach #only need to check between intervals and see if second interval's start #after first's end -> then definitely not a overlap, otherwise yes #sort by start -> O(n log n) #basically check if one interval starts before second ends, then overlapping #then if first ends after second, delete first in order to minimize, repeat #update and "stretch" the start and end of full "number line" of intervals #combined def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int: intervals.sort() res = 0 prevEnd = intervals[0][1] for start, end in intervals[1:]: #start at index 1 if start >= prevEnd: #non-overlapping, even if equal prevEnd = end else: #overlapping res += 1 prevEnd = min(end, prevEnd) return res
59
Meeting Rooms: Given an array of meeting time interval objects consisting of start and end times [[start_1,end_1],[start_2,end_2],...] (start_i < end_i), determine if a person could add all meetings to their schedule without any conflicts. Example 1: Input: intervals = [(0,30),(5,10),(15,20)] Output: false Explanation: (0,30) and (5,10) will conflict (0,30) and (15,20) will conflict Example 2: Input: intervals = [(5,8),(9,15)] Output: true Note: (0,8),(8,10) is not considered a conflict at 8 Constraints: 0 <= intervals.length <= 500 0 <= intervals[i].start < intervals[i].end <= 1,000,000 """ Definition of Interval: class Interval(object): def __init__(self, start, end): self.start = start self.end = end """ class Solution: def canAttendMeetings(self, intervals: List[Interval]) -> bool:
""" Definition of Interval: class Interval(object): def __init__(self, start, end): self.start = start self.end = end """ #sort by start, then just scan thru #just compare end time of first and start time of second, repeat #O(n log n) class Solution: def canAttendMeetings(self, intervals: List[Interval]) -> bool: intervals.sort(key=lambda i: i.start) for i in range(1, len(intervals)): i1 = intervals[i-1] #prev i2 = intervals[i] #curr if i1.end > i2.start: return False return True
60
Meeting Rooms II: Given an array of meeting time interval objects consisting of start and end times [[start_1,end_1],[start_2,end_2],...] (start_i < end_i), find the minimum number of days required to schedule all meetings without any conflicts. Example 1: Input: intervals = [(0,40),(5,10),(15,20)] Output: 2 Explanation: day1: (0,40) day2: (5,10),(15,20) Example 2: Input: intervals = [(4,9)] Output: 1 Note: (0,8),(8,10) is not considered a conflict at 8 Constraints: 0 <= intervals.length <= 500 0 <= intervals[i].start < intervals[i].end <= 1,000,000 """ Definition of Interval: class Interval(object): def __init__(self, start, end): self.start = start self.end = end """ class Solution: def minMeetingRooms(self, intervals: List[Interval]) -> int:
""" Definition of Interval: class Interval(object): def __init__(self, start, end): self.start = start self.end = end """ #if start=end, for this problem we assume it is non-overlapping #sort, then have 2 arrays for starts and end, compare side-by-side and if #start int: start = sorted([i.start for i in intervals]) end = sorted([i.end for i in intervals]) res, count = 0, 0 s, e = 0, 0 #starting and ending position pointers while s < len(intervals): if start[s] < end[e]: s += 1 count +=1 #we have an additional meeting else: e += 1 count -=1 res = max(res, count) return res
61
Rotate Image: Given a square n x n matrix of integers matrix, rotate it by 90 degrees clockwise. You must rotate the matrix in-place. Do not allocate another 2D matrix and do the rotation. Example 1: Input: matrix = [ [1,2], [3,4] ] Output: [ [3,1], [4,2] ] Example 2: Input: matrix = [ [1,2,3], [4,5,6], [7,8,9] ] Output: [ [7,4,1], [8,5,2], [9,6,3] ] Constraints: n == matrix.length == matrix[i].length 1 <= n <= 20 -1000 <= matrix[i][j] <= 1000 class Solution: def rotate(self, matrix: List[List[int]]) -> None:
class Solution: def rotate(self, matrix: List[List[int]]) -> None: l, r = 0, len(matrix) - 1 while l < r: for i in range(r-l): top, bottom = l, r #save top left top_left = matrix[top][l+i] #move bottom left -> top left matrix[top][l + i] = matrix[bottom - i][l] #move bottom right -> bottom left matrix[bottom - i][l] = matrix[bottom][r - i] # #move top right -> bottom right matrix[bottom][r - i] = matrix[top + i][r] #move top left -> top right matrix[top + i][r] = top_left r -= 1 l += 1
62
Spiral Matrix: Given an m x n matrix of integers matrix, return a list of all elements within the matrix in spiral order. Example 1: Input: matrix = [[1,2],[3,4]] Output: [1,2,4,3] Example 2: Input: matrix = [[1,2,3],[4,5,6],[7,8,9]] Output: [1,2,3,6,9,8,7,4,5] Example 3: Input: matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]] Output: [1,2,3,4,8,12,11,10,9,5,6,7] Constraints: 1 <= matrix.length, matrix[i].length <= 10 -100 <= matrix[i][j] <= 100 class Solution: def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
class Solution: #basically start from "outer" row/col and go all the way left, then down, then #right, then up, then the rest is a submatrix and do the same #specificy top and bottom boundaries for submatricies #use pointers for top and left, which are both 0, then make right and bottom #one more than rightmost/bottomest index (basically telling us when to stop) #after first row traversed, shift top down, then traverse down fully, shift #right to the left, then traverse left fully, shift bottom up, then traverse #up fully, shift left to the right, repeat #O(m*n) def spiralOrder(self, matrix: List[List[int]]) -> List[int]: res = [] directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] steps = [len(matrix[0]), len(matrix) - 1] r, c, d = 0, -1, 0 while steps[d & 1]: for i in range(steps[d & 1]): r += directions[d][0] c += directions[d][1] res.append(matrix[r][c]) steps[d & 1] -= 1 d += 1 d %= 4 return res
63
Set Matrix Zeroes: Given an m x n matrix of integers matrix, if an element is 0, set its entire row and column to 0's. You must update the matrix in-place. Follow up: Could you solve it using O(1) space? Example 1: Input: matrix = [ [0,1], [1,1] ] Output: [ [0,0], [0,1] ] Example 2: Input: matrix = [ [1,2,3], [4,0,5], [6,7,8] ] Output: [ [1,0,3], [0,0,0], [6,0,8] ] Constraints: 1 <= matrix.length, matrix[0].length <= 100 -2^31 <= matrix[i][j] <= (2^31) - 1 class Solution: def setZeroes(self, matrix: List[List[int]]) -> None:
class Solution: #have array, go single cell and start top left and mark 0 if there are any 0's #in the row, mark 0's for any cols that are needed def setZeroes(self, matrix: List[List[int]]) -> None: #O(1) -> O(m*n) ROWS, COLS = len(matrix), len(matrix[0]) mark = [[matrix[r][c] for c in range(COLS)] for r in range(ROWS)] #determine which rows/cols need to be zero for r in range(ROWS): for c in range(COLS): if matrix[r][c] == 0: for col in range(COLS): mark[r][col] = 0 for row in range(ROWS): mark[row][c] = 0 #replace 0's for r in range(ROWS): for c in range(COLS): matrix[r][c] = mark[r][c]
64
Number of One Bits: You are given an unsigned integer n. Return the number of 1 bits in its binary representation. You may assume n is a non-negative integer which fits within 32-bits. Example 1: Input: n = 00000000000000000000000000010111 Output: 4 Example 2: Input: n = 01111111111111111111111111111101 Output: 30 class Solution: def hammingWeight(self, n: int) -> int:
class Solution: def hammingWeight(self, n: int) -> int: res = 0 while n: n &= n - 1 res += 1 return res
65
Counting Bits: Given an integer n, count the number of 1's in the binary representation of every number in the range [0, n]. Return an array output where output[i] is the number of 1's in the binary representation of i. Example 1: Input: n = 4 Output: [0,1,1,2,1] Explanation: 0 --> 0 1 --> 1 2 --> 10 3 --> 11 4 --> 100 Constraints: 0 <= n <= 1000 class Solution: def countBits(self, n: int) -> List[int]:
class Solution: def countBits(self, n: int) -> List[int]: dp = [0] * (n + 1) for i in range(n + 1): dp[i] = dp[i >> 1] + (i & 1) return dp
66
Reverse Bits: Given a 32-bit unsigned integer n, reverse the bits of the binary representation of n and return the result. Example 1: Input: n = 00000000000000000000000000010101 Output: 2818572288 (10101000000000000000000000000000) Explanation: Reversing 00000000000000000000000000010101, which represents the unsigned integer 21, gives us 10101000000000000000000000000000 which represents the unsigned integer 2818572288. class Solution: def reverseBits(self, n: int) -> int:
class Solution: def reverseBits(self, n: int) -> int: res = 0 for i in range(32): bit = (n >> i) & 1 res += (bit << (31 - i)) return res
67
Missing Number: Given an array nums containing n integers in the range [0, n] without any duplicates, return the single number in the range that is missing from nums. Follow-up: Could you implement a solution using only O(1) extra space complexity and O(n) runtime complexity? Example 1: Input: nums = [1,2,3] Output: 0 Explanation: Since there are 3 numbers, the range is [0,3]. The missing number is 0 since it does not appear in nums. Example 2: Input: nums = [0,2] Output: 1 Constraints: 1 <= nums.length <= 1000 class Solution: def missingNumber(self, nums: List[int]) -> int:
class Solution: #O(n) def missingNumber(self, nums: List[int]) -> int: res = len(nums) for i in range(len(nums)): res += i - nums[i] return res
68
Sum of Two Integers: Given two integers a and b, return the sum of the two integers without using the + and - operators. Example 1: Input: a = 1, b = 1 Output: 2 Example 2: Input: a = 4, b = 7 Output: 11 Constraints: -1000 <= a, b <= 1000 class Solution: def getSum(self, a: int, b: int) -> int:
class Solution: def getSum(self, a: int, b: int) -> int: mask = 0xFFFFFFFF max_int = 0x7FFFFFFF while b != 0: carry = (a & b) << 1 a = (a ^ b) & mask b = carry & mask return a if a <= max_int else ~(a ^ mask)
69
Rotate Array: 1-D, then 2-D
class Solution: def rotate(self, matrix: List[List[int]], k: int) -> None: k = k % len(matrix) if k != 0: matrix[:k], matrix [k:] = matrix[-k:], matrix[:-k] class Solution: def rotate(self, matrix: List[List[int]], k: int) -> None: # Flatten the matrix flat = [elem for row in matrix for elem in row] # Rotate the flattened list (1D array) k = k % len(flat) if k != 0: flat = flat[-k:] + flat[:-k] # Fill the matrix back with rotated values for i in range(len(matrix)): matrix[i] = flat[i * len(matrix[0]):(i + 1) * len(matrix[0])]
70
Binary Tree Traversal: -Inorder -Preorder -Postorder -Level order
-Inorder ---------------------> LRR (left, root, right) -Preorder (DFS) -----------> RLR (root, left, right) -Postorder ------------------> LCR/LRR (left, right/child, root) -Level order (BFS) -------> L by L (level by level) class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right class BinaryTree: def inorderTraversal(self, root): return self.inorderTraversal(root.left) + [root.val] + self.inorderTraversal(root.right) if root else [] def preorderTraversal(self, root): return [root.val] + self.preorderTraversal(root.left) + self.preorderTraversal(root.right) if root else [] def postorderTraversal(self, root): return self.postorderTraversal(root.left) + self.postorderTraversal(root.right) + [root.val] if root else [] def levelOrderTraversal(self, root): if not root: return [] levels, queue = [], [(root, 0)] while queue: node, level = queue.pop(0) if level == len(levels): levels.append([]) levels[level].append(node.val) if node.left: queue.append((node.left, level + 1)) if node.right: queue.append((node.right, level + 1)) return levels
71
Binary Search
#O( log n) class Solution: def search(self, nums: List[int], target: int) -> int: low, high = 0, len(nums) - 1 while low <= high: mid = (low + high) // 2 if nums[mid] == target: return mid elif nums[mid] < target: low = mid + 1 else: high = mid - 1 return -1
72
Mergesort
def merge_sort(arr): def merge(left, right): sorted_arr = [] while left and right: if left[0] < right[0]: sorted_arr.append(left.pop(0)) else: sorted_arr.append(right.pop(0)) sorted_arr.extend(left or right) return sorted_arr if len(arr) > 1: mid = len(arr) // 2 left_half = merge_sort(arr[:mid]) right_half = merge_sort(arr[mid:]) return merge(left_half, right_half) else: return arr
73
Quicksort
def quick_sort(arr): def partition(low, high): pivot = arr[high] i = low - 1 for j in range(low, high): if arr[j] <= pivot: i += 1 arr[i], arr[j] = arr[j], arr[i] arr[i + 1], arr[high] = arr[high], arr[i + 1] return i + 1 def sort(low, high): if low < high: pi = partition(low, high) sort(low, pi - 1) sort(pi + 1, high) sort(0, len(arr) - 1) Example usage arr = [10, 7, 8, 9, 1, 5] quick_sort(arr) print("Sorted array is:", arr)
74
Palindrome: Check if string is valid palindrome (Javascript)
/** * @param {string} s * @return {boolean} */ var isPalindrome = function(s) { const cleanStr = s.toLowerCase().replace(/[^a-z0-9]/g, ''); const reversedStr = cleanStr.split('').reverse().join(''); return cleanStr === reversedStr; }; // Test cases function testIsPalindrome() { console.log("Test 1 Passed:", isPalindrome("A man, a plan, a canal: Panama") === true); console.log("Test 2 Passed:", isPalindrome("race a car") === false); console.log("Test 3 Passed:", isPalindrome(" ") === true); // considering empty string or spaces as palindromes console.log("Test 4 Passed:", isPalindrome("12321") === true); console.log("Test 5 Passed:", isPalindrome("123456") === false); } testIsPalindrome();
75
Longest Substring without Repeated Characters
#O(n) class Solution: def lengthOfLongestSubstring(self, s: str) -> int: left = 0 seen = {} output = 0 for right, curr in enumerate(s): if curr in seen: left = max(left, seen[curr] + 1) output = max(output, right - left + 1) seen[curr] = right return output