Skip to content

Commit 72c3a1f

Browse files
committed
more detailed
1 parent aa1e4d9 commit 72c3a1f

8 files changed

Lines changed: 425 additions & 4 deletions
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# https://leetcode.com/problems/recover-binary-search-tree/description/
2+
3+
"""
4+
You are given the root of a binary search tree (BST), where the values of exactly two nodes of the tree were swapped by mistake. Recover the tree without changing its structure.
5+
6+
Example 1:
7+
Input: root = [1,3,null,null,2]
8+
Output: [3,1,null,null,2]
9+
Explanation: 3 cannot be a left child of 1 because 3 > 1. Swapping 1 and 3 makes the BST valid.
10+
11+
Example 2:
12+
Input: root = [3,1,4,null,null,2]
13+
Output: [2,1,4,null,null,3]
14+
Explanation: 2 cannot be in the right subtree of 3 because 2 < 3. Swapping 2 and 3 makes the BST valid.
15+
16+
Constraints:
17+
The number of nodes in the tree is in the range [2, 1000].
18+
-231 <= Node.val <= 231 - 1
19+
20+
Follow up: A solution using O(n) space is pretty straight-forward. Could you devise a constant O(1) space solution?
21+
"""
22+
23+
# Definition for a binary tree node.
24+
# class TreeNode:
25+
# def __init__(self, val=0, left=None, right=None):
26+
# self.val = val
27+
# self.left = left
28+
# self.right = right
29+
class Solution:
30+
def recoverTree(self, root: Optional[TreeNode]) -> None:
31+
"""
32+
Do not return anything, modify root in-place instead.
33+
"""
34+
x=y=predecessor=pred=None
35+
36+
while root:
37+
if root.left:
38+
predecessor=root.left
39+
while predecessor.right and predecessor.right!=root:
40+
predecessor=predecessor.right
41+
42+
if predecessor.right is None:
43+
predecessor.right=root
44+
root=root.left
45+
else:
46+
if pred and root.val<pred.val:
47+
y=root
48+
if x is None:
49+
x=pred
50+
pred=root
51+
52+
predecessor.right=None
53+
root=root.right
54+
else:
55+
if pred and root.val<pred.val:
56+
y=root
57+
if x is None:
58+
x=pred
59+
pred=root
60+
root=root.right
61+
62+
x.val,y.val=y.val,x.val
63+
64+
65+
# Complexity Analysis
66+
67+
# Time complexity : O(N) since we visit each node up to two times.
68+
# Space complexity : O(1).

Binary Tree/572. Subtree of Another Tree.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,44 @@ def isSubtree(self, root: Optional[TreeNode], subRoot: Optional[TreeNode]) -> bo
4242

4343
# Naive approach, O(|s| * |t|)
4444

45+
class Solution:
46+
def isSubtree(self, root: Optional[TreeNode], subRoot: Optional[TreeNode]) -> bool:
47+
MOD_1=1000000007
48+
MOD_2=2147483647
49+
50+
def hash_subtree_at_node(node,need_to_add):
51+
if node is None:
52+
return (3,7)
53+
54+
left=hash_subtree_at_node(node.left,need_to_add)
55+
right=hash_subtree_at_node(node.right,need_to_add)
56+
57+
left_1=(left[0]<<5)%MOD_1
58+
right_1=(right[0]<<1)%MOD_1
59+
60+
left_2=(left[1]<<7)%MOD_2
61+
right_2=(right[1]<<1)%MOD_2
62+
63+
hashpair=((left_1+right_1+node.val)%MOD_1,(left_2+right_2+node.val)%MOD_2)
64+
65+
if need_to_add:
66+
memo.add(hashpair)
67+
return hashpair
68+
69+
memo=set()
70+
71+
hash_subtree_at_node(root,True)
72+
73+
s=hash_subtree_at_node(subRoot,False)
74+
return s in memo
75+
76+
'''
77+
Complexity Analysis
78+
Time complexity: O(M+N).
79+
We are traversing the tree rooted at root in O(N) time. We are also traversing the tree rooted at subRoot in O(M) time. For each node, we are doing constant time operations. After traversing, for lookup we are either doing O(1) operations, or O(N) operations. Hence, the overall time complexity is O(N+M).
4580
81+
Space complexity: O(M+N).
82+
We are using memo to store the hash pair of each node in the tree rooted at root. Hence, for this, we need O(N) space.
83+
Moreover, since we are using recursion, the space required for the recursion stack will be O(N) for hashSubtreeAtNode(root, true) and O(M) for hashSubtreeAtNode(subRoot, false).
84+
Hence, overall space complexity is O(M+N).
85+
'''

Heap/1046. Last Stone Weight.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,45 @@ def lastStoneWeight(self, stones: List[int]) -> int:
5050
# In Java though, it's O(N) to create the PriorityQueue.
5151
# We could reduce the space complexity to O(1) by implementing our own iterative heapfiy, if needed.
5252

53+
54+
class Solution:
55+
def lastStoneWeight(self, stones: List[int]) -> int:
56+
max_weight = max(stones)
57+
buckets = [0] * (max_weight + 1)
58+
59+
for weight in stones:
60+
buckets[weight] += 1
61+
62+
biggest_weight = 0
63+
current_weight = max_weight
64+
65+
while current_weight > 0:
66+
if buckets[current_weight] == 0:
67+
current_weight -= 1
68+
elif biggest_weight == 0:
69+
buckets[current_weight] %= 2
70+
if buckets[current_weight] == 1:
71+
biggest_weight = current_weight
72+
current_weight -= 1
73+
else:
74+
buckets[current_weight] -= 1
75+
if biggest_weight - current_weight <= current_weight:
76+
buckets[biggest_weight - current_weight] += 1
77+
biggest_weight = 0
78+
else:
79+
biggest_weight -= current_weight
80+
return biggest_weight
81+
82+
'''
83+
Time complexity : O(N+W).
84+
Putting the N stones of the input array into the bucket array is O(N), because inserting each stone is an O(1) operation.
85+
In the worst case, the main loop iterates through all of the W indexes of the bucket array. Processing each bucket is an O(1) operation. This, therefore, is O(W).
86+
Seeing as we don't know which is larger out of N and W, we get a total of O(N+W).
87+
Technically, this algorithm is pseudo-polynomial, as its time complexity is dependent on the numeric value of the input.
88+
Pseudo-polynomial algorithms are useful when there is no "true" polynomial alternative, but in situations such as this one where we have an O(NlogN) alternative (Approach 3), they are only useful for very specific inputs.
89+
With the small values of W that your code is tested against for this question here on LeetCode, this approach turns out to be faster than Approach 3.
90+
But that does not make it the better approach.
91+
92+
Space complexity : O(W).
93+
We allocated a new array of size W.
94+
'''

Heap/215. Kth Largest Element in an Array.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,39 @@ def findKthLargest(self, nums: List[int], k: int) -> int:
3131
if len(h)>k:
3232
heappop(h)
3333
return h[0]
34-
34+
3535
# Comeplexity:
3636
# Time: O(NlogK)
37-
# Space: O(K)
37+
# Space: O(K)
38+
39+
40+
class Solution:
41+
def findKthLargest(self, nums: List[int], k: int) -> int:
42+
min_value = min(nums)
43+
max_value = max(nums)
44+
count = [0] * (max_value - min_value + 1)
45+
46+
for num in nums:
47+
count[num - min_value] += 1
48+
49+
remain = k
50+
for num in range(len(count) - 1, -1, -1):
51+
remain -= count[num]
52+
if remain <= 0:
53+
return num + min_value
54+
55+
return -1
56+
57+
'''
58+
Complexity Analysis
59+
Given n as the length of nums and m as maxValue - minValue,
60+
61+
Time complexity: O(n+m)
62+
We first find maxValue and minValue, which costs O(n).
63+
Next, we initialize count, which costs O(m).
64+
Next, we populate count, which costs O(n).
65+
Finally, we iterate over the indices of count, which costs up to O(m).
66+
67+
Space complexity: O(m)
68+
We create an array count with size O(m).
69+
'''
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# https://leetcode.com/problems/maximum-twin-sum-of-a-linked-list/description/
2+
3+
"""
4+
In a linked list of size n, where n is even, the ith node (0-indexed) of the linked list is known as the twin of the (n-1-i)th node, if 0 <= i <= (n / 2) - 1.
5+
For example, if n = 4, then node 0 is the twin of node 3, and node 1 is the twin of node 2. These are the only nodes with twins for n = 4.
6+
The twin sum is defined as the sum of a node and its twin.
7+
Given the head of a linked list with even length, return the maximum twin sum of the linked list.
8+
9+
Example 1:
10+
Input: head = [5,4,2,1]
11+
Output: 6
12+
Explanation:
13+
Nodes 0 and 1 are the twins of nodes 3 and 2, respectively. All have twin sum = 6.
14+
There are no other nodes with twins in the linked list.
15+
Thus, the maximum twin sum of the linked list is 6.
16+
17+
Example 2:
18+
Input: head = [4,2,2,3]
19+
Output: 7
20+
Explanation:
21+
The nodes with twins present in this linked list are:
22+
- Node 0 is the twin of node 3 having a twin sum of 4 + 3 = 7.
23+
- Node 1 is the twin of node 2 having a twin sum of 2 + 2 = 4.
24+
Thus, the maximum twin sum of the linked list is max(7, 4) = 7.
25+
26+
Example 3:
27+
Input: head = [1,100000]
28+
Output: 100001
29+
Explanation:
30+
There is only one node with a twin in the linked list having twin sum of 1 + 100000 = 100001.
31+
32+
33+
Constraints:
34+
The number of nodes in the list is an even integer in the range [2, 105].
35+
1 <= Node.val <= 105
36+
"""
37+
38+
# Definition for singly-linked list.
39+
# class ListNode:
40+
# def __init__(self, val=0, next=None):
41+
# self.val = val
42+
# self.next = next
43+
class Solution:
44+
def pairSum(self, head: Optional[ListNode]) -> int:
45+
slow,fast=head,head
46+
maxSum=0
47+
48+
while fast and fast.next:
49+
fast=fast.next.next
50+
slow=slow.next
51+
52+
curr,prev=slow,None
53+
while curr:
54+
curr.next,prev,curr=prev,curr,curr.next
55+
56+
start=head
57+
while prev:
58+
maxSum=max(maxSum,start.val+prev.val)
59+
prev=prev.next
60+
start=start.next
61+
return maxSum
62+
63+
'''
64+
Complexity Analysis
65+
Here, n is the number of nodes in the linked list.
66+
67+
Time complexity: O(n)
68+
69+
It takes O(n) time to iterate over the linked list to find the middle and then reverse the second half of the linked list.
70+
We iterate over the half of the linked list to find the maximum twin sum, which also takes O(n) time.
71+
Space complexity: O(1)
72+
73+
Except for a few pointers that take up constant space, we don't take up any space.
74+
'''

LinkedList/23. Merge k Sorted Lists.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
4646
for i,node in enumerate(lists):
4747
if node:
4848
heappush(h,(node.val,i,node))
49-
49+
5050
dummy=ListNode()
5151
tail=dummy
5252
while h:
@@ -63,3 +63,48 @@ def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
6363
# Time O(Nlogk). Space O(k).
6464
# Produces a single sorted linked list.
6565

66+
67+
# Definition for singly-linked list.
68+
# class ListNode:
69+
# def __init__(self, val=0, next=None):
70+
# self.val = val
71+
# self.next = next
72+
class Solution:
73+
def merge2Lists(self, l1, l2):
74+
head = point = ListNode(0)
75+
while l1 and l2:
76+
if l1.val <= l2.val:
77+
point.next = l1
78+
l1 = l1.next
79+
else:
80+
point.next = l2
81+
l2 = l1
82+
l1 = point.next.next
83+
point = point.next
84+
if not l1:
85+
point.next = l2
86+
else:
87+
point.next = l1
88+
return head.next
89+
90+
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
91+
amount = len(lists)
92+
interval = 1
93+
94+
while interval < amount:
95+
for i in range(0, amount - interval, interval * 2):
96+
lists[i] = self.merge2Lists(lists[i], lists[i + interval])
97+
interval *= 2
98+
return lists[0] if amount > 0 else None
99+
100+
"""
101+
Complexity Analysis
102+
103+
Time complexity : O(Nlogk) where k is the number of linked lists.
104+
105+
We can merge two sorted linked list in O(n) time where n is the total number of nodes in two lists.
106+
Sum up the merge process and we can get: O(∑i=1log2kN)=O(Nlogk)
107+
108+
Space complexity : O(1)
109+
We can merge two sorted linked lists in O(1) space.
110+
"""

0 commit comments

Comments
 (0)