📜  重复删除 LIS 后的数组大小(1)

📅  最后修改于: 2023-12-03 15:28:31.501000             🧑  作者: Mango

重复删除 LIS 后的数组大小

在计算机科学中,LIS(最长上升子序列)问题是在给定序列中找到最长的子序列,使得其中的元素按升序排列。这个问题是一个经典的计算机科学问题,在许多领域都有应用。不过,在其对于特殊情况进行扩展时,可能会出现问题。

当给定的序列中存在重复元素时,LIS问题需要对结果进行特殊处理。简而言之,如果LIS中存在重复元素,需要将其删除,并重新计算LIS,得到新的最长上升子序列。此时,问题转变为“重复删除 LIS 后的数组大小”。

以下是一种可以实现此类操作的C语言代码实例:

#include <stdio.h>
#include <stdlib.h>

int binarySearch(int *arr, int l, int r, int key){
    while(r - l > 1){
        int mid = l + (r - l) / 2;
        if(arr[mid] >= key)
            r = mid;
        else
            l = mid;
    }

    return r;
}

int removeDuplicates(int *arr, int n){
    if(n == 0)
        return 0;
        
    int *tail = (int*) malloc(n*sizeof(int));
    int len = 1;

    tail[0] = arr[0];
    for(int i = 1; i < n; i++){
        if(arr[i] < tail[0])
            tail[0] = arr[i];
        else if(arr[i] > tail[len-1])
            tail[len++] = arr[i];
        else
            tail[binarySearch(tail, -1, len-1, arr[i])] = arr[i];
    }

    free(tail);

    return len;
}

int main(){
    int arr[] = {3, 10, 2, 1, 20};
    int n = sizeof(arr)/sizeof(arr[0]);

    printf("Original sequence: \n");
    for(int i = 0; i < n; i++)
        printf("%d ", arr[i]);

    int new_size = removeDuplicates(arr, n);

    printf("\nNew sequence after removing duplicates: \n");
    for(int i = 0; i < new_size; i++)
        printf("%d ", arr[i]);

    return 0;
}

以上代码主要分为两个函数,一个函数用于计算LIS,另一个函数用于删除LIS中的重复元素并返回新的数组大小。算法思想是:对于给定的序列 arr,我们定义一个空数组 tail,tail[0] 表示长度为 1 的所有上升子序列的最小末尾元素。则 tail 的元素严格单调递增。对于元素 arr[i],如果 arr[i] 小于 tail[0],则替换 tail[0];如果 arr[i] 大于 tail[len-1],则在末尾添加新元素;否则,从 tail 中找到第一个大于等于 arr[i] 的元素的位置,用 arr[i] 替换掉该位置的元素。最终,返回 tail 的长度即为重复删除 LIS 后的数组大小。

在上面的示例中,原始序列是 {3, 10, 2, 1, 20}。计算完LIS后得到的序列是{3, 10, 20},然后使用removeDuplicates() 函数对 LIS 消除重复元素,得到 {3, 10, 20},数组大小为3。

总之,对于存在重复元素的LIS问题,需要消除 LIS 中的重复元素才能得到正确答案。