LeetCode Entry

1438. Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit

23.06.2024 medium 2024 kotlin rust

Longest subarray with abs(a[i] - a[j]) <= limit window queue

1438. Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit medium blog post substack youtube 2024-06-23_07-19_1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/648

Problem TLDR

Longest subarray with abs(a[i] - a[j]) <= limit #medium #sliding_window #monotonic_queue

Intuition

Let’s observe how we can do this in a single iteration:


    //      0 1 2 3
    //      8 2 4 7    limit=4
    // 0    i
    //      j       8
    // 1      i     8 2    or 2
    // 2        i   8 2 4  8-2=6>4 -> move j
    //        j     2 4
    // 3          i 2 4 7  7-2=5>4 -> move j
    //          j   4 7

We should keep the window j..i and maintain maximums and minimums.

To find next maximum after current is dropped we can use Monotonic Queue technique: make it always decreasing, like 5 4 3 2 1. If any new value is bigger then the tail, for example add 4, it will be the next maximum and the tail 3 2 1 becomes irrelevant: 5 4 3 2 1 + 4 -> 5 4 4.

(Another solution would be to just use two heaps, one for maxiums, another for minimums.)

Approach

  • iterators saves some lines: maxOf, iter().max()
  • notice unwrap_or(&n) trick in Rust

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(n)\)

Code


    fun longestSubarray(nums: IntArray, limit: Int): Int {
        val mins = ArrayDeque<Int>(); val maxs = ArrayDeque<Int>()
        var j = 0
        return nums.withIndex().maxOf { (i, n) ->
            while (mins.size > 0 && mins.last() > n) mins.removeLast()
            while (maxs.size > 0 && maxs.last() < n) maxs.removeLast()
            mins += n; maxs += n
            if (maxs.first() - mins.first() > limit) {
                if (nums[j] == maxs.first()) maxs.removeFirst()
                if (nums[j++] == mins.first()) mins.removeFirst()
            }
            i - j + 1
        }
    }


    pub fn longest_subarray(nums: Vec<i32>, limit: i32) -> i32 {
        let (mut mins, mut maxs, mut j) = (VecDeque::new(), VecDeque::new(), 0);
        nums.iter().enumerate().map(|(i, &n)| {
            while *mins.back().unwrap_or(&n) > n { mins.pop_back(); }
            while *maxs.back().unwrap_or(&n) < n { maxs.pop_back(); }
            mins.push_back(n); maxs.push_back(n);
            if maxs.front().unwrap() - mins.front().unwrap() > limit {
                if nums[j] == *mins.front().unwrap() { mins.pop_front(); }
                if nums[j] == *maxs.front().unwrap() { maxs.pop_front(); }
                j += 1
            }
            (i - j + 1) as i32
        }).max().unwrap()
    }