Longest Subsequence With Decreasing Adjacent Difference - Complete Solution Guide
Longest Subsequence With Decreasing Adjacent Difference is LeetCode problem 3409, a Medium level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.
Problem Statement
You are given an array of integers nums . Your task is to find the length of the longest subsequence seq of nums , such that the absolute differences between consecutive elements form a non-increasing sequence of integers. In other words, for a subsequence seq 0 , seq 1 , seq 2 , ..., seq m of nums , |seq 1 - seq 0 | >= |seq 2 - seq 1 | >= ... >= |seq m - seq m - 1 | . Return the length of such a subsequence. Example 1: Input: nums = [16,6,3] Output: 3 Explanation: The longest subsequence is [16
Detailed Explanation
The problem asks us to find the length of the longest subsequence of a given array `nums` such that the absolute differences between consecutive elements in the subsequence form a non-increasing sequence. A subsequence is formed by taking elements from the original array in order, but not necessarily consecutively. The absolute difference between two numbers is the non-negative difference between them. A non-increasing sequence means the numbers are decreasing or staying the same. For example, if nums = [10, 20, 10, 19, 10, 20], one possible subsequence is [10, 20, 10, 19, 10]. The absolute differences between consecutive elements would be |20-10| = 10, |10-20| = 10, |19-10| = 9, |10-19| = 9 which forms the non-increasing sequence [10, 10, 9, 9]. The constraints are that the array length is between 2 and 10000 and that each number is between 1 and 300.
Solution Approach
The provided solutions use dynamic programming to find the length of the longest subsequence. The core idea is to maintain a DP table `dp[val][diff]` that stores the length of the longest subsequence ending with value `val` and last absolute difference `diff`. Additionally, it maintains a `suffix_max_dp` table to store the maximum DP values for each value `val`, indexed by difference. The `max_len_at_val` array stores the maximum subsequence length ending with a particular value regardless of what the last absolute difference was. The solution iterates through each number in `nums`, building the DP table as it goes.
Step-by-Step Algorithm
- Step 1: Initialize DP tables: `dp[V_max + 1][D_max + 1]`, `suffix_max_dp[V_max + 1][D_max + 1]`, and `max_len_at_val[V_max + 1]`. Initialize `ans` to 1 (since the minimum subsequence length is 1).
- Step 2: Iterate through each number `num` in the input `nums` array. Let `current_val = num`.
- Step 3: Create a `candidate_dp_row` to temporarily store the potential new lengths of the subsequence ending at `current_val`. This prevents changes to `dp` from affecting calculations in the current iteration.
- Step 4: Iterate through all possible previous values `prev_val` from 1 to `V_max`. If there exists a subsequence ending with `prev_val` (indicated by `max_len_at_val[prev_val] > 0`), calculate the absolute difference `d = abs(current_val - prev_val)`.
- Step 5: Find the maximum subsequence length ending at `prev_val` with the difference greater or equal to `d` from `suffix_max_dp[prev_val][d]`. Let `len_to_extend = suffix_max_dp[prev_val][d]`.
- Step 6: Calculate the new potential subsequence length: `new_len = 1 + max(1, len_to_extend)`. The `max(1, len_to_extend)` is necessary because `len_to_extend` might be 0, and we still need to add the current value to extend the subsequence.
- Step 7: Update `candidate_dp_row[d]` if `new_len` is greater.
- Step 8: After iterating through all possible `prev_val`s, update the `dp[current_val][d]` table with the values from the `candidate_dp_row`. Maintain a flag `updated_dp_row` to track if the current DP row has been updated. Update the answer if a longer subsequence is found.
- Step 9: If `updated_dp_row` is true, update the `suffix_max_dp[current_val]` table by taking the suffix maximum of the `dp[current_val]` row. The suffix max is needed because the subsequent difference `d` must be less than or equal to the previous difference. Starting from `d=D_max` copy the value from the main `dp` table. Iterate backwards over `d`, taking the max of the current value from `dp` and the suffix max for `d+1`.
- Step 10: Update the length of the longest subsequence ending at `current_val` in `max_len_at_val`.
- Step 11: After iterating through all numbers in `nums`, return `ans`.
Key Insights
- Insight 1: Dynamic programming is suitable to solve this problem since the optimal solution for a larger sequence can be built from optimal solutions of smaller subsequences.
- Insight 2: The key to forming the dynamic programming state is to consider both the last value added to the subsequence and the last absolute difference calculated. This allows us to verify the non-increasing condition.
- Insight 3: The relatively small constraint on num[i] (1 <= num[i] <= 300) allows us to use the value of the numbers and differences as indices in our DP tables. This greatly simplifies the implementation.
Complexity Analysis
Time Complexity: O(n*V)
Space Complexity: O(V*D)
Topics
This problem involves: Array, Dynamic Programming.
Companies
Asked at: Juspay.