(Good topic)贪心+二分查找:最长上升子序列(3.14 leetcode每日打卡)

给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:

 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
 你算法的时间复杂度应该为 O(n2) 。

进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?
 
思路:emmm,还没学动态规划,就看了一下官方思路写了一下,贪心和二分查找,二分查找主要用于优化速率。用一个dp数组保存最长子序列,从第一个数据开始,如果第二个数据比第一个数据小,如果大,就直接放到后边,然后第二个数据就顶替第一个数据,如果后边有数据,在dp数组中间,则这个数据就直接把刚好比它大的那个数据顶替掉,emmmm说不清楚。。。
直接上实例:
首先dp[0] = 10     然后发现nums[1]<dp[0],所以直接用nums[1]作为dp[0]重新开始,遇到nums[2]<dp[0],同理,遇到nums[3] = 5,放到后边,遇到nums[4] = 3,它大于2小于5,直接顶替5,以此类推
dp数组中的元素变化:
dp[numsSize] = 10
dp[numsSize] = 9
dp[numsSize] = 2
dp[numsSize] = 2  5
dp[numsSize] = 2  3
dp[numsSize] = 2  3  7
dp[numsSize] = 2  3  7  101
dp[numsSize] = 2  3  18  101
ok ok 返回长度即可。
int lengthOfLIS(int* nums, int numsSize)
{
    if(numsSize == 0)
    return 0;
    int dp[numsSize];
    int p = -1;

    dp[++p] = nums[0];
    for(int i=0; i<numsSize; i++)
    {
        if(nums[i] > dp[p])
        {
            dp[++p] = nums[i];
        }
        else //进行二分查找法
        {
            int low = 0; //指向头部
            int high = p; //指向尾部
            int ptr = 0;
            while(low <= high)
            {
                int mid = (high+low)/2; //指向中间
                if(nums[i] > dp[mid])
                {
                    ptr = mid;
                    low = mid+1;
                }
                else if(nums[i] <= dp[mid])
                {
                    high = mid-1;
                }
            }

             if(dp[ptr] >= nums[i])
            {
                dp[ptr] = nums[i];
            }
            else
            {
                dp[ptr+1] = nums[i];
            }
        }
    }
    
    return p+1;
}
 
 
原文地址:https://www.cnblogs.com/ZhengLijie/p/12493638.html