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
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
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
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:]
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
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)