diff --git a/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/README.md b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/README.md index 6e497626dc5c3..79583bc11b162 100644 --- a/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/README.md +++ b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/README.md @@ -73,8 +73,8 @@ class Solution: def longestSubarray(self, nums: List[int], limit: int) -> int: sl = SortedList() ans = j = 0 - for i, v in enumerate(nums): - sl.add(v) + for i, x in enumerate(nums): + sl.add(x) while sl[-1] - sl[0] > limit: sl.remove(nums[j]) j += 1 @@ -86,15 +86,13 @@ class Solution: class Solution { public int longestSubarray(int[] nums, int limit) { TreeMap tm = new TreeMap<>(); - int ans = 0, j = 0; - for (int i = 0; i < nums.length; ++i) { - tm.put(nums[i], tm.getOrDefault(nums[i], 0) + 1); - while (tm.lastKey() - tm.firstKey() > limit) { - tm.put(nums[j], tm.get(nums[j]) - 1); - if (tm.get(nums[j]) == 0) { + int ans = 0; + for (int i = 0, j = 0; i < nums.length; ++i) { + tm.merge(nums[i], 1, Integer::sum); + for (; tm.lastKey() - tm.firstKey() > limit; ++j) { + if (tm.merge(nums[j], -1, Integer::sum) == 0) { tm.remove(nums[j]); } - ++j; } ans = Math.max(ans, i - j + 1); } @@ -123,27 +121,20 @@ public: ```go func longestSubarray(nums []int, limit int) (ans int) { - tm := treemap.NewWithIntComparator() - j := 0 - for i, v := range nums { - if x, ok := tm.Get(v); ok { - tm.Put(v, x.(int)+1) + merge := func(st *redblacktree.Tree[int, int], x, v int) { + c, _ := st.Get(x) + if c+v == 0 { + st.Remove(x) } else { - tm.Put(v, 1) + st.Put(x, c+v) } - for { - a, _ := tm.Min() - b, _ := tm.Max() - if b.(int)-a.(int) > limit { - if x, _ := tm.Get(nums[j]); x.(int) == 1 { - tm.Remove(nums[j]) - } else { - tm.Put(nums[j], x.(int)-1) - } - j++ - } else { - break - } + } + st := redblacktree.New[int, int]() + j := 0 + for i, x := range nums { + merge(st, x, 1) + for ; st.Right().Key-st.Left().Key > limit; j++ { + merge(st, nums[j], -1) } ans = max(ans, i-j+1) } @@ -158,7 +149,7 @@ function longestSubarray(nums: number[], limit: number): number { let j = 0; for (let i = 0; i < nums.length; ++i) { ts.add(nums[i]); - while (ts.last() - ts.first() > limit) { + while (ts.last()! - ts.first()! > limit) { ts.delete(nums[j++]); } ans = Math.max(ans, i - j + 1); @@ -787,4 +778,369 @@ class TreapMultiSet implements ITreapMultiSet { +### 方法二:二分查找 + 滑动窗口 + +我们注意到,如果一个长度为 $k$ 的子数组满足条件,那么长度 $k' < k$ 的子数组也满足条件,这存在着单调性,因此,我们可以使用二分查找,找到最长的满足条件的子数组。 + +我们定义二分查找的左边界 $l = 0$,右边界 $r = n$。对于每个 $mid = \frac{l + r + 1}{2}$,我们检查是否存在一个长度为 $mid$ 的子数组满足条件。如果存在,我们更新 $l = mid$,否则更新 $r = mid - 1$。那么问题转换为数组中是否存在一个长度为 $mid$ 的子数组满足条件,这其实是求滑动窗口中的最大值和最小值的差值不超过 $limit$。我们可以用两个单调队列分别维护窗口内的最大值和最小值。 + +时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 是数组 $nums$ 的长度。 + + + +```python +class Solution: + def longestSubarray(self, nums: List[int], limit: int) -> int: + def check(k: int) -> bool: + min_q = deque() + max_q = deque() + for i, x in enumerate(nums): + if min_q and i - min_q[0] + 1 > k: + min_q.popleft() + if max_q and i - max_q[0] + 1 > k: + max_q.popleft() + while min_q and nums[min_q[-1]] >= x: + min_q.pop() + while max_q and nums[max_q[-1]] <= x: + max_q.pop() + min_q.append(i) + max_q.append(i) + if i >= k - 1 and nums[max_q[0]] - nums[min_q[0]] <= limit: + return True + return False + + l, r = 1, len(nums) + while l < r: + mid = (l + r + 1) >> 1 + if check(mid): + l = mid + else: + r = mid - 1 + return l +``` + +```java +class Solution { + private int[] nums; + private int limit; + + public int longestSubarray(int[] nums, int limit) { + this.nums = nums; + this.limit = limit; + int l = 1, r = nums.length; + while (l < r) { + int mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; + } else { + r = mid - 1; + } + } + return l; + } + + private boolean check(int k) { + Deque minQ = new ArrayDeque<>(); + Deque maxQ = new ArrayDeque<>(); + for (int i = 0; i < nums.length; ++i) { + if (!minQ.isEmpty() && i - minQ.peekFirst() + 1 > k) { + minQ.pollFirst(); + } + if (!maxQ.isEmpty() && i - maxQ.peekFirst() + 1 > k) { + maxQ.pollFirst(); + } + while (!minQ.isEmpty() && nums[minQ.peekLast()] >= nums[i]) { + minQ.pollLast(); + } + while (!maxQ.isEmpty() && nums[maxQ.peekLast()] <= nums[i]) { + maxQ.pollLast(); + } + minQ.offer(i); + maxQ.offer(i); + if (i >= k - 1 && nums[maxQ.peekFirst()] - nums[minQ.peekFirst()] <= limit) { + return true; + } + } + return false; + } +} +``` + +```cpp +class Solution { +public: + int longestSubarray(vector& nums, int limit) { + auto check = [&](int k) { + deque min_q; + deque max_q; + for (int i = 0; i < nums.size(); ++i) { + if (!min_q.empty() && i - min_q.front() + 1 > k) { + min_q.pop_front(); + } + if (!max_q.empty() && i - max_q.front() + 1 > k) { + max_q.pop_front(); + } + while (!min_q.empty() && nums[min_q.back()] >= nums[i]) { + min_q.pop_back(); + } + while (!max_q.empty() && nums[max_q.back()] <= nums[i]) { + max_q.pop_back(); + } + min_q.push_back(i); + max_q.push_back(i); + if (i >= k - 1 && nums[max_q.front()] - nums[min_q.front()] <= limit) { + return true; + } + } + return false; + }; + int l = 1, r = nums.size(); + while (l < r) { + int mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; + } else { + r = mid - 1; + } + } + return l; + } +}; +``` + +```go +func longestSubarray(nums []int, limit int) int { + l, r := 0, len(nums) + check := func(k int) bool { + minq := Deque{} + maxq := Deque{} + for i, x := range nums { + for !minq.Empty() && i-minq.Front()+1 > k { + minq.PopFront() + } + for !maxq.Empty() && i-maxq.Front()+1 > k { + maxq.PopFront() + } + for !minq.Empty() && nums[minq.Back()] >= x { + minq.PopBack() + } + for !maxq.Empty() && nums[maxq.Back()] <= x { + maxq.PopBack() + } + minq.PushBack(i) + maxq.PushBack(i) + if i >= k-1 && nums[maxq.Front()]-nums[minq.Front()] <= limit { + return true + } + } + return false + } + for l < r { + mid := (l + r + 1) >> 1 + if check(mid) { + l = mid + } else { + r = mid - 1 + } + } + return l +} + +// template +type Deque struct{ l, r []int } + +func (q Deque) Empty() bool { + return len(q.l) == 0 && len(q.r) == 0 +} + +func (q Deque) Size() int { + return len(q.l) + len(q.r) +} + +func (q *Deque) PushFront(v int) { + q.l = append(q.l, v) +} + +func (q *Deque) PushBack(v int) { + q.r = append(q.r, v) +} + +func (q *Deque) PopFront() (v int) { + if len(q.l) > 0 { + q.l, v = q.l[:len(q.l)-1], q.l[len(q.l)-1] + } else { + v, q.r = q.r[0], q.r[1:] + } + return +} + +func (q *Deque) PopBack() (v int) { + if len(q.r) > 0 { + q.r, v = q.r[:len(q.r)-1], q.r[len(q.r)-1] + } else { + v, q.l = q.l[0], q.l[1:] + } + return +} + +func (q Deque) Front() int { + if len(q.l) > 0 { + return q.l[len(q.l)-1] + } + return q.r[0] +} + +func (q Deque) Back() int { + if len(q.r) > 0 { + return q.r[len(q.r)-1] + } + return q.l[0] +} + +func (q Deque) Get(i int) int { + if i < len(q.l) { + return q.l[len(q.l)-1-i] + } + return q.r[i-len(q.l)] +} +``` + +```ts +function longestSubarray(nums: number[], limit: number): number { + const n = nums.length; + let [l, r] = [0, n]; + const check = (k: number): boolean => { + const minq = new Deque(); + const maxq = new Deque(); + for (let i = 0; i < n; ++i) { + while (!minq.isEmpty() && i - minq.frontValue()! + 1 > k) { + minq.popFront(); + } + while (!maxq.isEmpty() && i - maxq.frontValue()! + 1 > k) { + maxq.popFront(); + } + while (!minq.isEmpty() && nums[minq.backValue()!] >= nums[i]) { + minq.popBack(); + } + while (!maxq.isEmpty() && nums[maxq.backValue()!] <= nums[i]) { + maxq.popBack(); + } + minq.pushBack(i); + maxq.pushBack(i); + if (i >= k - 1 && nums[maxq.frontValue()!] - nums[minq.frontValue()!] <= limit) { + return true; + } + } + return false; + }; + while (l < r) { + const mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; + } else { + r = mid - 1; + } + } + return l; +} + +class Node { + value: T; + next: Node | null; + prev: Node | null; + + constructor(value: T) { + this.value = value; + this.next = null; + this.prev = null; + } +} + +class Deque { + private front: Node | null; + private back: Node | null; + private size: number; + + constructor() { + this.front = null; + this.back = null; + this.size = 0; + } + + pushFront(val: T): void { + const newNode = new Node(val); + if (this.isEmpty()) { + this.front = newNode; + this.back = newNode; + } else { + newNode.next = this.front; + this.front!.prev = newNode; + this.front = newNode; + } + this.size++; + } + + pushBack(val: T): void { + const newNode = new Node(val); + if (this.isEmpty()) { + this.front = newNode; + this.back = newNode; + } else { + newNode.prev = this.back; + this.back!.next = newNode; + this.back = newNode; + } + this.size++; + } + + popFront(): T | undefined { + if (this.isEmpty()) { + return undefined; + } + const value = this.front!.value; + this.front = this.front!.next; + if (this.front !== null) { + this.front.prev = null; + } else { + this.back = null; + } + this.size--; + return value; + } + + popBack(): T | undefined { + if (this.isEmpty()) { + return undefined; + } + const value = this.back!.value; + this.back = this.back!.prev; + if (this.back !== null) { + this.back.next = null; + } else { + this.front = null; + } + this.size--; + return value; + } + + frontValue(): T | undefined { + return this.front?.value; + } + + backValue(): T | undefined { + return this.back?.value; + } + + getSize(): number { + return this.size; + } + + isEmpty(): boolean { + return this.size === 0; + } +} +``` + + + diff --git a/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/README_EN.md b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/README_EN.md index 578aa3627ef9d..437bc0298a660 100644 --- a/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/README_EN.md +++ b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/README_EN.md @@ -66,8 +66,8 @@ class Solution: def longestSubarray(self, nums: List[int], limit: int) -> int: sl = SortedList() ans = j = 0 - for i, v in enumerate(nums): - sl.add(v) + for i, x in enumerate(nums): + sl.add(x) while sl[-1] - sl[0] > limit: sl.remove(nums[j]) j += 1 @@ -79,15 +79,13 @@ class Solution: class Solution { public int longestSubarray(int[] nums, int limit) { TreeMap tm = new TreeMap<>(); - int ans = 0, j = 0; - for (int i = 0; i < nums.length; ++i) { - tm.put(nums[i], tm.getOrDefault(nums[i], 0) + 1); - while (tm.lastKey() - tm.firstKey() > limit) { - tm.put(nums[j], tm.get(nums[j]) - 1); - if (tm.get(nums[j]) == 0) { + int ans = 0; + for (int i = 0, j = 0; i < nums.length; ++i) { + tm.merge(nums[i], 1, Integer::sum); + for (; tm.lastKey() - tm.firstKey() > limit; ++j) { + if (tm.merge(nums[j], -1, Integer::sum) == 0) { tm.remove(nums[j]); } - ++j; } ans = Math.max(ans, i - j + 1); } @@ -116,27 +114,20 @@ public: ```go func longestSubarray(nums []int, limit int) (ans int) { - tm := treemap.NewWithIntComparator() - j := 0 - for i, v := range nums { - if x, ok := tm.Get(v); ok { - tm.Put(v, x.(int)+1) + merge := func(st *redblacktree.Tree[int, int], x, v int) { + c, _ := st.Get(x) + if c+v == 0 { + st.Remove(x) } else { - tm.Put(v, 1) + st.Put(x, c+v) } - for { - a, _ := tm.Min() - b, _ := tm.Max() - if b.(int)-a.(int) > limit { - if x, _ := tm.Get(nums[j]); x.(int) == 1 { - tm.Remove(nums[j]) - } else { - tm.Put(nums[j], x.(int)-1) - } - j++ - } else { - break - } + } + st := redblacktree.New[int, int]() + j := 0 + for i, x := range nums { + merge(st, x, 1) + for ; st.Right().Key-st.Left().Key > limit; j++ { + merge(st, nums[j], -1) } ans = max(ans, i-j+1) } @@ -151,7 +142,7 @@ function longestSubarray(nums: number[], limit: number): number { let j = 0; for (let i = 0; i < nums.length; ++i) { ts.add(nums[i]); - while (ts.last() - ts.first() > limit) { + while (ts.last()! - ts.first()! > limit) { ts.delete(nums[j++]); } ans = Math.max(ans, i - j + 1); @@ -780,4 +771,369 @@ class TreapMultiSet implements ITreapMultiSet { +### Solution 2: Binary Search + Sliding Window + +We notice that if a subarray of length $k$ satisfies the condition, then a subarray of length $k' < k$ also satisfies the condition. This shows a monotonicity, therefore, we can use binary search to find the longest subarray that satisfies the condition. + +We define the left boundary of the binary search as $l = 0$, and the right boundary as $r = n$. For each $mid = \frac{l + r + 1}{2}$, we check whether there exists a subarray of length $mid$ that satisfies the condition. If it exists, we update $l = mid$, otherwise we update $r = mid - 1$. The problem is transformed into whether there exists a subarray of length $mid$ in the array that satisfies the condition, which is actually to find the difference between the maximum and minimum values in the sliding window does not exceed $limit$. We can use two monotonic queues to maintain the maximum and minimum values in the window respectively. + +The time complexity is $O(n \times \log n)$, and the space complexity is $O(n)$. Where $n$ is the length of the array $nums$. + + + +```python +class Solution: + def longestSubarray(self, nums: List[int], limit: int) -> int: + def check(k: int) -> bool: + min_q = deque() + max_q = deque() + for i, x in enumerate(nums): + if min_q and i - min_q[0] + 1 > k: + min_q.popleft() + if max_q and i - max_q[0] + 1 > k: + max_q.popleft() + while min_q and nums[min_q[-1]] >= x: + min_q.pop() + while max_q and nums[max_q[-1]] <= x: + max_q.pop() + min_q.append(i) + max_q.append(i) + if i >= k - 1 and nums[max_q[0]] - nums[min_q[0]] <= limit: + return True + return False + + l, r = 1, len(nums) + while l < r: + mid = (l + r + 1) >> 1 + if check(mid): + l = mid + else: + r = mid - 1 + return l +``` + +```java +class Solution { + private int[] nums; + private int limit; + + public int longestSubarray(int[] nums, int limit) { + this.nums = nums; + this.limit = limit; + int l = 1, r = nums.length; + while (l < r) { + int mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; + } else { + r = mid - 1; + } + } + return l; + } + + private boolean check(int k) { + Deque minQ = new ArrayDeque<>(); + Deque maxQ = new ArrayDeque<>(); + for (int i = 0; i < nums.length; ++i) { + if (!minQ.isEmpty() && i - minQ.peekFirst() + 1 > k) { + minQ.pollFirst(); + } + if (!maxQ.isEmpty() && i - maxQ.peekFirst() + 1 > k) { + maxQ.pollFirst(); + } + while (!minQ.isEmpty() && nums[minQ.peekLast()] >= nums[i]) { + minQ.pollLast(); + } + while (!maxQ.isEmpty() && nums[maxQ.peekLast()] <= nums[i]) { + maxQ.pollLast(); + } + minQ.offer(i); + maxQ.offer(i); + if (i >= k - 1 && nums[maxQ.peekFirst()] - nums[minQ.peekFirst()] <= limit) { + return true; + } + } + return false; + } +} +``` + +```cpp +class Solution { +public: + int longestSubarray(vector& nums, int limit) { + auto check = [&](int k) { + deque min_q; + deque max_q; + for (int i = 0; i < nums.size(); ++i) { + if (!min_q.empty() && i - min_q.front() + 1 > k) { + min_q.pop_front(); + } + if (!max_q.empty() && i - max_q.front() + 1 > k) { + max_q.pop_front(); + } + while (!min_q.empty() && nums[min_q.back()] >= nums[i]) { + min_q.pop_back(); + } + while (!max_q.empty() && nums[max_q.back()] <= nums[i]) { + max_q.pop_back(); + } + min_q.push_back(i); + max_q.push_back(i); + if (i >= k - 1 && nums[max_q.front()] - nums[min_q.front()] <= limit) { + return true; + } + } + return false; + }; + int l = 1, r = nums.size(); + while (l < r) { + int mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; + } else { + r = mid - 1; + } + } + return l; + } +}; +``` + +```go +func longestSubarray(nums []int, limit int) int { + l, r := 0, len(nums) + check := func(k int) bool { + minq := Deque{} + maxq := Deque{} + for i, x := range nums { + for !minq.Empty() && i-minq.Front()+1 > k { + minq.PopFront() + } + for !maxq.Empty() && i-maxq.Front()+1 > k { + maxq.PopFront() + } + for !minq.Empty() && nums[minq.Back()] >= x { + minq.PopBack() + } + for !maxq.Empty() && nums[maxq.Back()] <= x { + maxq.PopBack() + } + minq.PushBack(i) + maxq.PushBack(i) + if i >= k-1 && nums[maxq.Front()]-nums[minq.Front()] <= limit { + return true + } + } + return false + } + for l < r { + mid := (l + r + 1) >> 1 + if check(mid) { + l = mid + } else { + r = mid - 1 + } + } + return l +} + +// template +type Deque struct{ l, r []int } + +func (q Deque) Empty() bool { + return len(q.l) == 0 && len(q.r) == 0 +} + +func (q Deque) Size() int { + return len(q.l) + len(q.r) +} + +func (q *Deque) PushFront(v int) { + q.l = append(q.l, v) +} + +func (q *Deque) PushBack(v int) { + q.r = append(q.r, v) +} + +func (q *Deque) PopFront() (v int) { + if len(q.l) > 0 { + q.l, v = q.l[:len(q.l)-1], q.l[len(q.l)-1] + } else { + v, q.r = q.r[0], q.r[1:] + } + return +} + +func (q *Deque) PopBack() (v int) { + if len(q.r) > 0 { + q.r, v = q.r[:len(q.r)-1], q.r[len(q.r)-1] + } else { + v, q.l = q.l[0], q.l[1:] + } + return +} + +func (q Deque) Front() int { + if len(q.l) > 0 { + return q.l[len(q.l)-1] + } + return q.r[0] +} + +func (q Deque) Back() int { + if len(q.r) > 0 { + return q.r[len(q.r)-1] + } + return q.l[0] +} + +func (q Deque) Get(i int) int { + if i < len(q.l) { + return q.l[len(q.l)-1-i] + } + return q.r[i-len(q.l)] +} +``` + +```ts +function longestSubarray(nums: number[], limit: number): number { + const n = nums.length; + let [l, r] = [0, n]; + const check = (k: number): boolean => { + const minq = new Deque(); + const maxq = new Deque(); + for (let i = 0; i < n; ++i) { + while (!minq.isEmpty() && i - minq.frontValue()! + 1 > k) { + minq.popFront(); + } + while (!maxq.isEmpty() && i - maxq.frontValue()! + 1 > k) { + maxq.popFront(); + } + while (!minq.isEmpty() && nums[minq.backValue()!] >= nums[i]) { + minq.popBack(); + } + while (!maxq.isEmpty() && nums[maxq.backValue()!] <= nums[i]) { + maxq.popBack(); + } + minq.pushBack(i); + maxq.pushBack(i); + if (i >= k - 1 && nums[maxq.frontValue()!] - nums[minq.frontValue()!] <= limit) { + return true; + } + } + return false; + }; + while (l < r) { + const mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; + } else { + r = mid - 1; + } + } + return l; +} + +class Node { + value: T; + next: Node | null; + prev: Node | null; + + constructor(value: T) { + this.value = value; + this.next = null; + this.prev = null; + } +} + +class Deque { + private front: Node | null; + private back: Node | null; + private size: number; + + constructor() { + this.front = null; + this.back = null; + this.size = 0; + } + + pushFront(val: T): void { + const newNode = new Node(val); + if (this.isEmpty()) { + this.front = newNode; + this.back = newNode; + } else { + newNode.next = this.front; + this.front!.prev = newNode; + this.front = newNode; + } + this.size++; + } + + pushBack(val: T): void { + const newNode = new Node(val); + if (this.isEmpty()) { + this.front = newNode; + this.back = newNode; + } else { + newNode.prev = this.back; + this.back!.next = newNode; + this.back = newNode; + } + this.size++; + } + + popFront(): T | undefined { + if (this.isEmpty()) { + return undefined; + } + const value = this.front!.value; + this.front = this.front!.next; + if (this.front !== null) { + this.front.prev = null; + } else { + this.back = null; + } + this.size--; + return value; + } + + popBack(): T | undefined { + if (this.isEmpty()) { + return undefined; + } + const value = this.back!.value; + this.back = this.back!.prev; + if (this.back !== null) { + this.back.next = null; + } else { + this.front = null; + } + this.size--; + return value; + } + + frontValue(): T | undefined { + return this.front?.value; + } + + backValue(): T | undefined { + return this.back?.value; + } + + getSize(): number { + return this.size; + } + + isEmpty(): boolean { + return this.size === 0; + } +} +``` + + + diff --git a/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution.go b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution.go index 7837ea2437aa6..5207af04d54d7 100644 --- a/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution.go +++ b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution.go @@ -1,25 +1,18 @@ func longestSubarray(nums []int, limit int) (ans int) { - tm := treemap.NewWithIntComparator() - j := 0 - for i, v := range nums { - if x, ok := tm.Get(v); ok { - tm.Put(v, x.(int)+1) + merge := func(st *redblacktree.Tree[int, int], x, v int) { + c, _ := st.Get(x) + if c+v == 0 { + st.Remove(x) } else { - tm.Put(v, 1) + st.Put(x, c+v) } - for { - a, _ := tm.Min() - b, _ := tm.Max() - if b.(int)-a.(int) > limit { - if x, _ := tm.Get(nums[j]); x.(int) == 1 { - tm.Remove(nums[j]) - } else { - tm.Put(nums[j], x.(int)-1) - } - j++ - } else { - break - } + } + st := redblacktree.New[int, int]() + j := 0 + for i, x := range nums { + merge(st, x, 1) + for ; st.Right().Key-st.Left().Key > limit; j++ { + merge(st, nums[j], -1) } ans = max(ans, i-j+1) } diff --git a/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution.java b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution.java index 2952030bae38a..3c4d6362fc729 100644 --- a/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution.java +++ b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution.java @@ -1,15 +1,13 @@ class Solution { public int longestSubarray(int[] nums, int limit) { TreeMap tm = new TreeMap<>(); - int ans = 0, j = 0; - for (int i = 0; i < nums.length; ++i) { - tm.put(nums[i], tm.getOrDefault(nums[i], 0) + 1); - while (tm.lastKey() - tm.firstKey() > limit) { - tm.put(nums[j], tm.get(nums[j]) - 1); - if (tm.get(nums[j]) == 0) { + int ans = 0; + for (int i = 0, j = 0; i < nums.length; ++i) { + tm.merge(nums[i], 1, Integer::sum); + for (; tm.lastKey() - tm.firstKey() > limit; ++j) { + if (tm.merge(nums[j], -1, Integer::sum) == 0) { tm.remove(nums[j]); } - ++j; } ans = Math.max(ans, i - j + 1); } diff --git a/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution.py b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution.py index b83d72d0bd50e..88444c45aa4c2 100644 --- a/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution.py +++ b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution.py @@ -5,8 +5,8 @@ class Solution: def longestSubarray(self, nums: List[int], limit: int) -> int: sl = SortedList() ans = j = 0 - for i, v in enumerate(nums): - sl.add(v) + for i, x in enumerate(nums): + sl.add(x) while sl[-1] - sl[0] > limit: sl.remove(nums[j]) j += 1 diff --git a/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution.ts b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution.ts index e334426da3ffb..7c56dcb839f79 100644 --- a/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution.ts +++ b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution.ts @@ -4,7 +4,7 @@ function longestSubarray(nums: number[], limit: number): number { let j = 0; for (let i = 0; i < nums.length; ++i) { ts.add(nums[i]); - while (ts.last() - ts.first() > limit) { + while (ts.last()! - ts.first()! > limit) { ts.delete(nums[j++]); } ans = Math.max(ans, i - j + 1); diff --git a/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution2.cpp b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution2.cpp new file mode 100644 index 0000000000000..0e5a554c8c872 --- /dev/null +++ b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution2.cpp @@ -0,0 +1,39 @@ +class Solution { +public: + int longestSubarray(vector& nums, int limit) { + auto check = [&](int k) { + deque min_q; + deque max_q; + for (int i = 0; i < nums.size(); ++i) { + if (!min_q.empty() && i - min_q.front() + 1 > k) { + min_q.pop_front(); + } + if (!max_q.empty() && i - max_q.front() + 1 > k) { + max_q.pop_front(); + } + while (!min_q.empty() && nums[min_q.back()] >= nums[i]) { + min_q.pop_back(); + } + while (!max_q.empty() && nums[max_q.back()] <= nums[i]) { + max_q.pop_back(); + } + min_q.push_back(i); + max_q.push_back(i); + if (i >= k - 1 && nums[max_q.front()] - nums[min_q.front()] <= limit) { + return true; + } + } + return false; + }; + int l = 1, r = nums.size(); + while (l < r) { + int mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; + } else { + r = mid - 1; + } + } + return l; + } +}; \ No newline at end of file diff --git a/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution2.go b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution2.go new file mode 100644 index 0000000000000..b89df38767775 --- /dev/null +++ b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution2.go @@ -0,0 +1,94 @@ +func longestSubarray(nums []int, limit int) int { + l, r := 0, len(nums) + check := func(k int) bool { + minq := Deque{} + maxq := Deque{} + for i, x := range nums { + for !minq.Empty() && i-minq.Front()+1 > k { + minq.PopFront() + } + for !maxq.Empty() && i-maxq.Front()+1 > k { + maxq.PopFront() + } + for !minq.Empty() && nums[minq.Back()] >= x { + minq.PopBack() + } + for !maxq.Empty() && nums[maxq.Back()] <= x { + maxq.PopBack() + } + minq.PushBack(i) + maxq.PushBack(i) + if i >= k-1 && nums[maxq.Front()]-nums[minq.Front()] <= limit { + return true + } + } + return false + } + for l < r { + mid := (l + r + 1) >> 1 + if check(mid) { + l = mid + } else { + r = mid - 1 + } + } + return l +} + +// template +type Deque struct{ l, r []int } + +func (q Deque) Empty() bool { + return len(q.l) == 0 && len(q.r) == 0 +} + +func (q Deque) Size() int { + return len(q.l) + len(q.r) +} + +func (q *Deque) PushFront(v int) { + q.l = append(q.l, v) +} + +func (q *Deque) PushBack(v int) { + q.r = append(q.r, v) +} + +func (q *Deque) PopFront() (v int) { + if len(q.l) > 0 { + q.l, v = q.l[:len(q.l)-1], q.l[len(q.l)-1] + } else { + v, q.r = q.r[0], q.r[1:] + } + return +} + +func (q *Deque) PopBack() (v int) { + if len(q.r) > 0 { + q.r, v = q.r[:len(q.r)-1], q.r[len(q.r)-1] + } else { + v, q.l = q.l[0], q.l[1:] + } + return +} + +func (q Deque) Front() int { + if len(q.l) > 0 { + return q.l[len(q.l)-1] + } + return q.r[0] +} + +func (q Deque) Back() int { + if len(q.r) > 0 { + return q.r[len(q.r)-1] + } + return q.l[0] +} + +func (q Deque) Get(i int) int { + if i < len(q.l) { + return q.l[len(q.l)-1-i] + } + return q.r[i-len(q.l)] +} \ No newline at end of file diff --git a/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution2.java b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution2.java new file mode 100644 index 0000000000000..3b4c3fa3bbaf3 --- /dev/null +++ b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution2.java @@ -0,0 +1,44 @@ +class Solution { + private int[] nums; + private int limit; + + public int longestSubarray(int[] nums, int limit) { + this.nums = nums; + this.limit = limit; + int l = 1, r = nums.length; + while (l < r) { + int mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; + } else { + r = mid - 1; + } + } + return l; + } + + private boolean check(int k) { + Deque minQ = new ArrayDeque<>(); + Deque maxQ = new ArrayDeque<>(); + for (int i = 0; i < nums.length; ++i) { + if (!minQ.isEmpty() && i - minQ.peekFirst() + 1 > k) { + minQ.pollFirst(); + } + if (!maxQ.isEmpty() && i - maxQ.peekFirst() + 1 > k) { + maxQ.pollFirst(); + } + while (!minQ.isEmpty() && nums[minQ.peekLast()] >= nums[i]) { + minQ.pollLast(); + } + while (!maxQ.isEmpty() && nums[maxQ.peekLast()] <= nums[i]) { + maxQ.pollLast(); + } + minQ.offer(i); + maxQ.offer(i); + if (i >= k - 1 && nums[maxQ.peekFirst()] - nums[minQ.peekFirst()] <= limit) { + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution2.py b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution2.py new file mode 100644 index 0000000000000..95e140a96c4cc --- /dev/null +++ b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution2.py @@ -0,0 +1,28 @@ +class Solution: + def longestSubarray(self, nums: List[int], limit: int) -> int: + def check(k: int) -> bool: + min_q = deque() + max_q = deque() + for i, x in enumerate(nums): + if min_q and i - min_q[0] + 1 > k: + min_q.popleft() + if max_q and i - max_q[0] + 1 > k: + max_q.popleft() + while min_q and nums[min_q[-1]] >= x: + min_q.pop() + while max_q and nums[max_q[-1]] <= x: + max_q.pop() + min_q.append(i) + max_q.append(i) + if i >= k - 1 and nums[max_q[0]] - nums[min_q[0]] <= limit: + return True + return False + + l, r = 1, len(nums) + while l < r: + mid = (l + r + 1) >> 1 + if check(mid): + l = mid + else: + r = mid - 1 + return l diff --git a/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution2.ts b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution2.ts new file mode 100644 index 0000000000000..028b29440bbe7 --- /dev/null +++ b/solution/1400-1499/1438.Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit/Solution2.ts @@ -0,0 +1,133 @@ +function longestSubarray(nums: number[], limit: number): number { + const n = nums.length; + let [l, r] = [0, n]; + const check = (k: number): boolean => { + const minq = new Deque(); + const maxq = new Deque(); + for (let i = 0; i < n; ++i) { + while (!minq.isEmpty() && i - minq.frontValue()! + 1 > k) { + minq.popFront(); + } + while (!maxq.isEmpty() && i - maxq.frontValue()! + 1 > k) { + maxq.popFront(); + } + while (!minq.isEmpty() && nums[minq.backValue()!] >= nums[i]) { + minq.popBack(); + } + while (!maxq.isEmpty() && nums[maxq.backValue()!] <= nums[i]) { + maxq.popBack(); + } + minq.pushBack(i); + maxq.pushBack(i); + if (i >= k - 1 && nums[maxq.frontValue()!] - nums[minq.frontValue()!] <= limit) { + return true; + } + } + return false; + }; + while (l < r) { + const mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; + } else { + r = mid - 1; + } + } + return l; +} + +class Node { + value: T; + next: Node | null; + prev: Node | null; + + constructor(value: T) { + this.value = value; + this.next = null; + this.prev = null; + } +} + +class Deque { + private front: Node | null; + private back: Node | null; + private size: number; + + constructor() { + this.front = null; + this.back = null; + this.size = 0; + } + + pushFront(val: T): void { + const newNode = new Node(val); + if (this.isEmpty()) { + this.front = newNode; + this.back = newNode; + } else { + newNode.next = this.front; + this.front!.prev = newNode; + this.front = newNode; + } + this.size++; + } + + pushBack(val: T): void { + const newNode = new Node(val); + if (this.isEmpty()) { + this.front = newNode; + this.back = newNode; + } else { + newNode.prev = this.back; + this.back!.next = newNode; + this.back = newNode; + } + this.size++; + } + + popFront(): T | undefined { + if (this.isEmpty()) { + return undefined; + } + const value = this.front!.value; + this.front = this.front!.next; + if (this.front !== null) { + this.front.prev = null; + } else { + this.back = null; + } + this.size--; + return value; + } + + popBack(): T | undefined { + if (this.isEmpty()) { + return undefined; + } + const value = this.back!.value; + this.back = this.back!.prev; + if (this.back !== null) { + this.back.next = null; + } else { + this.front = null; + } + this.size--; + return value; + } + + frontValue(): T | undefined { + return this.front?.value; + } + + backValue(): T | undefined { + return this.back?.value; + } + + getSize(): number { + return this.size; + } + + isEmpty(): boolean { + return this.size === 0; + } +}