Skip to content

Commit 855ff71

Browse files
committed
updated
1 parent 61215cf commit 855ff71

4 files changed

Lines changed: 354 additions & 0 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ Useful utility snippets:
143143
- Set kth bit: `num |= (1 << k)`.
144144
- Unset kth bit: `num &= ~(1 << k)`.
145145
- Toggle kth bit: `num ^= (1 << k)`.
146+
- Binary string to int: `int(s, 2)`.
147+
- Int to binary string: `bin(num)[2:]`.
146148
- Power of two check: `(num & (num - 1)) == 0` or `(num & -num) == num`.
147149
- Swap without temp: `a ^= b; b ^= a; a ^= b`.
148150
- Compare floating values with tolerance: `abs(x - y) <= 1e-7`.
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
# https://leetcode.com/problems/longest-balanced-subarray-ii/description/
2+
3+
'''
4+
You are given an integer array nums.
5+
A subarray is called balanced if the number of distinct even numbers in the subarray is equal to the number of distinct odd numbers.
6+
Return the length of the longest balanced subarray.
7+
8+
Example 1:
9+
Input: nums = [2,5,4,3]
10+
Output: 4
11+
Explanation:
12+
The longest balanced subarray is [2, 5, 4, 3].
13+
It has 2 distinct even numbers [2, 4] and 2 distinct odd numbers [5, 3]. Thus, the answer is 4.
14+
Example 2:
15+
Input: nums = [3,2,2,5,4]
16+
Output: 5
17+
Explanation:
18+
The longest balanced subarray is [3, 2, 2, 5, 4].
19+
It has 2 distinct even numbers [2, 4] and 2 distinct odd numbers [3, 5]. Thus, the answer is 5.
20+
Example 3:
21+
Input: nums = [1,2,3,2]
22+
Output: 3
23+
Explanation:
24+
25+
The longest balanced subarray is [2, 3, 2].
26+
It has 1 distinct even number [2] and 1 distinct odd number [3]. Thus, the answer is 3.
27+
28+
Constraints:
29+
1 <= nums.length <= 105
30+
1 <= nums[i] <= 105
31+
32+
Prefix Sum + Segment Tree
33+
'''
34+
35+
class LazyTag:
36+
def __init__(self):
37+
self.to_add=0
38+
39+
def add(self,other):
40+
self.to_add+=other.to_add
41+
return self
42+
43+
def has_tag(self):
44+
return self.to_add!=0
45+
46+
def clear(self):
47+
self.to_add=0
48+
49+
class SegmentTreeNode:
50+
def __init__(self):
51+
self.min_value=0
52+
self.max_value=0
53+
self.lazy_tag=LazyTag()
54+
55+
56+
class SegmentTree:
57+
def __init__(self,data):
58+
self.n=len(data)
59+
self.tree=[SegmentTreeNode() for _ in range(self.n*4+1)]
60+
self._build(data,1,self.n,1)
61+
62+
def add(self,l,r,val):
63+
tag=LazyTag()
64+
tag.to_add=val
65+
self._update(l,r,tag,1,self.n,1)
66+
67+
def find_last(self,start,val):
68+
if start>self.n:
69+
return -1
70+
return self._find(start,self.n,val,1,self.n,1)
71+
72+
def _apply_tag(self,i,tag):
73+
self.tree[i].min_value+=tag.to_add
74+
self.tree[i].max_value+=tag.to_add
75+
self.tree[i].lazy_tag.add(tag)
76+
77+
def _pushdown(self,i):
78+
if self.tree[i].lazy_tag.has_tag():
79+
tag=LazyTag()
80+
tag.to_add=self.tree[i].lazy_tag.to_add
81+
self._apply_tag(i<<1,tag)
82+
self._apply_tag((i<<1)|1,tag)
83+
self.tree[i].lazy_tag.clear()
84+
def _pushup(self,i):
85+
self.tree[i].min_value=min(
86+
self.tree[i<<1].min_value,self.tree[(i<<1)|1].min_value
87+
)
88+
self.tree[i].max_value=max(self.tree[i<<1].max_value,self.tree[(i<<1)|1].max_value)
89+
90+
def _build(self,data,l,r,i):
91+
if l==r:
92+
self.tree[i].min_value=data[l-1]
93+
self.tree[i].max_value=data[l-1]
94+
return
95+
mid=l+((r-l)>>1)
96+
self._build(data,l,mid,i<<1)
97+
self._build(data,mid+1,r,(i<<1)|1)
98+
self._pushup(i)
99+
100+
def _update(self,target_l,target_r,tag,l,r,i):
101+
if target_l<=l and r<=target_r:
102+
self._apply_tag(i,tag)
103+
return
104+
self._pushdown(i)
105+
mid=l+((r-l)>>1)
106+
if target_l<=mid:
107+
self._update(target_l,target_r,tag,l,mid,i<<1)
108+
if target_r>mid:
109+
self._update(target_l,target_r,tag,mid+1,r,(i<<1)|1)
110+
self._pushup(i)
111+
112+
def _find(self,target_l,target_r,val,l,r,i):
113+
if self.tree[i].min_value>val or self.tree[i].max_value<val:
114+
return -1
115+
if l==r:
116+
return l
117+
self._pushdown(i)
118+
mid=l+((r-l)>>1)
119+
if target_r>=mid+1:
120+
res=self._find(target_l,target_r,val,mid+1,r,(i<<1)|1)
121+
if res!=-1:
122+
return res
123+
if l<=target_r and mid>=target_l:
124+
return self._find(target_l,target_r,val,l,mid,i<<1)
125+
return -1
126+
127+
128+
class Solution:
129+
def longestBalanced(self, nums: List[int]) -> int:
130+
occurrences=defaultdict(deque)
131+
132+
def sgn(x):
133+
return 1 if x%2==0 else -1
134+
135+
length=0
136+
prefix_sum=[0]*len(nums)
137+
prefix_sum[0]=sgn(nums[0])
138+
occurrences[nums[0]].append(1)
139+
140+
for i in range(1,len(nums)):
141+
prefix_sum[i]=prefix_sum[i-1]
142+
occ=occurrences[nums[i]]
143+
if not occ:
144+
prefix_sum[i]+=sgn(nums[i])
145+
occ.append(i+1)
146+
147+
seg=SegmentTree(prefix_sum)
148+
for i in range(len(nums)):
149+
length=max(length,seg.find_last(i+length,0)-i)
150+
next_pos=len(nums)+1
151+
occurrences[nums[i]].popleft()
152+
if occurrences[nums[i]]:
153+
next_pos=occurrences[nums[i]][0]
154+
seg.add(i+1,next_pos-1,-sgn(nums[i]))
155+
return length
156+
157+
158+
159+
# Complexity Analysis
160+
# Let n be the length of nums.
161+
# Time complexity: O(nlogn).
162+
# Computing prefix sums and maintaining element positions require O(nlogn). Building the segment tree takes O(nlogn). Each iteration performs a constant number of segment tree operations and map accesses, each taking O(logn). Therefore, the total time complexity is O(nlogn).
163+
164+
# Time complexity: O(n).
165+
# The segment tree, prefix sum array, and auxiliary data structures together require O(n) space.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# https://leetcode.com/problems/minimum-absolute-difference/description/
2+
3+
'''
4+
Given an array of distinct integers arr, find all pairs of elements with the minimum absolute difference of any two elements.
5+
Return a list of pairs in ascending order(with respect to pairs), each pair [a, b] follows
6+
a, b are from arr
7+
a < b
8+
b - a equals to the minimum absolute difference of any two elements in arr
9+
10+
Example 1:
11+
Input: arr = [4,2,1,3]
12+
Output: [[1,2],[2,3],[3,4]]
13+
Explanation: The minimum absolute difference is 1. List all pairs with difference equal to 1 in ascending order.
14+
Example 2:
15+
Input: arr = [1,3,6,10,15]
16+
Output: [[1,3]]
17+
Example 3:
18+
Input: arr = [3,8,-10,23,19,-4,-14,27]
19+
Output: [[-14,-10],[19,23],[23,27]]
20+
21+
Constraints:
22+
2 <= arr.length <= 105
23+
-106 <= arr[i] <= 106
24+
'''
25+
26+
27+
class Solution:
28+
def minimumAbsDifference(self, nums: List[int]) -> List[List[int]]:
29+
nums.sort()
30+
31+
min_difference=math.inf
32+
ans=[]
33+
34+
for i in range(len(nums)-1):
35+
diff=abs(nums[i+1]-nums[i])
36+
if diff<min_difference:
37+
min_difference=diff
38+
ans=[[nums[i],nums[i+1]]]
39+
elif diff==min_difference:
40+
ans.append([nums[i],nums[i+1]])
41+
return ans
42+
43+
# Complexity Analysis
44+
45+
# Let n be the length of the array arr.
46+
# Time complexity: O(n⋅log(n))
47+
# First, we sort arr using comparision sorting, which takes O(n⋅log(n)).
48+
# We then traverse the array, which takes O(n) time.
49+
# To sum up, the overall time complexity is O(n⋅log(n)).
50+
51+
# Space complexity: O(n).
52+
53+
54+
# Counting Sort
55+
class Solution:
56+
def minimumAbsDifference(self, nums: List[int]) -> List[List[int]]:
57+
min_element=min(nums)
58+
max_element=max(nums)
59+
shift=-min_element
60+
line=[0]*(max_element-min_element+1)
61+
min_diff=max_element-min_element
62+
prev=0
63+
ans=[]
64+
65+
for num in nums:
66+
line[num+shift]=1
67+
68+
for curr in range(1,max_element+shift+1):
69+
if line[curr]==0:
70+
continue
71+
current_diff=curr-prev
72+
if current_diff<min_diff:
73+
min_diff=current_diff
74+
ans=[[prev-shift,curr-shift]]
75+
elif current_diff==min_diff:
76+
ans.append([prev-shift,curr-shift])
77+
prev=curr
78+
return ans
79+
80+
# Complexity Analysis
81+
82+
# Let n be the size of the input array arr, and m be the range of values in arr.
83+
# Time complexity: O(m+n)
84+
# We initialize an auxiliary array of all zeros, which takes O(m) time.
85+
86+
87+
# Space complexity: O(m+n)
88+
# We used an auxiliary array line of size O(m).
89+
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# https://leetcode.com/problems/design-hit-counter/description/
2+
3+
'''
4+
Design a hit counter which counts the number of hits received in the past 5 minutes (i.e., the past 300 seconds).
5+
Your system should accept a timestamp parameter (in seconds granularity), and you may assume that calls are being made to the system in chronological order (i.e., timestamp is monotonically increasing). Several hits may arrive roughly at the same time.
6+
Implement the HitCounter class:
7+
HitCounter() Initializes the object of the hit counter system.
8+
void hit(int timestamp) Records a hit that happened at timestamp (in seconds). Several hits may happen at the same timestamp.
9+
int getHits(int timestamp) Returns the number of hits in the past 5 minutes from timestamp (i.e., the past 300 seconds).
10+
11+
Example 1:
12+
Input
13+
["HitCounter", "hit", "hit", "hit", "getHits", "hit", "getHits", "getHits"]
14+
[[], [1], [2], [3], [4], [300], [300], [301]]
15+
Output
16+
[null, null, null, null, 3, null, 4, 3]
17+
18+
Explanation
19+
HitCounter hitCounter = new HitCounter();
20+
hitCounter.hit(1); // hit at timestamp 1.
21+
hitCounter.hit(2); // hit at timestamp 2.
22+
hitCounter.hit(3); // hit at timestamp 3.
23+
hitCounter.getHits(4); // get hits at timestamp 4, return 3.
24+
hitCounter.hit(300); // hit at timestamp 300.
25+
hitCounter.getHits(300); // get hits at timestamp 300, return 4.
26+
hitCounter.getHits(301); // get hits at timestamp 301, return 3.
27+
28+
Constraints:
29+
1 <= timestamp <= 2 * 109
30+
All the calls are being made to the system in chronological order (i.e., timestamp is monotonically increasing).
31+
At most 300 calls will be made to hit and getHits.
32+
33+
Follow up: What if the number of hits per second could be huge? Does your design scale?
34+
'''
35+
36+
37+
38+
class HitCounter:
39+
40+
def __init__(self):
41+
self.timestamp_hits=deque()
42+
43+
def hit(self, timestamp: int) -> None:
44+
self.timestamp_hits.append(timestamp)
45+
46+
47+
def getHits(self, timestamp: int) -> int:
48+
while self.timestamp_hits and self.timestamp_hits[0]<=timestamp-300:
49+
self.timestamp_hits.popleft()
50+
return len(self.timestamp_hits)
51+
52+
# with bounded memory, amortized O(1) operations, and precise window semantics:
53+
54+
55+
# Space Efficiency:
56+
# Deque size ≤ hits in last 300 seconds → O(1) bounded space (e.g., max 300 hits if 1/sec)
57+
# Time Efficiency:
58+
# Each hit is added once and removed once → amortized O(1) per operation
59+
# Correctness:
60+
# Window = (timestamp - 300, timestamp] → hits at timestamp-300 are expired (excluded), so condition <= timestamp-300 is precise
61+
# Handles Duplicates:
62+
# Multiple hits at same timestamp? All expired together when window passes
63+
64+
# Scenario Steps Result Why Correct
65+
# Duplicate timestamps
66+
# hit(1)×3 getHits(300) → keeps all (1 > 0)
67+
# getHits(301) → removes all (1 ≤ 1) 3 → 0 Window = (timestamp-300, timestamp]
68+
# At 301: (1, 301] excludes timestamp=1
69+
# Boundary precision
70+
# hit(1), hit(300), hit(301) getHits(301):
71+
# - Remove 1 (1 ≤ 1)
72+
# - Keep 300, 301 2 Window (1, 301] includes 300/301 ✅
73+
# Excludes 1 ✅
74+
# Burst traffic
75+
# 10,000 hits @ t=1 getHits(301):
76+
# - Pops all 10k hits in one pass
77+
# - Deque becomes empty 0 Memory freed immediately ✅
78+
# No leak even after massive burst
79+
# Stale hits + new hits
80+
# hit(1), hit(2), hit(400) getHits(400):
81+
# - Remove 1,2 (≤100)
82+
# - Keep 400 1 Only hits in (100, 400] counted ✅
83+
# Back-to-back queries
84+
# hit(1), getHits(100), getHits(400) First call: keeps 1 (1 > -200)
85+
# Second call: removes 1 (1 ≤ 100) 1 → 0 State persists correctly between calls ✅
86+
# No hits getHits(100) 0 Empty deque handled safely ✅
87+
# 💡 Why This Scales
88+
# Metric Behavior Real-World Impact
89+
# Memory Bounded by hits in last 300s Handles 1M hits/sec → deque holds ≤ 300M entries (manageable)
90+
# Time per getHits Amortized O(1) Each hit pushed/popped once → total work = O(total hits)
91+
# Timestamp order Relies on strictly increasing timestamps (per problem) No sorting needed → optimal for streaming data
92+
# Window semantics (timestamp-300, timestamp] Matches problem spec: hits at timestamp-300 are excluded
93+
# 🌐 Real-World Context
94+
# This is the exact pattern used in:
95+
96+
# Rate limiters (API gateways)
97+
# Sliding window analytics (Redis ZREMRANGEBYSCORE)
98+
# Network traffic monitors

0 commit comments

Comments
 (0)