6.6 吉利的一天! 最长上升子序列(三种方法)

1337. 方阵中战斗力最弱的 K 行
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution:
    def kWeakestRows(self, mat: List[List[int]], k: int) -> List[int]:
    #每一行最左边的0
        def binary(num):
            left,right=0,len(num)-1
            while left<right:
                mid=left+(right-left)//2
                if num[mid]==0:
                    right=mid
                else:
                    left=mid+1
            return left

        #按照每一行最左边0的索引排序,越小说明越弱
        n=len(mat[0])
        m=len(mat)
        ans=[]
        for i in range(m):
            if mat[i][-1]==1:
                ans.append([i,n])
            elif mat[i][0]==0:
                ans.append([i,0])
            else:
                ans.append([i,binary(mat[i])])
        ans=sorted(ans,key=lambda x:(x[1],x[0]))
        return [i for i,v in ans[:k] ]

1287. 有序数组中出现次数超过25%的元素
在这里插入图片描述
有序数组,如果len(arr)/4个数连着相等,那么该数就符合要求

class Solution:
    def findSpecialInteger(self, arr: List[int]) -> int:
        n=len(arr)//4
        for i in range(len(arr)-n):
            if arr[i]==arr[i+n]:
                return arr[i]

计数法

class Solution:
    def findSpecialInteger(self, arr: List[int]) -> int:
        for i,value in Counter(arr).items():
            if value>len(arr)//4:
                return i

1338. 数组大小减半
在这里插入图片描述
在这里插入图片描述

class Solution:
    def minSetSize(self, arr: List[int]) -> int:
        n=len(arr)
        ans=Counter(arr)
        ans=sorted(ans.items(),key=lambda x:-x[1])
        res=0
        cnt=0
        for i,value in ans:
            res+=1
            cnt+=value
            if cnt>=n//2:
                return res

66. 加一
在这里插入图片描述

class Solution:
    def plusOne(self, digits: List[int]) -> List[int]:
        digits[-1]+=1
        for i in range(len(digits)-1,-1,-1):
            if digits[i]>9:
                digits[i]%=10
                if i!=0:
                    digits[i-1]+=1
                else:
                    digits.insert(0,1)
        return digits

67. 二进制求和
在这里插入图片描述
逐位计算:

class Solution:
    def addBinary(self, a: str, b: str) -> str:
        i,j=len(a)-1,len(b)-1
        res=[]
        while i>=0 and j>=0:
            res.append(int(a[i])+int(b[j]))
            i-=1
            j-=1
        while i>=0:
            res.append(int(a[i]))
            i-=1
        while j>=0:
            res.append(int(b[j]))
            j-=1
        for i in range(len(res)):
            if res[i]>1:
                res[i]%=2
                if i!=len(res)-1:
                    res[i+1]+=1
                else:
                    res.append(1)
        ans=''
        for i in res[::-1]:
            ans+=str(i)
        return ans

位运算 :
异或:无进位加法 x^y
保存进位:两个数字与操作后左移一位,将进位对到左一位,(x&y)<<1
x 保存结果,y保存进位,直到进位为0

class Solution:
    def addBinary(self, a: str, b: str) -> str:
        #位运算
        x,y=int(a,2),int(b,2)
        while y!=0:
            x,y=x^y,(x&y)<<1
        return bin(x)[2:]

989. 数组形式的整数加法
在这里插入图片描述
在这里插入图片描述

class Solution:
    def addToArrayForm(self, A: List[int], K: int) -> List[int]:
        a=''.join(str(i) for i in A)
        res=str(int(a)+K)
        c=list(int(i) for i in res)
        return c

767. 重构字符串
在这里插入图片描述
如果一个字符出现的次数超过了 (N + 1) / 2,那么就不存在这样一种排列
如果N为奇数,单个字符最多出现(N)//2+1
如果N为偶数,单个字符最多出现(N)//2

class Solution:
    def reorganizeString(self, S: str) -> str:
        ans=sorted(Counter(S).items(),key=lambda x:x[1],reverse=True)
        if ans[0][1]>=(len(S)+1)//2+1:
            return ''
        res=[0]*len(S)
        idx=0
        for x,val in ans:
        #隔一位插入字符
            while val>0 and idx<len(S):
                res[idx]=x
                val-=1
                idx+=2
                if idx>=len(S):
                    idx=1
        return ''.join(res)

128. 最长连续序列
在这里插入图片描述
遍历数组,如果一个数的前一个数不在数组里(O(1)的时间复杂度),说明这个数还没有遍历过,将起点改为该数,往后延伸更新最长连续序列
如果一个数的前一个数已经在数组内,说明该数不是连续序列的起点,跳过
时间复杂度分析:
https://leetcode-cn.com/problems/longest-consecutive-sequence/solution/128ha-xi-biao-by-genjie-li/
在这里插入图片描述
在这里插入图片描述

class Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        arr=set(nums)
        maxl=0
        for a in arr:
            if a-1 not in arr:
                curl=1
                curnum=a
                while curnum+1 in arr:
                    curl+=1
                    curnum+=1
                maxl=max(maxl,curl)
        return maxl

1282. 用户分组
在这里插入图片描述

class Solution:
    def groupThePeople(self, groupSizes: List[int]) -> List[List[int]]:
        match=defaultdict(list)
        for idx,val in enumerate(groupSizes):
            match[val].append(idx)
        res=[]
        for i in match.keys():
            if len(match[i])==i:
                res.append(match[i])
            else:
                j=0
                while j<len(match[i]):
                    res.append(match[i][j:j+i])
                    j=j+i
        return res

334. 递增的三元子序列
在这里插入图片描述
前后遍历,分别保存当前位置之前的最小值,之后的最大值,如果存在一个元素,小于当前元素之后的最大值,大于当前元素之前的最小值,则说明存在递增的三元子序列

class Solution:
    def increasingTriplet(self, nums: List[int]) -> bool:
        left=[0]*len(nums)
        right=[0]*len(nums)
        minl=float('inf')
        maxl=float('-inf')
        for i in range(len(nums)):
            minl=min(minl,nums[i])
            left[i]=minl
        for i in range(len(nums)-1,-1,-1):
            maxl=max(maxl,nums[i])
            right[i]=maxl
        for i in range(len(nums)):
            if nums[i]>left[i] and nums[i]<right[i]:
                return True
        return False

300. 最长上升子序列
在这里插入图片描述
动态规划:
在这里插入图片描述
只有当nums[i]>nums[j],才能从状态j转移到状态i
dp是以i为结尾的元素,最长递增子序列

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        if not nums:
            return 0
        dp=[1]*len(nums)
        for i in range(len(nums)):
            for j in range(i):
                if nums[i]>nums[j]:
                    dp[i]=max(dp[i],dp[j]+1)
        return max(dp)

法二:时间极短,
维护一个结果数组,如果当前元素比结果数组的值都大的的话,就追加在结果数组后面(相当于递增序列长度加了1);否则的话用当前元素覆盖掉第一个比它大的元素(这样做的话后续递增序列才有可能更长,即使并没有更长,这个覆盖操作也并没有副作用哈,当然这个覆盖操作可能会让最终的结果数组值并不是最终的递增序列值,这无所谓)
覆盖掉第一个大于当前元素并不改变当前最长递增数列的长度
为什么要替换呢,因为越小的元素后面更可能接一个比他大的元素
因为这个数组是严格递增的,如果每次加的元素都比数组末尾元素小,会一直替换前面的元素,并不会改变长度,如果加的元素比末尾元素大,那么一定可以加到后面来增加长度,就算当前数组内元素不符合要求,但是长度不变

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        if not nums:
            return 0
        maxl=0
        match=[]
        for num in nums:
            #维护一个单调递增,当前值大于最后元素时,直接加上当前值,长度加1
            if not match or match[-1]<num:
                match.append(num)
                maxl+=1
            else:
                k=len(match)-1
                #当前值小于或等于最后一位时,从后往前找到第一个比当前值小的元素,将元素后一位替换为当前值,同时更新长度
                while k>=0 and match[k]>=num:
                    k-=1
                match[k+1]=num
                maxl=max(maxl,len(match))
        return maxl

法三: 二分查找 更小的值后面接更大的值的可能性更大
在法二的基础上,找到第一个大于当前元素采用二分查找法,把复杂度降为O(NlogN)
因为维护的是严格递增,所以可以采用二分法查找
找到严格递增数组中左边第一个大于当前元素的值,替换掉该值
速度更快了

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        if not nums:
            return 0
        #法三:
        match=[]
        for num in nums:
            if not match or match[-1]<num:
                match.append(num)
            else:
                l,r=0,len(match)-1
                while l<r:
                    mid=(l+r)//2
                    if match[mid]>=num:
                        r=mid
                    else:
                        l=mid+1
                match[r]=num
        return len(match)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值