Longest Increasing Subsequence Pattern

Problems Following Longest Increasing Subsequence Pattern

1. Longest Increasing Subsequence

Problem Statement:

Given a number sequence, find the length of its Longest Incresing Subsequence (LIS).

In an increasing subsequence, all the elements are in increasing order (from lowest to highest).

====== Examples ======
Input: {4, 2, 3, 6, 10, 1, 12}
Output: 5
Explanation: The LIS is {2, 3, 6, 10, 12}

Input: {-4, 10, 3, 7, 15}
Output: 4
Explanation The LIS is {-4, 3, 7, 15}


Brute-Force : Recursive Solution

Code:

def find_longest_incresing_subsequence_recursion(seq):
    return find_longest_incresing_subsequence_recursion_util(seq, 0, -1)


def find_longest_incresing_subsequence_recursion_util(seq, current, prev):
    if (current == len(seq)):
        return 0

    current_included_count = 0
    if (prev == -1 or seq[current] >= seq[prev]):
        current_included_count = 1 + find_longest_incresing_subsequence_recursion_util(seq, current + 1, current)

    current_excluded_count = find_longest_incresing_subsequence_recursion_util(seq, current + 1, prev)

    return max(current_included_count, current_excluded_count)


print("Recursive Method :")
print(find_longest_incresing_subsequence_recursion([4, 2, 3, 6, 10, 1, 12]))
print(find_longest_incresing_subsequence_recursion([-4, 10, 3, 7, 15]))

Output:

Recursive Method :
5
4

Complexity:


DP : Recursion + Memoization (Top-Down) Solution

Code:

def find_longest_incresing_subsequence_dp_meomization(seq):
    n = len(seq)
    memory = [[0]*(n+1) for _ in range(n)]
    return find_longest_incresing_subsequence_dp_meomization_util(seq, 0, -1, memory)


def find_longest_incresing_subsequence_dp_meomization_util(seq, current, prev, memory):
    if (current == len(seq)):
        return 0

    if (memory[current][prev + 1]):
        return memory[current][prev + 1]

    current_included_count = 0
    if (prev == -1 or seq[current] >= seq[prev]):
        current_included_count = 1 + find_longest_incresing_subsequence_dp_meomization_util(seq, current + 1, current, memory)

    current_excluded_count = find_longest_incresing_subsequence_dp_meomization_util(seq, current + 1, prev, memory)
    memory[current][prev + 1] = max(current_included_count, current_excluded_count)

    return memory[current][prev + 1]


print("\nDP -> Recursion + Memoization Method :")
print(find_longest_incresing_subsequence_dp_meomization([4, 2, 3, 6, 10, 1, 12]))
print(find_longest_incresing_subsequence_dp_meomization([-4, 10, 3, 7, 15]))

Output:

DP -> Recursion + Memoization Method :
5
4

Complexity:


DP : Iteration + Tabulation (Bottom-Up) Solution

Recursive Formula:

if num[i] > num[j] => dp[i] = dp[j] + 1 if there is no bigger LIS for i

Tabulation:

Final Table:

Code:

def find_longest_incresing_subsequence_dp_tabulation(nums):
    n = len(nums)
    table = [1] * n

    for i in range(1, n):
        for j in range(i):
            if (nums[i] > nums[j]):
                table[i] = max(table[i], table[j] + 1)

    return table[i]


print("\nDP -> Iteration + Tabulation Method :")
print(find_longest_incresing_subsequence_dp_tabulation([4, 2, 3, 6, 10, 1, 12]))
print(find_longest_incresing_subsequence_dp_tabulation([-4, 10, 3, 7, 15]))

Output:

DP -> Iteration + Tabulation Method :
5
4

Complexity:



2. Maximum Sum Increasing Subsequence

Problem Statement:

Given a number sequence, find the increasing subsequence with the higest sum.

====== Examples ======
Input: {4, 1, 2, 6, 10, 1, 12}
Output: 32
Explanation: The increasing subsequence is {4, 6, 10, 12}
Please note the difference, as the LIS is {1, 2, 6, 10, 12} with sum 31

Input: {-4, 10, 3, 7, 15}
Output: 25
Explanantion: The increasing subsequence are {10, 15} and {3, 7, 15}
Again the LIS is {-4, 3, 7, 15} with sum 21


Solution Approach:


DP : Iteration + Tabulation (Bottom-Up) Solution

Recursive Formula:

if num[i] > num[j] => dp[i] = dp[j] + 1 if there is no bigger MSIS for i

Tabulation:

Final Table:

Code:

def find_max_sum_incresing_subsequence_dp_tabulation(nums):
    n = len(nums)
    table = [num for num in nums]

    for i in range(1, n):
        for j in range(i):
            if (nums[i] > nums[j]):
                table[i] = max(table[i], table[j] + nums[i])

    return table[i]


print("DP -> Iteration + Tabulation Method :")
print(find_max_sum_incresing_subsequence_dp_tabulation([4, 1, 2, 6, 10, 1, 12]))
print(find_max_sum_incresing_subsequence_dp_tabulation([-4, 10, 3, 7, 15]))

Output:

DP -> Iteration + Tabulation Method :
32
25

Complexity:



3. Minimum Deletions to Make a Sequence Sorted

Problem Statement:

Given a number sequence, find the minimum number of elements that should be the deleted to make remaining sequence sorted.

====== Examples ======
Input: {4, 2, 3, 6, 10, 1, 12}
Output: 2
Explanation: We need to delete {4,1} to make remaining sequence {2, 3, 6, 10, 12} sorted

Input: {-4, 10, 3, 7, 15}
Output: 1
Explanation: We need to delete {10} to make remaining sequence {-4, 3, 7, 15} sorted

Input: {3, 2, 1, 0}
Output: 3
Explanation: Since sequence are in reverse order, need to delete all except one.


Solution Approach:


DP : Iteration + Tabulation (Bottom-Up) Solution

Code:

def min_deletions_required_to_sort_sequence_dp_tabulation(nums):
    n = len(nums)
    table = [1]*n

    for i in range(1, n):
        for j in range(i):
            if (nums[i] > nums[j]):
                table[i] = max(table[i], table[j] + 1)

    print(f"Min deletions rquired to sort sequence : {n-table[i]}")


print("DP -> Iteration + Tabulation Method :")
min_deletions_required_to_sort_sequence_dp_tabulation([4, 2, 3, 6, 10, 1, 12])
min_deletions_required_to_sort_sequence_dp_tabulation([-4, 10, 3, 7, 15])
min_deletions_required_to_sort_sequence_dp_tabulation([3, 2, 1, 0])

Output:

DP -> Iteration + Tabulation Method :
Min deletions rquired to sort sequence : 2
Min deletions rquired to sort sequence : 1
Min deletions rquired to sort sequence : 3

Complexity:



4. Longest Bitonic Subsequence

Problem Statement:

Given a number sequence, find the length of its Longest Bitonic Subsequence(LBS).

A subsequence is considered bitonic if it is monotonically increasing and then monotonically decreasing.

====== Examples ======
Input: {4, 2, 3, 6, 10, 1, 12}
Output: 5
Explanation: The LBS is {2, 3, 6, 10, 1}

Input: {4, 2, 5, 9, 7, 6, 10, 3, 1}
Output: 7
Explanation: The LBS is {4, 5, 9, 7, 6, 3, 1}


Brute-Force : Recursive Solution


DP : Iteration + Tabulation (Bottom-Up) Solution

Code:

def find_longest_bitonic_subsequence_dp_tabulation(nums):
    n = len(nums)
    table_lds_forward = [1] * n
    table_lds_backward = [1] * n

    # From beginning to end of sequence, calculate backward LDS
    for i in range(1, n):
        for j in range(i - 1, -1, -1):
            if (nums[j] < nums[i]):
                table_lds_backward[i] = max(table_lds_backward[i], table_lds_backward[j] + 1)

    # From end to beginning of sequence, calculate forward LDS
    for i in range(n - 2, -1, -1):
        for j in range(i + 1, n):
            if (nums[j] < nums[i]):
                table_lds_forward[i] = max(table_lds_forward[i], table_lds_forward[j] + 1)

    # Calculate max lbs length
    max_lbs_length = 0
    for i in range(n):
        max_lbs_length = max(max_lbs_length, table_lds_backward[i] + table_lds_forward[i] - 1)

    return max_lbs_length


print("DP -> Iteration + Tabulation Method :")
print(find_longest_bitonic_subsequence_dp_tabulation([4, 2, 3, 6, 10, 1, 12]))
print(find_longest_bitonic_subsequence_dp_tabulation([4, 2, 5, 9, 7, 6, 10, 3, 1]))

Output:

DP -> Iteration + Tabulation Method :
5
7

Complexity:



5. Longest Alternating Subsequence




← Previous: Longest Common Substring Pattern

Next: Miscellaneous DP Problems →