0% found this document useful (0 votes)
14 views39 pages

Merge Strings and String Algorithms

The document contains multiple Python class solutions for various algorithmic problems, including merging strings, finding the greatest common divisor of strings, and manipulating arrays. Each class implements a method to solve a specific problem, showcasing different approaches and optimizations. The problems range from string manipulation to array processing and include challenges like finding maximum averages and counting vowels.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
14 views39 pages

Merge Strings and String Algorithms

The document contains multiple Python class solutions for various algorithmic problems, including merging strings, finding the greatest common divisor of strings, and manipulating arrays. Each class implements a method to solve a specific problem, showcasing different approaches and optimizations. The problems range from string manipulation to array processing and include challenges like finding maximum averages and counting vowels.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

1) 1768.

Merge Strings Alternately

class Solution:
def mergeAlternately(self, word1: str, word2: str) -> str:
x = ''
if len(word1)>len(word2):
n = len(word2)
for i in range(n):
x = x + word1[i] + word2[i]
x = x + word1[n:]
else:
n= len(word1)
for i in range(n):
x = x + word1[i] + word2[i]
x = x+ word2[n:]
return x

class Solution:
def mergeAlternately(self, word1: str, word2: str) -> str:
x = ''
if len(word1)>=len(word2):
for i in range(len(word2)):
x = x + word1[i]+word2[i]
x = x+ word1[i+1:]
if len(word2)>len(word1):
for i in range(len(word1)):
x = x+ word1[i]+word2[i]
x = x+ word2[i+1:]
return x

class Solution:
def mergeAlternately(self, word1: str, word2: str) -> str:
x = ''
for i in range(min(len(word1),len(word2))):
x = x+word1[i]+word2[i]
if word1[i+1:]:
x = x+ word1[i+1:]
else:
x = x+word2[i+1:]
return x

---------------------
2) 1071. Greatest Common Divisor of Strings

class Solution:
def gcdOfStrings(self, str1: str, str2: str) -> str:
if str1+str2 != str2+str1:
return ""
min_val = min(len(str1),len(str2))
print('min_val',min_val)
for i in range(min_val,0,-1):
if len(str1)%i==0 and len(str2)%i==0:
print('str1[:i]',str1[:i])
return str1[:i]
return str1[:1]
--------------------

class Solution:
def gcdOfStrings(self, str1: str, str2: str) -> str:
if str1+str2 != str2+str1:
return ''
for i in range(min(len(str1),len(str2)),0,-1):
if len(str1)%i ==0 and len(str2)%i == 0:
return str1[:i]

class Solution:
def gcdOfStrings(self, str1: str, str2: str) -> str:
if str1+str2!=str2+str1:
return ""
else:
def gcd(n1,n2):
for i in range(min(n1,n2),0,-1):
if n1%i==0 and n2%i==0:
return i
n1=len(str1)
n2=len(str2)
return str1[:gcd(n1,n2)]

----------------------------

3) 1431. Kids With the Greatest Number of Candies

import numpy as np
class Solution:
def kidsWithCandies(self, candies: List[int], extraCandies: int) -> List[bool]:
max_cand = 0
kgnc = [None]*len(candies)
# kgnc = [Link](len(candies))
print('kgnc',kgnc)
for i in range(len(candies)):
if candies[i]>max_cand:
max_cand = candies[i]
print(max_cand)
for i in range(len(candies)):
if candies[i]+extraCandies>=max_cand:
kgnc[i]=True
else:
kgnc[i]=False
return kgnc

import numpy as np
class Solution:
def kidsWithCandies(self, candies: List[int], extraCandies: int) -> List[bool]:
max_candies = max(candies)
for i in range(len(candies)):
if candies[i]+extraCandies<max_candies:
candies[i]=False
else:
candies[i]=True
return candies
-----------------------------

4) 605. Can Place Flowers

class Solution:
def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool:
if n==0:
return True
if len(flowerbed)==1:
if flowerbed[0]==0:
n = n-1
if n <=0:
return True
else:
return False
if len(flowerbed)==0 and n>1:
return False
if flowerbed[1]==0 and flowerbed[0]==0:
n = n-1
flowerbed[0]=1
if n==0:
return True
if flowerbed[-2]==0 and flowerbed[-1]==0:
n = n-1
flowerbed[-1]=1
if n==0:
return True
for i in range(1,len(flowerbed)-1):
if flowerbed[i-1]==0 and flowerbed[i+1]==0 and flowerbed[i]!=1:
n = n-1
flowerbed[i]=1
if n==0 or n<0:
return True
else :
return False

return x

-------------------------------------

5) 345. Reverse Vowels of a String

class Solution:
def reverseVowels(self, s: str) -> str:
vo = ''
for i in range(len(s)):
if s[i] in {'a','e','i','o','u','A' ,"E","I","O","U"}:
vo = vo + s[i]
print('vo',vo)
l = ''
n = -1
for i in range(int(len(s))):
if s[i] in {'a','e','i','o','u' ,'A' ,"E","I","O","U"}:
print('i',i)
print('s[i]',s[i])
print('vo[n]',vo[n])
l=l+vo[n]
n = n-1
else:
l = l + s[i]
print('l',l)
return l

-----

class Solution:
def reverseVowels(self, s: str) -> str:
s_arr = list(s)
vowels = 'aeiouAEIOU'
start = 0
end = len(s)-1
while start<end:
while start<end and [Link](s_arr[start])==-1:
start+=1
while start<end and [Link](s_arr[end])==-1:
end-=1
s_arr[start],s_arr[end]=s_arr[end],s_arr[start]
start+=1
end-=1
return "".join(s_arr)

--------------------------------

6) 151. Reverse Words in a String

class Solution:
def reverseWords(self, s: str) -> str:
s_fin = []
s_arr = [Link](' ')
print('s_arr',s_arr)
for i in range(len(s_arr)):
if s_arr[i]!='':
s_fin.append(s_arr[i])
s_fin = s_fin[::-1]
print('s_fin',s_fin)
return ' '.join(s_fin)

class Solution:
def reverseWords(self, s: str) -> str:
s= [Link](' ')
s =list(s)
print('s',s)
s= [word for word in s[::-1] if word!='']
return ' '.join(s)

class Solution:
def reverseWords(self, s: str) -> str:
s = [Link]()
start = 0
end = len(s)-1
while start<end:
while start<end and s[start]==' ':
start+=1
while start<end and s[end]==' ':
end-=1
s[start],s[end]=s[end],s[start]

start +=1
end-=1
return ' '.join(s)

--------------------------------

7) 238. Product of Array Except Self

### not working for 0

class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
prod = 1
for i in range(len(nums)):
print('i',i)
print('nums[i]',nums[i])
prod*=nums[i]
for i in range(len(nums)):
if nums[i]!=0:
nums[i]=int(prod/nums[i])
return nums

#### time limit exceeded

class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
arr = [1]*(len(nums))
for i in range(len(nums)):
for j in range(len(nums)):
if i!=j :
arr[i]=arr[i]*nums[j]
return arr

#### more mememory but passed

class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
answer_l = [1]*len(nums)
for i in range(1,len(nums)):
answer_l[i] = answer_l[i-1]*nums[i-1]
print('answer_l',answer_l)
answer_r = [1]*len(nums)
for i in range(len(nums)-2,-1,-1):
answer_r[i]= answer_r[i+1]*nums[i+1]
print('answer_r',answer_r)
answer = [1]*len(answer_l)
for i in range(len(answer_l)):
answer[i]= answer_l[i]*answer_r[i]
print('answer',answer)
return answer

########### less memeory

class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
answer = [1]*len(nums)
for i in range(1,len(nums)):
answer[i] = answer[i-1]*nums[i-1]
print('answer',answer)
right = nums[-1]
for i in range(len(nums)-2,-1,-1):
answer[i]=right*answer[i]
print('i',i)
print('answer[i]',answer[i])
right = right * nums[i]
return answer

------------------------------------------

8) 334. Increasing Triplet Subsequence

### n**3 time limit exceeded

class Solution:
def increasingTriplet(self, nums: List[int]) -> bool:
for i in range(len(nums)):
for j in range(i+1,len(nums)):
for k in range(j+1,len(nums)):
if nums[i]<=nums[j]<=nums[k]:
return True
return False

#### more space solution

import sys

max_value = [Link]
min_value = -[Link] - 1

class Solution:
def increasingTriplet(self, nums: List[int]) -> bool:
left_low = [max_value]*len(nums)
left_low[0]=nums[0]
for i in range(len(nums)):
left_low[i] = min(left_low[i-1],nums[i])
right_high = [min_value]*len(nums)
right_high[-1] = nums[-1]
for i in range(len(nums)-2,-1,-1):
right_high[i] = max(right_high[i+1],nums[i])
for i in range(1,len(nums)-1):
if nums[i]>left_low[i-1] and nums[i]<right_high[i+1]:
return True
return False
####### most optmized solution

import sys

max_value = [Link]
min_value = -[Link] - 1

class Solution:
def increasingTriplet(self, nums: List[int]) -> bool:
int1 = max_value
int2 = max_value

for i in range(len(nums)):
int3 = nums[i]
if int1>=int3:
int1=int3
elif int2>=int3:
int2=int3
else :
return True
int3 = nums[i]
return False

----------------------

9) 443. String Compression

class Solution:
def compress(self, chars: List[str]) -> int:
i = 0
j = 0
while j<len(chars):
char = chars[j]
count=0
while j<len(chars) and chars[j]==char:
j+=1
count+=1
chars[i]=char
i+=1
if count>1:
for digit in str(count):
chars[i]= digit
i+=1
return i

------------------------------

10) 283. Move Zeroes

class Solution:
def moveZeroes(self, nums: list) -> None:
slow = 0
for fast in range(len(nums)):
if nums[slow]==0 and nums[fast]!=0:
nums[slow],nums[fast]=nums[fast],nums[slow]
if nums[slow]!=0:
slow+=1
return nums

class Solution:
def moveZeroes(self, nums: list) -> None:
slow = 0
fast = 0
while slow<=fast and fast<=len(nums)-1:
if nums[slow]==0 and nums[fast]!=0:
nums[slow],nums[fast]=nums[fast],nums[slow]
if nums[slow]!=0:
slow+=1
fast+=1
return nums

-------------------------

11) 392. Is Subsequence

class Solution:
def isSubsequence(self, s: str, t: str) -> bool:
p=0
q=0
if len(s)==0 :
return True
elif len(t)==0:
return False
else:
while q<len(t) and p<len(s):
if s[p]==t[q]:
p+=1
q+=1
else :
q+=1
return True if p==len(s) else False

---------------------

12) 11. Container With Most Water

class Solution:
def maxArea(self, height: List[int]) -> int:
left = 0
right = len(height)-1
max_size = 0
while left<right:
max_size = max(max_size,(right-left)*min(height[left],height[right]))
if height[right]<height[left]:
right-=1
else:
left+=1
return max_size

--------------------------------
13) 1679. Max Number of K-Sum Pairs

class Solution:
def maxOperations(self, nums: List[int], k: int) -> int:
counter = {}
count = 0
for num in nums:
counter[num]=[Link](num,0)+1
for i in range(len(nums)):
compliment = k-nums[i]
if compliment in counter and counter[compliment]>0 and
counter[nums[i]]>0:
if compliment==nums[i] and counter[nums[i]]<2:
continue
else :
counter[nums[i]]-=1
counter[compliment]-=1
count+=1
return count

------------------------

14) 643. Maximum Average Subarray I

class Solution:
def findMaxAverage(self, nums: List[int], k: int) -> float:
left = 0
right = k
current_sum = sum(nums[:k])
max_sum = current_sum
print('nums length',len(nums))
while right<len(nums):
current_sum = current_sum-nums[left]+nums[right]
left+=1
right+=1
max_sum = max(max_sum,current_sum)
return max_sum/k

class Solution:
def findMaxAverage(self, nums: List[int], k: int) -> float:
left=0
current_sum = sum(nums[:k])
max_sum = current_sum
for right in range(k,len(nums)):
current_sum = current_sum+nums[right]-nums[left]
left+=1
max_sum = max(max_sum,current_sum)
return max_sum/k

------------------------------

15) 1456. Maximum Number of Vowels in a Substring of Given Length

class Solution:
def maxVowels(self, s: str, k: int) -> int:
vowels = 'aeiouAEIOU'
left = 0
right = k
current_vowels = 0
for l in s[:k]:
if [Link](l)==-1:
continue
else:
current_vowels+=1
max_vowels = current_vowels

def findVowels(k):
if [Link](k)==-1:
return 0
else:
return 1

while right<len(s):
current_vowels = current_vowels-(findVowels(s[left]))
+findVowels(s[right])
max_vowels = max(current_vowels,max_vowels)
right+=1
left+=1
return max_vowels

class Solution:
def maxVowels(self, s: str, k: int) -> int:
vowels = {'A','E','I','O','U','a','e','i','o','u'}
curr_vowels = sum([1 for i in s[:k] if i in vowels])
max_vowels = curr_vowels
left = 0
right = k
while right<len(s):
if s[left] in vowels:
curr_vowels -=1
if s[right] in vowels:
curr_vowels+=1
max_vowels = max(curr_vowels,max_vowels)
left+=1
right+=1
return max_vowels

------------------------

16) 1004. Max Consecutive Ones III

class Solution:
def longestOnes(self, nums: List[int], k: int) -> int:
slow = 0
output = 0
count = 0
for fast in range(len(nums)):
if nums[fast]==0:
count+=1
while count>k:
if nums[slow]==0:
count-=1
slow+=1
output = max(output,fast-slow+1)

return output
----------------------------

17) 1493. Longest Subarray of 1's After Deleting One Element

class Solution:
def longestSubarray(self, nums: List[int]) -> int:
left = 0
right = 0
count=0
max_length = 0

for right in range(len(nums)):


if nums[right]==0:
count+=1
while count>1:
if nums[left]==0:
count-=1
left+=1
max_length = max(max_length,right-left)
return max_length

------------------------------

18) 1732. Find the Highest Altitude

class Solution:
def largestAltitude(self, gain: List[int]) -> int:
current_altitude , greatest_altitude = 0,0
for i in gain:

current_altitude +=i
greatest_altitude = max(greatest_altitude,current_altitude)
return greatest_altitude

------------------------------

19) 724. Find Pivot Index

class Solution:
def pivotIndex(self, nums: List[int]) -> int:
total = sum(nums)
left_total = 0
for i in range(len(nums)):
right_total = total-nums[i]-left_total
if right_total ==left_total:
return i
left_total +=nums[i]
return -1

-------------------------------

20) 2215. Find the Difference of Two Arrays


class Solution:
def findDifference(self, nums1: List[int], nums2: List[int]) ->
List[List[int]]:
set1 = set(nums1)
set2 = set(nums2)
diff1 = set1-set2
diff2 = set2-set1

return [list(diff1),list(diff2)]

-----------------------------

21) 1207. Unique Number of Occurrences

from collections import Counter


class Solution:
def uniqueOccurrences(self, arr: List[int]) -> bool:
count = Counter(arr)
occurances = list([Link]())
return True if len(occurances)==len(set(occurances)) else False

class Solution:
def uniqueOccurrences(self, arr: List[int]) -> bool:
counter = {}
for i in range(len(arr)):
counter[arr[i]]=[Link](arr[i],0)+1
return True if len([Link]())==len(set([Link]())) else
False

------------------------------------

22) 1657. Determine if Two Strings Are Close

class Solution:
def closeStrings(self, word1: str, word2: str) -> bool:
if len(word1)!=len(word2):
return False
dict_1 = {}
dict_2 = {}
for word in word1:
dict_1[word]=dict_1.get(word,0)+1
for word in word2:
dict_2[word]=dict_2.get(word,0)+1
if set(dict_1.keys())!=set(dict_2.keys()):
return False
if sorted(dict_1.values())!=sorted(dict_2.values()):
return False
return True

--------------------------------

23) 2352. Equal Row and Column Pairs

class Solution:
def equalPairs(self, grid: List[List[int]]) -> int:
n = len(grid)
hashmap = {}
for row in grid:
print('row',row)
rowstr = str(row)
hashmap[rowstr] = [Link](rowstr,0)+1
count=0
for j in range(n):
col = [grid[i][j] for i in range(n)]
colstr = str(col)
count+= [Link](colstr,0)

return count

-------------------------------------

24) 2390. Removing Stars From a String

class Solution:
def removeStars(self, s: str) -> str:
res = []
for i in s:
if i =="*":
[Link]()
else:
[Link](i)
return "".join(res)

--------------------------------------

25) 735. Asteroid Collision

class Solution:
def asteroidCollision(self, asteroids: List[int]) -> List[int]:
output = []
for asteroid in asteroids:
while output and output[-1]>0 and asteroid<0:
if -asteroid==output[-1]:
[Link]()
elif -asteroid>output[-1]:
[Link]()
continue
break
else:
[Link](asteroid)
return output

---------------------------------------

26) 394. Decode String

class Solution:
def decodeString(self, s: str) -> str:
stack = []
for i in range(len(s)):
if s[i]!=']':
[Link](s[i])
else:
substring = ''
while(stack[-1]!='['):
substring = [Link]() + substring
[Link]()
num=''
while(stack and stack[-1].isdigit()):
num = [Link]()+num
num = int(num)
[Link](num*substring)
return ''.join(stack)

-----------------------------------

27) 933. Number of Recent Calls

import collections
class RecentCounter:

def __init__(self):
self.q = [Link]()

def ping(self, t: int) -> int:


[Link](t)

while self.q and self.q[0]<t-3000:


[Link]()
return len(self.q)

# Your RecentCounter object will be instantiated and called as such:


# obj = RecentCounter()
# param_1 = [Link](t)

-----------------------------------

28) 649. Dota2 Senate

class Solution:
def predictPartyVictory(self, senate: str) -> str:
senate = list(senate)
D,R = deque(),deque()
for i,e in enumerate(senate):
if e =='R':
[Link](i)
else :
[Link](i)
while D and R:
dTurn = [Link]()
rTurn = [Link]()
if dTurn<rTurn:
[Link](dTurn+len(senate))
else :
[Link](rTurn+len(senate))
return "Radiant" if R else "Dire"

-------------------------------------------

29) 2095. Delete the Middle Node of a Linked List

# Definition for singly-linked list.


class ListNode:
def __init__(self, val=0, next=None):
[Link] = val
[Link] = next
class Solution:
def deleteMiddle(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head or not [Link]:
return None
slow = head
fast = head
prev = None

while fast and [Link]:


prev = slow
slow = [Link]
fast = [Link]
[Link] = [Link]

return head

----------------------------

30) 328. Odd Even Linked List

# Definition for singly-linked list.


class ListNode:
def __init__(self, val=0, next=None):
[Link] = val
[Link] = next
class Solution:
def oddEvenList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head or not [Link]:
return head

odd = head
even = [Link]
even_head = even

while even and [Link]:


[Link] = [Link]
odd = [Link]
[Link] = [Link]
even = [Link]
[Link] = even_head
return head

-----------------------------------------

31) 206. Reverse Linked List

# Definition for singly-linked list.


class ListNode:
def __init__(self, val=0, next=None):
[Link] = val
[Link] = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
prev = None
curr = head
while curr:
next_node = [Link]
[Link] = prev
prev = curr
curr = next_node
return prev

---------------------------------------

32) 2130. Maximum Twin Sum of a Linked List

# Definition for singly-linked list.


class ListNode:
def __init__(self, val=0, next=None):
[Link] = val
[Link] = next
class Solution:
def pairSum(self, head: Optional[ListNode]) -> int:
slow,fast = head,head
prev = None
while fast and [Link]:
fast = [Link]
temp = [Link]
[Link] = prev
prev = slow
slow = temp

res = 0
while slow:
res = max(res, [Link]+[Link])
prev = [Link]
slow = [Link]
return res

-------------------------

33) 104. Maximum Depth of Binary Tree

# Definition for a binary tree node.


class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
return 1+max([Link]([Link]),[Link]([Link]))

--------------------------------

34)872. Leaf-Similar Trees

# Definition for a binary tree node.


class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
class Solution:
def leafSimilar(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) ->
bool:
leaf1 = []
leaf2 = []
def dfs(root,curr):
if not root:
return
if not [Link] and not [Link]:
[Link]([Link])
dfs([Link],curr)
dfs([Link],curr)
dfs(root1,leaf1)
dfs(root2,leaf2)
return leaf1==leaf2

---------------------------------

Why the Difference?


Instance Methods (like maxDepth):

They are defined at the class level.


They are bound to the instance (accessed via self).
When calling an instance method (even recursively), you must use
[Link](...).
Local (Nested) Functions (like dfs in leafSimilar):

They are defined within a method.


Their scope is local to that method, and they are not attributes of the instance.
You can call them directly by name within that method.
Thus, in your leafSimilar example, since dfs is just a helper function local to
leafSimilar, you don’t use self. when calling it. If you had defined dfs as a
separate method at the class level, you would need to call it with [Link](...).

I hope this clears up the concept!

----------------------------

35) 1448. Count Good Nodes in Binary Tree

# Definition for a binary tree node.


class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
class Solution:
def goodNodes(self, root: TreeNode) -> int:
def dfs(root,maxValue):
if not root:
return 0
maxValue = max(maxValue,[Link])

if [Link]==maxValue:
return 1+dfs([Link],maxValue)+dfs([Link],maxValue)
else:
return 0+ dfs([Link],maxValue)+dfs([Link],maxValue)
return dfs(root,[Link])

----------------------------

36) 437. Path Sum III

# Definition for a binary tree node.


class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
class Solution:
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> int:
def dfs(node,currsum):
nonlocal ans,prefixsum
if node is None:
return

currsum +=[Link]
ans+=[Link](currsum-targetSum,0)

prefixsum[currsum]=[Link](currsum,0)+1

dfs([Link],currsum)
dfs([Link],currsum)

prefixsum[currsum]-=1

prefixsum = {}
prefixsum[0]=1
ans = 0
dfs(root,0)
return ans

-----------------------------------------

37) 1372. Longest ZigZag Path in a Binary Tree

# Definition for a binary tree node.


class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
class Solution:
def longestZigZag(self, root: Optional[TreeNode]) -> int:
[Link] = 0
def solve(node,deep,dir):
[Link] = max([Link],deep)
if [Link] is not None:
if dir!='left':
solve([Link],deep+1,'left')
else:
solve([Link],1,'left')
if [Link] is not None:
if dir!='right':
solve([Link],deep+1,'right')
else:
solve([Link],1,'right')
solve(root,0,'')
return [Link]

# Definition for a binary tree node.


class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
class Solution:
def longestZigZag(self, root: Optional[TreeNode]) -> int:
max_length = 0
def dfs(node,dir,length):
nonlocal max_length
max_length = max(max_length,length)
if [Link] is not None:
if dir!='left':
dfs([Link],'left',length+1)
else:
dfs([Link],'left',1)
if [Link] is not None:
if dir!='right':
dfs([Link],'right',length+1)
else:
dfs([Link],'right',1)
dfs(root,'',0)
return max_length

-------------------------------------------

38) 236. Lowest Common Ancestor of a Binary Tree

# Definition for a binary tree node.


class TreeNode:
def __init__(self, x):
[Link] = x
[Link] = None
[Link] = None

class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode')
-> 'TreeNode':
if not root or root==p or root==q:
return root
left = [Link]([Link],p,q)
right = [Link]([Link],p,q)

if left and right:


return root

return left or right

----------------------------------------

39) 199. Binary Tree Right Side View


# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# [Link] = val
# [Link] = left
# [Link] = right
class Solution:
def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
res = []
q= [Link]([root])

while q:
rightside = None
qlen = len(q)
for i in range(qlen):
node = [Link]()
if node:
rightside = node
[Link]([Link])
[Link]([Link])
if rightside:
[Link]([Link])
return res

----------------

40) 1161. Maximum Level Sum of a Binary Tree


DFS
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# [Link] = val
# [Link] = left
# [Link] = right
class Solution:
def maxLevelSum(self, root: Optional[TreeNode]) -> int:
sums = [0]
def traverse(node,level):
if not node:
return
if level>len(sums)-1:
[Link](0)
sums[level]+=[Link]
traverse([Link],level+1)
traverse([Link],level+1)
traverse(root,0)
res = float("-inf")
res_index=-1
print(sums)
for i,e in enumerate(sums):
if e>res:
res_index = i
res =e

return res_index+1
------------------------------------
BFS

# Definition for a binary tree node.


# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# [Link] = val
# [Link] = left
# [Link] = right
class Solution:
def maxLevelSum(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
q = [root]
level = 1
max_level = 1
max_sum = float('-inf')

while q:
level_sum = 0
next_level = []
for node in q:
level_sum +=[Link]

if [Link]:
next_level.append([Link])
if [Link]:
next_level.append([Link])
if level_sum>max_sum:
max_sum = level_sum
max_level = level
q = next_level
level+=1
return max_level

---------------------------------------

41) 700. Search in a Binary Search Tree

BFS

# Definition for a binary tree node.


# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# [Link] = val
# [Link] = left
# [Link] = right
class Solution:
def searchBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
curr = root
while curr and [Link]!=val:
if [Link]<val:
curr = [Link]
else:
curr = [Link]
return curr
DFS

# Definition for a binary tree node.


# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# [Link] = val
# [Link] = left
# [Link] = right
class Solution:
def searchBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
if root is None:
return root
if [Link] == val:
return root
if [Link]<val:
return [Link]([Link],val)
elif [Link]>val:
return [Link]([Link],val)

-------------------------------------------------

42) 450. Delete Node in a BST

# Definition for a binary tree node.


# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# [Link] = val
# [Link] = left
# [Link] = right
class Solution:
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
if not root:
return root
if key>[Link]:
[Link] = [Link]([Link],key)
elif key<[Link]:
[Link] = [Link]([Link],key)
else:
if not [Link]:
return [Link]
elif not [Link]:
return [Link]
curr = [Link]
while [Link]:
curr = [Link]
[Link] = [Link]
[Link] = [Link]([Link],[Link])
return root

-------------

43) 841. Keys and Rooms

- DFS

class Solution:
def canVisitAllRooms(self, rooms: List[List[int]]) -> bool:
visited = set()
def dfs(room):
if room in visited:
return
[Link](room)
for key in rooms[room]:
dfs(key)
dfs(0)
return len(visited)==len(rooms)

- BFS

class Solution:
def canVisitAllRooms(self, rooms: List[List[int]]) -> bool:
visited = set()
queue = deque([0])

while queue:
room = [Link]()
if room not in visited:
[Link](room)
for key in rooms[room]:
if key not in visited:
[Link](key)
return len(rooms)==len(visited)

----------------------------------------------------

44) 547. Number of Provinces

class Solution:
def findCircleNum(self, isConnected: List[List[int]]) -> int:

def dfs(i):
[Link](i)
for j in range(n):
if isConnected[i][j] and j not in [Link]:
dfs(j)
return

province = 0
[Link] = set()
n = len(isConnected)
for i in range(n):
if i not in [Link]:
province+=1
dfs(i)
return province

-------------------------------------------

45) 1466. Reorder Routes to Make All Paths Lead to the City Zero

class Solution:
def minReorder(self, n: int, connections: List[List[int]]) -> int:
edges = {(a,b) for a,b in connections}
print('edges',edges)
neighbours = {city:[] for city in range(n)}
print('neighbours',neighbours)
visit = set()
changes = 0

for a,b in connections:


print('a,b',a,b)
neighbours[a].append(b)
neighbours[b].append(a)
print('neighbours updated :',neighbours)
print('visit:',visit)
def dfs(city):
nonlocal edges,neighbours,visit,changes
for neighbour in neighbours[city]:
if neighbour in visit:
continue
if (neighbour,city) not in edges:
changes+=1
[Link](neighbour)
dfs(neighbour)
[Link](0)
print('visit updatded :',visit)
dfs(0)
print('visit updatded after dfs:',visit)
print('changes',changes)
return changes

------------------------------------

46) 399. Evaluate Division

class Solution:
def calcEquation(self, equations: List[List[str]], values: List[float],
queries: List[List[str]]) -> List[float]:
adj = [Link](list)
for i,eq in enumerate(equations):
a,b = eq
adj[a].append([b,values[i]])
adj[b].append([a,1/values[i]])
print('adj',adj)

def bfs(src,target):
if src not in adj or target not in adj:
return -1
q,visit = deque(),set()
[Link]([src,1])
[Link](src)
while q:
n,w = [Link]()
if n==target:
return w
for nei , weight in adj[n]:
if nei not in visit:
[Link]([nei,w*weight])
[Link](nei)
return -1
return [bfs(q[0],q[1]) for q in queries]

--------------------------------------------
47) 1926. Nearest Exit from Entrance in Maze

class Solution:
def nearestExit(self, maze: List[List[str]], entrance: List[int]) -> int:
cells = deque([(entrance[0],entrance[1],0)])
maze[entrance[0]][entrance[1]]="+"
rows,cols = len(maze),len(maze[0])
while cells:
r,c,steps = [Link]()
check = [(r+1,c),(r-1,c),(r,c+1),(r,c-1)]
for i,j in check:
if i>=0 and j>=0 and i<rows and j<cols and maze[i][j]=='.':
if i==0 or j==0 or i==rows-1 or j==cols-1:
return steps+1
[Link]((i,j,steps+1))
maze[i][j]="+"
return -1

---------------------------------------

48) 994. Rotting Oranges

class Solution:
def orangesRotting(self, grid: List[List[int]]) -> int:
q = deque()
time,fresh = 0,0

ROWS,COLS = len(grid),len(grid[0])
for r in range(ROWS):
for c in range(COLS):
if grid[r][c]==1:
fresh+=1
if grid[r][c]==2:
[Link]([r,c])
directions = [[0,1],[0,-1],[1,0],[-1,0]]

while q and fresh>0:


for i in range(len(q)):
r,c = [Link]()
for dr,dc in directions:
row,col = dr+r,dc+c
if (row<0 or row==len(grid) or col<0 or col==len(grid[0]) or
grid[row][col]!=1):
continue
grid[row][col]=2
[Link]([row,col])
fresh-=1
time+=1
return time if fresh==0 else -1

--------------------------------------------

49) 215. Kth Largest Element in an Array

class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
[Link]()
return nums[-k]
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
k = len(nums)-k
def quickselect(l,r):
pivot,p = nums[r],l
for i in range(l,r):
if nums[i]<=pivot:
nums[p],nums[i]=nums[i],nums[p]
p+=1
nums[p],nums[r]=nums[r],nums[p]

if p>k: return quickselect(l,p-1)


elif p<k: return quickselect(p+1,r)
else: return nums[p]
return quickselect(0,len(nums)-1)

class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
heap = []
for num in nums:
[Link](heap,-num)
while k > 0:
res = [Link](heap)
k -=1
return -res

-----------------------------------

50) 2336. Smallest Number in Infinite Set

class SmallestInfiniteSet:

def __init__(self):
[Link] = [True for _ in range(1001)]

def popSmallest(self) -> int:


for x in range(1,1001):
if [Link][x]:
[Link][x]=False
return x

def addBack(self, num: int) -> None:


[Link][num]=True

# Your SmallestInfiniteSet object will be instantiated and called as such:


# obj = SmallestInfiniteSet()
# param_1 = [Link]()
# [Link](num)

----------------------------------------------

import heapq
class SmallestInfiniteSet:

def __init__(self):
[Link] = 1
self.added_numbers = set()
self.min_heap = []

def popSmallest(self) -> int:


if self.min_heap:
smallest = [Link](self.min_heap)
self.added_numbers.remove(smallest)
return smallest
else:
smallest = [Link]
[Link]+=1
return smallest

def addBack(self, num: int) -> None:


if num<[Link] and num not in self.added_numbers:
[Link](self.min_heap,num)
self.added_numbers.add(num)

# Your SmallestInfiniteSet object will be instantiated and called as such:


# obj = SmallestInfiniteSet()
# param_1 = [Link]()
# [Link](num)

------------------------------------------------

51) 2542. Maximum Subsequence Score

class Solution:
def maxScore(self, nums1: List[int], nums2: List[int], k: int) -> int:
pairs = [(n1,n2) for n1,n2 in zip(nums1,nums2)]
pairs = sorted(pairs,key=lambda p:p[1],reverse=True)
minheap = []
n1sum = 0
res = 0

for n1,n2 in pairs:


n1sum +=n1
[Link](minheap,n1)
if len(minheap)>k:
n1pop = [Link](minheap)
n1sum-=n1pop
if len(minheap)==k:
res = max(res,n1sum*n2)

return res

------------------------------------------------

52) 2462. Total Cost to Hire K Workers

class Solution:
def totalCost(self, costs: List[int], k: int, candidates: int) -> int:
heap = []
l_end = -1
r_start = len(costs)
if candidates>=len(costs):
return sum(sorted(costs)[:k])

for i in range(min(candidates,len(costs))):
heappush(heap,(costs[i],i))
l_end = i

for r in range(max(len(costs)-candidates,l_end+1),len(costs)):
heappush(heap,(costs[r],r))
if r<r_start:
r_start=r
res = 0

while k:
cost,index = heappop(heap)
res+=cost
k-=1
if index<=l_end and l_end+1<r_start:
l_end+=1
heappush(heap,(costs[l_end],l_end))
elif index>=r_start and r_start-1>l_end:
r_start-=1
heappush(heap,(costs[r_start],r_start))
return res

-------------------------------------------

53) 374. Guess Number Higher or Lower

# The guess API is already defined for you.


# @param num, your guess
# @return -1 if num is higher than the picked number
# 1 if num is lower than the picked number
# otherwise return 0
# def guess(num: int) -> int:

class Solution:
def guessNumber(self, n: int) -> int:
l,r = 1,n
while True:
m = (l+r)//2
res = guess(m)
if res<0:
r = m-1
elif res>0:
l=m+1
else:
return m

----------------------

54) 2300. Successful Pairs of Spells and Potions

class Solution:
def successfulPairs(self, spells: List[int], potions: List[int], success: int)
-> List[int]:
[Link]()
res = []
for s in spells:
l,r = 0,len(potions)-1
idx = len(potions)
while l<=r:
m = (l+r)//2
if s*potions[m]>=success:
r=m-1
idx=m
else:
l=m+1
[Link](len(potions)-idx)
return res

-------------------------------

55) 162. Find Peak Element

class Solution:
def findPeakElement(self, nums: List[int]) -> int:
l,r = 0,len(nums)-1
while l<=r:
m = l+((r-l)//2)
if m>0 and nums[m]<nums[m-1]:
r = m-1
elif m<len(nums)- 1 and nums[m]<nums[m+1]:
l = m+1
else:
return m

------------------------------

56) 875. Koko Eating Bananas

class Solution:
def minEatingSpeed(self, piles: List[int], h: int) -> int:
l,r = 1,max(piles)

res = r
while l<=r:
k=(l+r)//2
hours=0
for p in piles:
hours+=[Link](p/k)
if hours<=h:
res = min(res,k)
r=k-1
else:
l=k+1
return res

--------------------------------------------

57) 17. Letter Combinations of a Phone Number

class Solution:
def letterCombinations(self, digits: str) -> List[str]:
if not digits:
return []
phone = {
"2":"abc",
'3':'def',
"4":'ghi',
"5": "jkl",
"6": "mno",
"7": "pqrs",
"8": "tuv",
"9": "wxyz"
}

result = []

def backtrack(index:int , curr:str):


if index==len(digits):
[Link](curr)
return
possible_letter = phone[digits[index]]

for letter in possible_letter:


backtrack(index+1,curr+letter)

backtrack(0,'')
return result

-----------------------------------------------

58) 216. Combination Sum III

class Solution:
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
res = []

def backtrack(num,stack,target):
if len(stack)==k:
if target==0:
[Link](stack)
return

for x in range(num+1,10):
if x<=target:
backtrack(x,stack+[x],target-x)
else:
return
backtrack(0,[],n)
return res

----------------------------------

59) 1137. N-th Tribonacci Number

class Solution:
def tribonacci(self, n: int) -> int:
if n<3:
return 0 if n==0 else 1
a,b,c = 0,1,1

for i in range(n-2):
a,b,c = b , c , a+b+c
return c

class Solution:
def tribonacci(self, n: int) -> int:
if n==0:
return 0
if n==1:
return 1
if n==2:
return 1
t0,t1,t2 = 0,1,1
for n in range(3,n+1):
t_next = t0+t1+t2
t0,t1,t2 = t1,t2,t_next
return t2

----------------------------

60) 746. Min Cost Climbing Stairs

class Solution:
def minCostClimbingStairs(self, cost: List[int]) -> int:
[Link](0)
for i in range(len(cost)-3,-1,-1):
cost[i]+=min(cost[i+1],cost[i+2])
return min(cost[0],cost[1])

class Solution:
def minCostClimbingStairs(self, cost: List[int]) -> int:
n = len(cost)
if n==0:
return 0
if n==1:
return cost[0]
dp = [0]*n
dp[0]=cost[0]
dp[1]=cost[1]
for i in range(2,n):
dp[i]=cost[i]+min(dp[i-1],dp[i-2])
return min(dp[-1],dp[-2])

-----------------------------------

61) 198. House Robber

class Solution:
def rob(self, nums: List[int]) -> int:
rob1,rob2 = 0,0

for n in nums:
temp = max(n+rob1,rob2)
rob1 = rob2
rob2 = temp
return rob2
class Solution:
def rob(self, nums: List[int]) -> int:
n = len(nums)

if n==0:
return 0
if n==1:
return nums[0]

dp = [0]*n
dp[0]=nums[0]
dp[1]=max(nums[1],nums[0])

for i in range(2,n):
dp[i]=max(dp[i-1],dp[i-2]+nums[i])
return dp[-1]

----------------------------------

62) 790. Domino and Tromino Tiling

class Solution:
def numTilings(self, n: int) -> int:
MOD = 10**9 + 7

# Base cases
if n == 0:
return 1
if n == 1:
return 1
if n == 2:
return 2

dp = [0] * (n + 1)
dp[0] = 1
dp[1] = 1
dp[2] = 2

# Use the corrected recurrence:


# dp[i] = 2 * dp[i-1] + dp[i-3]
for i in range(3, n + 1):
dp[i]=(2*dp[i-1]+dp[i-3])% MOD

return dp[n]

-------------------------------------------------

63) 62. Unique Paths

class Solution:
def uniquePaths(self, m: int, n: int) -> int:
dp = [[1]*n for _ in range(m)]
print('dp',dp)

for i in range(1,m):
for j in range(1,n):
dp[i][j]=dp[i-1][j]+dp[i][j-1]
return dp[m-1][n-1]

---------------------------------------

64) 1143. Longest Common Subsequence

class Solution:
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]
else:
dp[i][j]=max(dp[i][j+1],dp[i+1][j])
return dp[0][0]

--------------------------------

65) 714. Best Time to Buy and Sell Stock with Transaction Fee

class Solution:
def maxProfit(self, prices: List[int], fee: int) -> int:
cash = 0
hold = -prices[0]

for price in prices[1:]:


new_cash = max(cash,hold+price-fee) #sell
new_hold = max(hold,cash-price) #buy
cash,hold = new_cash ,new_hold
return cash

class Solution:
def maxProfit(self, prices: List[int], fee: int) -> int:
def rec(prices,fee,index=0,holding=False,memo=None):
if memo is None:
memo = {}
if index==len(prices):
return 0
key = (index,holding)
if key in memo:
return memo[key]
if not holding:
# buy
buy = -prices[index]+rec(prices,fee,index+1,True,memo)
# skip buying
dont_buy = rec(prices,fee,index+1,False,memo)
result = max(buy,dont_buy)
else:
# sell
sell = prices[index]-fee+rec(prices,fee,index+1,False,memo)
# hold not sell
hold = rec(prices,fee,index+1,True,memo)
result = max(sell,hold)
memo[key]=result
return result
return rec(prices,fee,0)

-----------------------------------

66) 72. Edit Distance

class Solution:
def minDistance(self, word1: str, word2: str) -> int:
cache = [[float('inf')]*(len(word2)+1) for i in range(len(word1)+1)]

for j in range(len(word2)+1):
cache[len(word1)][j]=len(word2)-j
for i in range(len(word1)+1):
cache[i][len(word2)]=len(word1)-i

for i in range(len(word1)-1,-1,-1):
for j in range(len(word2)-1,-1,-1):
if word1[i]==word2[j]:
cache[i][j]=cache[i+1][j+1]
else:
cache[i][j]=1+min(cache[i][j+1],cache[i+1][j],cache[i+1][j+1])
return cache[0][0]

-----------------------

67) 338. Counting Bits

class Solution:
def countBits(self, n: int) -> List[int]:
dp = [0]*(n+1)
offset = 1
for i in range(1,n+1):
if offset*2==i:
offset = i
dp[i]=1+dp[i-offset]
return dp

class Solution:
def countBits(self, n: int) -> List[int]:
dp = [0]
for i in range(1,n+1):
[Link](dp[i//2]+i%2)
return dp

-----------------------------

68) 136. Single Number

class Solution:
def singleNumber(self, nums: List[int]) -> int:
res = 0
for num in nums:
res = res^num
return res

class Solution:
def singleNumber(self, nums: List[int]) -> int:
res = {}
for num in nums:
if num in res:
res[num]-=1
else:
res[num]=1
print('keys',[Link]())
for key in [Link]():
if res[key]==0:
continue
else:
return key
print('values',[Link])

-----------------------------------

69) 1318. Minimum Flips to Make a OR b Equal to c

class Solution:
def minFlips(self, a: int, b: int, c: int) -> int:
flips = 0
while a>0 or b>0 or c>0:
abit = a&1
bbit = b&1
cbit = c&1
if cbit==1:
if (abit | bbit)!=1:
flips+=1
else:
if abit==1:
flips+=1
if bbit==1:
flips+=1
a >>= 1
b >>= 1
c >>= 1
return flips

----------------------------------

70) 208. Implement Trie (Prefix Tree)

class TrieNode:
def __init__(self):
[Link] = {}
[Link] = False

class Trie:
def __init__(self):
[Link] = TrieNode()
def insert(self, word: str) -> None:
curr = [Link]
for c in word:
if c not in [Link]:
[Link][c]=TrieNode()
curr = [Link][c]
[Link] = True
def search(self, word: str) -> bool:
curr = [Link]
for c in word:
if c not in [Link]:
return False
curr = [Link][c]
return [Link]
def startsWith(self, prefix: str) -> bool:
curr = [Link]
for c in prefix:
if c not in [Link]:
return False
curr = [Link][c]
return True

------------------------------------------

71) 1268. Search Suggestions System

- Binary Search

class Solution:
def suggestedProducts(self, products: List[str], searchWord: str) ->
List[List[str]]:
res = []
[Link]()
l,r = 0,len(products)-1
for i in range(len(searchWord)):
c = searchWord[i]

while l<=r and (i>=len(products[l]) or products[l][i]!=c):


l+=1
while l<=r and (i>=len(products[r]) or products[r][i]!=c):
r-=1
[Link]([])
remain = r-l+1
for j in range(min(3,remain)):
res[-1].append(products[l+j])
return res

- Trie / Prefix Tree

from typing import List

class TrieNode:
def __init__(self):
[Link] = {}
[Link] = [] # Store up to 3 lexicographically sorted suggestions

class Trie:
def __init__(self):
[Link] = TrieNode()

def insert(self, word: str):


curr = [Link]
for c in word:
if c not in [Link]:
[Link][c] = TrieNode()
curr = [Link][c]
# Maintain a sorted list of top 3 words at each node
[Link](word)
[Link]() # Sort lexicographically
if len([Link]) > 3: # Keep only top 3 suggestions
[Link]()

def search(self, prefix: str) -> List[List[str]]:


curr = [Link]
result = []

for c in prefix:
if c in [Link]:
curr = [Link][c]
[Link]([Link])
else:
# If prefix not found, fill remaining results with empty lists
[Link]([] for _ in range(len(prefix) - len(result)))
break

return result

class Solution:
def suggestedProducts(self, products: List[str], searchWord: str) ->
List[List[str]]:
trie = Trie()
[Link]() # Sort lexicographically before inserting

# Insert all products into the Trie


for product in products:
[Link](product)

# Search for suggestions for each prefix of searchWord


return [Link](searchWord)

------------------------------------------------------

72) 435. Non-overlapping Intervals

class Solution:
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
[Link]()
res = 0
prevEnd = intervals[0][1]

for start,end in intervals[1:]:


if start>=prevEnd:
prevEnd = end
else:
res+=1
prevEnd = min(end,prevEnd)
return res

-------------------------------------

73) 452. Minimum Number of Arrows to Burst Balloons

class Solution:
def findMinArrowShots(self, points: List[List[int]]) -> int:
[Link]()
res = len(points)
prev = points[0]
for i in range(1,len(points)):
curr = points[i]
if curr[0]<=prev[1]:
res-=1
prev = [curr[0],min(curr[1],prev[1])]
else:
prev=curr
return res

---------------------------------------------

74) 739. Daily Temperatures

class Solution:
def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
res = [0]*len(temperatures)
stack = [] # [temperature,index]
for i,t in enumerate(temperatures):
while stack and t>stack[-1][0]:
stackT,stackIdx=[Link]()
res[stackIdx]=(i-stackIdx)
[Link]([t,i])
return res

-----------------------------------------

75) 901. Online Stock Span

class StockSpanner:

def __init__(self):
[Link] = [] # (price,span)

def next(self, price: int) -> int:


span = 1
while [Link] and [Link][-1][0]<=price:
span+=[Link][-1][1]
[Link]()
[Link]((price,span))
return span

-----------------------------

# Your StockSpanner object will be instantiated and called as such:


# obj = StockSpanner()
# param_1 = [Link](price)

# Your Trie object will be instantiated and called as such:


# obj = Trie()
# [Link](word)
# param_2 = [Link](word)
# param_3 = [Link](prefix)

- Graphs - BFS , Heap / Priority Queue


- also start from q6 and 2 cells above implement them

genai revise then start type in the code neetcode then continue

help me solve this prpblem,1st help me understand it , help me get intutiuon ,


then illustrate and visualise a example , then code
if posdsible can u draw and show me as well what are trying to convey

-----------------------------------------

You might also like