# 采用贪心法+二分法。使用maxlen存储对应元素的最大递增序列长度;tmp存储实际值
# 概念1:当新加入的元素i比末尾元素大时,满足递增---直接加入; 若比末尾元素小,则
# 采用二分法寻找第一个比该元素大的数,并将其替换为i
# 以[2,1,5,3,6,4,8,9,7]为例。最初mexlen=[1];tmp=[2]. 
# 加入1,比tmp[-1]小,因此将2替换为1---tmp=[1],maxlen=[1,1] 
# 加入5,比tmp[-1]大,直接加入---tmp=[1,5],maxlen=[1,1,2]
# 加入3,比tmp[-1]小,因此将5替换为3---tmp=[1,3],maxlen=[1,1,2,2].... 
# 最后tmp=[1,3,4,7,9]; maxlen=[1,1,2,2,3,3,4,5,4] 
# 概念2:len(tmp)表示最大长度,但是并不一定是最终值。len(maxlen)表示arr的长度
# maxlen[-2]=5,表示对应的arr[-2]是最大递增序列的末尾,同理maxlen[-3]=4,表示
# 对用的arr[-3]为倒数第二位; 1,2,2,2是因为有很多种组合,字典序按最小排列,故去最前方的值
class Solution:
    def LIS(self , arr ):
        if len(arr)<2: return arr 

        self.index=None  #构建二分查找,查找第一个比i大的元素位置
        def binary_find(arr,left,right,target):
            if left>right: return 
            mid=int(left+(right-left)/2) 
            if arr[mid]>=target: #注意>=,因为可能存在4,4
                self.index=mid
                return binary_find(arr, left, mid-1, target)
            elif arr[mid]<target: 
                return binary_find(arr, mid+1, right, target)

        maxlen,tmp=[1],[arr[0]]
        for i in arr[1:]: 
            if i>tmp[-1]: 
                tmp.append(i)
                maxlen.append(len(tmp)) 
            else: 
                binary_find(tmp,0, len(tmp)-1, i) 
                tmp[self.index]=i 
                maxlen.append(len(tmp[:self.index+1])) 

        length=len(tmp)  #实际的最大长度
        for i in range(len(arr)-1,-1,-1): 
            if maxlen[i]==length: 
                tmp[length-1]=arr[i] 
                length-=1

        return tmp
        # write code here