目录
- 数组中重复的数据:
利用index本身特性
- 删除排序数组中的重复项:
快慢指针(重复元素覆盖)
- 删除排序数组中的重复项 II
- 两数之和:
hash思想
- 三数之和:
列表分割+双指针(相同元素过滤)
- 接雨水 :
列表分割+左右指针
- 列表分割权重:
数值区间二分法
- 二维数组中的查找:
- 寻找旋转排序数组中的最小值:
区间二分法
- 剑指 Offer 12. 矩阵中的路径:
辅助递归调用函数
- 和为K的子数组:
子数组和的hash思想
- 查找和最小的k对组合数字:
数值区间二分法
- 有序矩阵中第k小的元素
- 返回所有组合
- 滑动窗口最大值:heap(最小堆,又叫优先队列)
- 前k个高频元素
- 查找和最小的k对组合数字
- 找出第k小的距离对:
二分法+双指针
- 数组中的第K个最大元素:
快排
- 最少移动次数使数组元素相等 II
- 拼多多 种树
- 数组中的最长山脉
- 求解一个素数的立方根
- 最大数
- 除自身以外数组的乘积
- 计算右侧小于当前元素的个
- 3 的幂(简单题)
- 矩阵中的最长递增路径
- 孤独像素 I
- 有效的数独
python位运算:
运算符 | 描述 |
---|---|
& | 按位与运算符: 参与运算的两个值,如果两个相应位都为1,则该位的结果为1 ,否则为0 |
| | 按位或运算符: 只要对应的两个二进制位有一个1时,结果为就为1 |
^ | 按位异或运算符:当两对应的二进制相异时,结果为1 |
~ | 按位取反运算符:对数据的每个二进制位取反,即把1变成0,把0变为1. ~x 类似于 -x-1 |
<< | 左移动运算符:运算数的各二进制全部左移若干位,由"<<"右边的数指定移动的位数,高位丢弃,低位补0 |
>> | 右移动运算符:运算数的各二进制全部右移若干位,由">>"右边的数指定移动的位数 |
具体题目
442. 数组中重复的数据
给定一个整数数组 a,其中1 ≤ a[i] ≤ n (n为数组长度), 其中有些元素出现两次而其他元素出现一次。
找到所有出现两次的元素。
你可以不用到任何额外空间并在O(n)时间复杂度内解决这个问题吗?
代码:
class Solution(object):
def findDuplicates(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
if nums is None or len(nums) < 2:
return []
result = []
for i in range(len(nums)):
while nums[i] != i + 1: # 当前位置的值是否符合index
if nums[i] == nums[nums[i] - 1]: # 发现重复项
result.append(nums[i])
break
temp = nums[nums[i] - 1]
nums[nums[i] - 1] = nums[i]
nums[i] = temp
return list(set(result))
26. 删除排序数组中的重复项
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
代码:
class Solution:
def removeDuplicates(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if len(nums) <= 1:
return len(nums)
s = 0
for f in range(1, len(nums)):
if nums[s] != nums[f]:
s += 1
nums[s] = nums[f]
return s + 1
80. 删除排序数组中的重复项 II
给定一个增序排列数组 nums ,你需要在 原地 删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。
class Solution:
def removeDuplicates(self, nums: 'List[int]') -> 'int':
i = 0
for e in nums:
if i < 2 or e != nums[i-2]:
nums[i] = e
i += 1
return i
1. 两数之和
代码:
class Solution:
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
n=len(nums)
#创建一个空字典
HashMap= {}
for i in range(n):
complement = target - nums[i]
#字典d中存在nums[x]时
if complement in HashMap.keys(): # if complement in HashMap:判断某个键是否存在的两种方式
return HashMap[complement],i
#否则往字典增加键/值对
else:
HashMap[nums[i]] = i
#边往字典增加键/值对,边与nums[x]进行对比
15. 三数之和
代码:
class Solution:
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
result = list()
nums_len = len(nums)
if nums_len < 3:
return result
l, r, dif = 0, 0, 0
nums.sort()
for i in range(nums_len - 2):
if nums[i] > 0:
break
if i > 0 and nums[i - 1] == nums[i]:
continue
l = i + 1
r = nums_len - 1
dif = -nums[i]
while l < r:
if nums[l] + nums[r] == dif:
result.append([nums[l], nums[r], nums[i]])
while l < r and nums[l] == nums[l + 1]:
l += 1
while l < r and nums[r] == nums[r - 1]:
r -= 1
l += 1
r -= 1
elif nums[l] + nums[r] < dif:
l += 1
else:
r -= 1
return result
42. 接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
代码:
class Solution(object):
def trap(self, height):
"""
:type height: List[int]
:rtype: int
"""
"""
基本思路:先找到最大值,即山峰peak的位置,然后用双指针,分别从两端的柱子靠近,
如果柱子大于前面柱子的最大值则不存在积水,小于则存在积水,并且当前柱子的积水量:前面柱子的最大值-当前柱子的高度
"""
if height is None:
return 0
maxh=0
indexmax=0
for i in range(len(height)):
if maxh < height[i]:
maxh=height[i]
indexmax=i
left,right=0,0
re=0
for i in range(indexmax):
if height[i]>left:
left=height[i]
continue
re+=left-height[i]
for j in range(len(height)-1,indexmax,-1):
if right<height[j]:
right=height[j]
continue
re+=right-height[j]
return re
剑指 Offer 04. 二维数组中的查找
class Solution:
def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
if len(matrix)==0:
return False
nrow=len(matrix)
ncol=len(matrix[0])
row=0
cols=ncol-1
while row <=nrow - 1 and cols>=0:
if target==matrix[row][cols]:
return True
elif target > matrix[row][cols]:
row+=1
else:
cols-=1
return False
153. 寻找旋转排序数组中的最小值
假设按照升序排序的数组在预先未知的某个点上进行了旋转。例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] 。
请找出其中最小的元素。
class Solution:
def findMin(self, nums: List[int]) -> int:
left, right = 0, len(nums) - 1
while left < right:
mid = 1+(right-left) >> 1
if nums[mid] > nums[right]:
left = mid + 1
else:
right = mid
return nums[left]
剑指 Offer 12. 矩阵中的路径
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。
[[“a”,“b”,“c”,“e”],
[“s”,“f”,“c”,“s”],
[“a”,“d”,“e”,“e”]]
但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
def dfs(i, j, k):
if not 0 <= i < len(board) or not 0 <= j < len(board[0]) or board[i][j] != word[k]:
return False
if k == len(word) - 1:
return True
board[i][j] = '' # 标记已经走过的路径,
res = dfs(i + 1, j, k + 1) or dfs(i - 1, j, k + 1) or dfs(i, j + 1, k + 1) or dfs(i, j - 1, k + 1)
board[i][j] = word[k] # 恢复被标记的位置的元素值
return res
for i in range(len(board)):
for j in range(len(board[0])):
if dfs(i, j, 0): return True
return False
560. 和为K的子数组
class Solution:
def subarraySum(self, nums: List[int], k: int) :
# hash表:序列头尾对应的位置,将起点对应的序列和存储在hash表中,dict={}
# 计算数组中第i个元素到第j个元素的和sum(nums[i:j]),这里只需要将sum(nums[:i])
# 放到hash表中,k=sum(nums[:j])-sum(nums[:i])
m={0:1}
sumN=0
count=0
for i in range(len(nums)):
sumN+=nums[i]
count+=m.get(sumN-k,0)
m[sumN]=m.get(sumN,0)+1
return count
378 有序矩阵中第k小的元素
class Solution:
def kthSmallest(self, matrix: List[List[int]], k: int) :
#因为每次循环中都保证了第k小的数在left-right之间,当left==right时,第k小的数即被找出来,
# 数值区间二分
n,m=len(matrix),len(matrix[0])
l,h=matrix[0][0],matrix[n-1][m-1]
while l <h:
count=0
mid=(l+h)//2
for i in range(n):
j=m-1
while j>=0 and matrix[i][j]>mid:
j-=1
count+=j+1
if count >=k:
h=mid
else:
l=mid+1
return l
9.依次给出n个正整数A1,A2,… ,An,将这n个数分割成m段,每一段内的所有数的和记为这一段的权重, m段权重的最大值记为本次分割的权重。问所有分割方案中分割权重的最小值是多少?
"""
最优值在数组最大值和数组之和之间,可以使用数值区间二分查找。
区间划分判定条件:
开始假设只有一个子数组,循环遍历,并向其中添加元素,直到数组和大于mid,划分数组,并将和值赋值新值。
如果开辟的数组>m,意味着数组容量mid太小,需要从[mid,right],否则在[left,right]中查找
"""
def split_arr(nums, m):
n = len(nums)
left = max(nums)
right = sum(nums)
ans = right
while left < right:
res = 0
cnt = 1
mid = (left + right) // 2
for i in range(n):
if res + nums[i] > mid:
cnt += 1
res = nums[i]
else:
res += nums[i]
if cnt <= m:
ans = min(mid, ans)
right = mid
else:
left = mid + 1
return ans
10. 从n个数字的数组中任取m个为一个组合,返回所有组合,顺序不一样的算一个组合(递归遍历+回溯)
参考
239. 滑动窗口最大值
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
# 1.用滑窗解决滑动窗口最大值
class Solution:
def maxSlidingWindow(self,nums,k):
n=len(nums)
if n==0:
return []
ans=[]
tmp=max(nums[:k]) # 当前窗口里的最大值
for i in range(n-k): # i 为滑动窗口的左边界
ans.append(tmp)
#sliding window
if nums[i+k] >tmp: # nums[i+k] 将要加入的数
tmp=nums[i+k]
else:
if nums[i] ==tmp: # 丢弃的数
tmp=max(nums[i+1:i+1+k])
ans.append(tmp)
return ans
#双端队列:获取窗口最大值的o(1)时间,需借助单调栈,头大尾小
from collections import deque
class Solution:
def maxSlidingWindow(self,nums,k):
queue=deque()
if not nums:
return []
res=[]
for i in range(len(nums)):
# 如果对头正好离开了滑动窗口。pop它
if queue and queue[0]==i-k:
queue.popleft()
# 单调队列push
while queue and nums[queue[-1]]< nums[i]: # 队列不为空,且新增加的右端值大于队尾
queue.pop()
queue.append(i) #添加右端值,且已经为队列中的最小值
if i+1 >=k: #窗口开始滑动
res.append(nums[queue[0]])
return res
347 前k个高频元素
出现频数问题就可以考虑桶排序
代码:
class Solution(object):
def topKFrequent(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
"""
解题思路,我们可以设置若干个桶,每个桶储存出现频率相同的数,
并且桶的下标代表桶中数出现的频率,即第i个桶中出现数的频率为i。把数都放桶之后,从后往前遍历桶,
最先得到的k个数就是出现频率最高的k个数。
"""
frequent_of_number={}
for num in nums:
frequent_of_number[num]=frequent_of_number.get(num,0)+1
#建通,1.申请一个包含所有元素的数组,并初始化。
buckets=[[] for _ in range(len(nums)+1)] #
for key,value in frequent_of_number.items():
buckets[value].append(key)
res=[]
for i in range(len(nums),-1,-1):
if k>0 and buckets[i]:
res +=buckets[i]
k-=len(buckets[i])
if k==0:
return res
373 查找和最小的k对组合数字
给定两个以升序排列的整形数组 nums1 和 nums2, 以及一个整数 k。
定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2。
找到和最小的 k 对数字 (u1,v1), (u2,v2) … (uk,vk)。
参考
class Solution:
def kthSmallest(self,matrix,k):
n=len(matrix)
heap=[(matrix[i][0],i,0) for i in range(n)] # 取第一列作为候选集,记录值和坐标
heapq.heapify(heap)
for i in range(k-1): # 第k次return
num,x,y=heapq.heappop(heap)
if y!=n-1: # 如果这一行还没被弹完
heapq.heappush(heap,(matrix[x][y+1],x,y+1)) # 加入这一行的下一个候选人
return heapq.heappop(heap)[0]
方法2:
#coding=utf-8
def searchKPair(nums1,nums2,k):
res=[(nums1[0],nums2[0])]
dp=[[ 0 for _ in range(len(nums2))]for _ in range(len(nums1))]
i,j=0,0
dp[0][0]=nums1[0]+nums2[0]
cnt=1
while i <len(nums1) or j < len(nums2):
if cnt ==k:
break
if dp[i][j+1] = 0:
dp[i][j+1]=nums1[i]+nums2[j+1]
if dp[i+1][j] = 0:
dp[i+1][j]=nums1[i+1]+nums2[j]
if dp[i+1][j]<dp[i][j+1]:
res.append((nums1[i+1],nums2[j]))
i+=1
cnt+=1
else:
res.append((nums1[i],nums2[j+1]))
j+=1
cnt+=1
return res
nums1=[1,7,11]
nums2=[2,4,6]
res=searchKPair(nums1, nums2, 3)
print(res)
719 找出第k小的距离对
给定一个整数数组,返回所有数对之间的第 k 个最小距离。一对 (A, B) 的距离被定义为 A 和 B 之间的绝对差值
class Solution:
def smallestDistancePair(self,nums,k):
nums.sort()
min_distance=0
max_distance=nums[-1]-nums[0]
# 第k小的距离差必然在[min,max]之间,通过二分搜索确定距离差
low,high=min_distance,max_distance
while low < high:
mid=(low+high)//2
count=self.count_mid_distance(nums,mid)
if count >=k:
high=mid
else:
low=mid+1
return low
def count_mid_distance(self,nums,target):
left,count=0,0
"""
由于数组已有序,所以我们只需要统计差值在target内的数量即可,大于target的我们可以直接跳过,以此来减少计算次数
依然使用动态窗口机制,我们每次计算至差值 <= target,则窗口向右滑动时,两侧元素差值 > target,我们可以直接将左侧元素剔除
"""
for right in range(1,len(nums)):
"""
每次将right与 [left, right] 中的每个元素进行比较,由于数组有序,我们只需要将left移动至第一个满足 right-left <= tartget
的位置即可,中间的元素即为满足条件的元素,# 若无元素满足条件,则left追上right
"""
while nums[right]-nums[left] > targt:
left+=1
count+=right-left
return count
215 数组中的第K个最大元素
快速排序
代码:
class Solution(object):
def findKthLargest(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
k=len(nums)-k
left=0
right= len(nums)-1
while left<right:
j=self.partition(nums,left,right)
if j==k:
break
elif j<k:
left=j+1
else:
right=j-1
return nums[k]
def partition(self,list,p,r):
i=p-1
for j in range(p,r):
if list[j]<=list[r]:
i+=1
list[i],list[j]=list[j],list[i]
list[i+1],list[r]=list[r],list[i+1]
return i+1
def quick_sort(array, l, r):
if l < r:
q = partition(array, l, r)
quick_sort(array, l, q - 1)
quick_sort(array, q + 1, r)
def partition(array, l, r):
x = array[r]
i = l - 1
for j in range(l, r):
if array[j] <= x:
i += 1
array[i], array[j] = array[j], array[i]
array[i + 1], array[r] = array[r], array[i+1]
return i + 1
2.堆排序(python库 heapq):
对于堆排序一般升序采用大顶堆,降序采用小顶堆。本题中想要寻找的第k个最大的元素,自然需要的是升序排序,因此采用大顶堆。当然本题并不是一个纯粹的排序,因此并不需要全部排序完成,只需要进行k次交换,即可找到第k个最大的元素。参考
class Solution(object):
def findKthLargest(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
return self.heap_sort(nums,k)
def heap_sort(self,nums,k):
#构建大顶堆
for i in range(len(nums)//2-1,-1,-1):
self.heap_adjust(nums,i,len(nums))
cnt=0
#交换堆顶元素,然后重新调整堆结构
for i in range(len(nums)-1,0,-1):
self.heap_swap(nums,0,i) #将堆顶元素和最后一个位置互换,将剩余n-1元素重新调整堆结构
cnt+=1
if cnt==k:
return nums[i]
self.heap_adjust(nums,0,i)
return nums[0]
def heap_adjust(self,nums,start,length):
tmp=nums[start]
k=start*2+1
while k <length : #对于完全二叉树,没有做节点则一定没有右节点
#当左节点的序号
left=start*2+1
#当前节点的右节点序号
right=left +1
if right <length and nums[right]>nums[left]:
#如果右节点比较大
k= right
if nums[k]>tmp:
nums[start]=nums[k]
start=k
else:
break
k=k*2+1
nums[start]=tmp
def heap_swap(self,nums,i,j):
nums[i],nums[j]=nums[j],nums[i]
return nums
462 最少移动次数使数组元素相等 II
思路:朝着中位数的方向移动
class Solution(object):
def minMoves2(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
nums=sorted(nums)
res=0
left,right=0,len(nums)-1
while left <right:
res+=nums[right]-nums[left]
left+=1
right-=1
return res
1.拼多多 种树
小多想在美化一下自己的庄园。他的庄园毗邻一条小河,他希望在河边种一排树,共 M 棵。小多采购了 N 个品种的树,每个品种的数量是 Ai (树的总数量恰好为 M)。但是他希望任意两棵相邻的树不是同一品种的。小多请你帮忙设计一种满足要求的种树方案。
例子:
3
4 2 1
输出:
1 2 1 2 1 3 1
def dfs(n,tree):
maxer= max(tree)
s = sum(tree)
if maxer > (s + 1)/2 : #唯一一种不存在满足条件方案的情况
print("-")
result = []
while (s): #直到所有的树全部种上
maxer = 0
index = -1
#数量最多以及对应的品种
for i in range(len(tree)): #遍历所有的品种找到最多的
if tree[i] > maxer:
maxer = tree[i]
index = i
if maxer > s / 2:
result.append(index + 1)
tree[index] -= 1
#上面一段代码用来保证总量为奇数时,超过一半的品种数。第一个坑必须中该品种的树:比如 1 2 4
else:
for i in range(len(tree)):
if tree[i] > 0 and (len(result) == 0 or len(result) and i + 1 != result[-1]) :
result.append(i + 1)
tree[i] -= 1
break
else:
continue
s -= 1
result = list(map(str, result))
print(" ".join(result))
n1 = input()
arr = list(map(int,input().split()))
dfs(n1,arr)
845.数组中的最长山脉
输入:[2,1,4,7,3,2,5]
输出:5
解释:最长的 “山脉” 是 [1,4,7,3,2],长度为 5。
解题思路:双指针。先找到比左右两侧大的数 然后以这个数为中心 依次找到左右的长度
class Solution(object):
def longestMountain(self, A):
"""
:type A: List[int]
:rtype: int
"""
if len(A)<3:
return 0
res=0
for i in range(1,len(A)-1):
if A[i-1]<A[i] and A[i+1]<A[i]:
left,right=i-1,i+1
while left>0 and A[left-1]<A[left]:
left-=1
while right<len(A)-1 and A[right+1]<A[right]:
right+=1
res=max(res,right-left+1)
return res
方法2
从x轴的零坐标出发,走出的第n步,步长为n,即第一步移动的距离为1,第二步移动的距离为2。每次移动可以向左或向右移动。求最少需要走多少步才能到达target位置(target可以为负)。若无论怎么走都达到不了,则输出-1。
解题思路:
target为正或负,所需要的步数是一样的。target=abs(target)
1.求sum=1+2+…+k。是sum刚好大于target。diff=sum-target
2.若diff为偶数,则让diff/2反向即可,共需要k步到达target。
3.若diff为奇数,让任何数反向都是减少偶数距离,不会使得diff为0。因此让diff+k+1
4.若diff+k+1为偶数,则根据1可知k+1步可到达target。
5.若diff+k+1为奇数,说明k+1为偶数,则k+2必然为奇数,因此diff+k+1+k+2必为偶数,即可以在k+2步时到达
def FindTarget(target):
target=abs(target)
i=0
sum=0
while sum<target:
i += 1
sum+=i
if sum==target:
return i
else:
diff=sum-target
if diff%2==0:
return i
else:
if (diff+i+1)%2==0:
return i+1
else:
return i+2
x=input()
print FindTarget(x)
1. 求解一个素数的立方根
def subtriplicate(n,diff):
if n ==0.0 or n==1.0:
return n
if n>1:
ans=helper(0,n,diff)
elif 0<n<1:
ans=helper(n,1,diff)
elif n<-1:
ans=helper(n,0,diff)
else:
ans=helper(n,-1,diff)
return ans
def helper(left,right,diff):
flag=True
while left <right:
mid=(right+left)/2
if abs(mid *mid*mid - n) <=diff :
return mid
elif mid*mid*mid -n >diff:
right=mid
else:
left=mid
return left
if __name__=="__main__":
n=0.9
diff=0.001
print(subtriplicate(n,diff))
179. 最大数
给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。
本质: 元素排序
class Solution:
def largestNumber(self, nums: List[int]) -> str:
return "0" if (nums:= sorted(map(str, nums), key=cmp_to_key(lambda x,y:int(y+x)-int(x+y))))[0]=="0" else "".join(nums)
#先把nums中的所有数字转化为字符串,形成字符串数组 nums_str
#比较两个字符串x,y的拼接结果x+y和y+x哪个更大,从而确定x和y谁排在前面;将nums_str降序排序
#把整个数组排序的结果拼接成一个字符串,并且返回
def largestNumber(self, nums: List[int]) -> str:
nums_str=list(map(str,nums))
compare=lambda x,y: 1 if x+y<y+x else -1
nums_str.sort(key=functools.cmp_to_key(compare))
res=''.join(nums_str)
if res[0]=='0':
res='0'
return res
def largestNumber(self, nums: List[int]) -> str:
res = ''
for i in range(0, len(nums) - 1):
for j in range(i + 1, len(nums)):
if int(str(nums[i]) + str(nums[j])) < int(str(nums[j]) + str(nums[i])):
nums[i], nums[j] = nums[j], nums[i]
for num in nums:
res += str(num)
return str(int(res))
238. 除自身以外数组的乘积
# 方法1: 左右乘积列表
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
length = len(nums)
# L 和 R 分别表示左右两侧的乘积列表
L, R, answer = [0]*length, [0]*length, [0]*length
# L[i] 为索引 i 左侧所有元素的乘积
# 对于索引为 '0' 的元素,因为左侧没有元素,所以 L[0] = 1
L[0] = 1
for i in range(1, length):
L[i] = nums[i - 1] * L[i - 1]
# R[i] 为索引 i 右侧所有元素的乘积
# 对于索引为 'length-1' 的元素,因为右侧没有元素,所以 R[length-1] = 1
R[length - 1] = 1
for i in reversed(range(length - 1)):
R[i] = nums[i + 1] * R[i + 1]
# 对于索引 i,除 nums[i] 之外其余各元素的乘积就是左侧所有元素的乘积乘以右侧所有元素的乘积
for i in range(length):
answer[i] = L[i] * R[i]
return answer
# 方法2 :
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
length = len(nums)
answer = [0]*length
# answer[i] 表示索引 i 左侧所有元素的乘积
# 因为索引为 '0' 的元素左侧没有元素, 所以 answer[0] = 1
answer[0] = 1
for i in range(1, length):
answer[i] = nums[i - 1] * answer[i - 1]
# R 为右侧所有元素的乘积
# 刚开始右边没有元素,所以 R = 1
R = 1;
for i in reversed(range(length)):
# 对于索引 i,左边的乘积为 answer[i],右边的乘积为 R
answer[i] = answer[i] * R
# R 需要包含右边所有的乘积,所以计算下一个结果时需要将当前值乘到 R 上
R *= nums[i]
return answer
计算右侧小于当前元素的个
二分法:
class Solution:
def countSmaller(self, nums: List[int]) -> List[int]:
n=len(nums)
count=[0]*n
stack=[]
def find(arr,l,r,target):
while l<=r:
m=l+(r-l)//2
if arr[m]>=target:
l=m+1
else:
r=m-1
return l
for i in range(n-1,-1,-1):
x=nums[i]
# t=[]
# while stack and stack[-1]>=x:
# t.append(stack.pop())
idx=find(stack,0,len(stack)-1,x)
count[i]=len(stack)-idx
stack.insert(idx,x)
# stack.append(x)
# while t :
# stack.append(t.pop())
return count
326. 3 的幂
class Solution:
def isPowerOfThree(self, n: int) -> bool:
while n and n % 3 == 0:
n //= 3
return n == 1
329. 矩阵中的最长递增路径
- 记忆化搜索:从任意点出发,都存在一条最长的递增路径
- 递归:从(i,j)出发的最长路径即为f(i,j),从而构建如下递归公式:
f(i, j) = max{f(x, y)} + 1
,其中(x,y)是(i,j)的相邻点,为了避免重复计算,我们使用一个矩阵存储从(i,j)出发的最长路径。
class Solution:
def longestIncreasingPath(self, matrix: List[List[int]]) -> int:
m, n = len(matrix), len(matrix[0])
flag = [[-1] * n for _ in range(m)] #存储从(i,j)出发的最长递归路径
def dfs(i, j):
if flag[i][j] != -1: # 记忆化搜索,避免重复的计算
return flag[i][j]
else:
d = 1
for (x, y) in [[-1, 0], [1, 0], [0, 1], [0, -1]]:
x, y = i + x, j + y
if 0 <= x < m and 0 <= y < n and matrix[x][y] > matrix[i][j]:
d = max(d, dfs(x, y) + 1) # 取四个邻接点的最长
flag[i][j] = d
return d
res = 0
for i in range(m): # 遍历矩阵计算最长路径
for j in range(n):
if flag[i][j] == -1:
res = max(res, dfs(i, j))
return res
531. 孤独像素 I
给你一个大小为 m x n 的图像 picture ,图像由黑白像素组成,‘B’ 表示黑色像素,‘W’ 表示白色像素,请你统计并返回图像中 黑色 孤独像素的数量。
黑色孤独像素 的定义为:如果黑色像素 ‘B’ 所在的同一行和同一列不存在其他黑色像素,那么这个黑色像素就是黑色孤独像素。
class Solution:
def findLonelyPixel(self, picture: List[List[str]]) -> int:
row = len(picture)
col = len(picture[0])
rowcount = [0] * row
colcount = [0] * col
result = 0
for i in range(row):
for j in range(col):
if picture[i][j] == 'B':
rowcount[i] += 1
colcount[j] += 1
for i in range(row):
for j in range(col):
if picture[i][j] == 'B':
if rowcount[i] == 1 and colcount[j] == 1:
result += 1
return result
36. 有效的数独
解题思路:记录某行、某列、3x3 宫格内数字=======》使用hashMap
class Solution:
def isValidSudoku(self, board):
"""
:type board: List[List[str]]
:rtype: bool
"""
rows = [{} for i in range(9)]
columns = [{} for i in range(9)]
boxes = [{} for i in range(9)]
# validate a board
for i in range(9):
for j in range(9):
num = board[i][j]
if num != '.':
num = int(num)
box_index = (i // 3 ) * 3 + j // 3
# keep the current cell value
rows[i][num] = rows[i].get(num, 0) + 1
columns[j][num] = columns[j].get(num, 0) + 1
boxes[box_index][num] = boxes[box_index].get(num, 0) + 1
# check if this value has been already seen before
if rows[i][num] > 1 or columns[j][num] > 1 or boxes[box_index][num] > 1:
return False
return True