一、数组查找(用二分法:一般求局部极小值、数组部分有序)
例 一个给定的不包含相同元素的整数数组,求它的一个局部最小值(局部极小值的定义是一个值比左右相邻的(如果存在)都小的值)
#复杂度O(logn)
def findmix(A):
length = len(A)
if length < 2:
return 0
left = 0
right = length -1
while left <= right:
if left == right:
return A[left]
mid = (left + right) // 2
if A[mid] < A[mid + 1]:
right = mid
else:
left = mid + 1
leetcode153、154类型同,33、81类型同,154、81有重复,重点去掉mid和right部分末尾重复内容,使其能判断是否单调,可对照看
leetcode153. Find Minimum in Rotated Sorted Array
class Solution:
def findMin(self, nums):
left = 0
right = len(nums)-1
while left <= right:
if left == right:
return nums[left]
mid = (left + right) // 2
if nums[mid] > nums[right]:
left = mid + 1
else:
right = mid
leetcode154. Find Minimum in Rotated Sorted Array II
class Solution:
def findMin(self, nums):
left = 0
right = len(nums)-1
while left <= right:
if left == right:
return nums[left]
mid = (left + right) // 2
while mid < right and nums[mid] == nums[right]:
right -= 1
if nums[mid] <= nums[right]:
right = mid
else:
left = mid + 1
leetcode33. Search in Rotated Sorted Array
#O(logn)重点:先判断mid对应值是否等于target,然后通过判断mid和right对应值的大小判断
#哪一段是单调的,进而分别判断这个数是否在这一段中,进行取半操作
class Solution:
def search(self, nums, target):
left = 0
right = len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
return mid
if nums[mid] < nums[right]:
if nums[mid] < target <= nums[right]:
left = mid + 1
else:
right = mid - 1
else:
if nums[left] <= target < nums[mid]:
right = mid - 1
else:
left = mid + 1
return -1
leetcode81. Search in Rotated Sorted Array II
class Solution:
def search(self, nums, target):
left = 0
right = len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
return True
while mid < right and nums[mid] == nums[right]: #这一步是关键
right -= 1
if nums[mid] <= nums[right]:
if nums[mid] < target <= nums[right]:
left = mid + 1
else:
right = mid - 1
else:
if nums[left] <= target < nums[mid]:
right = mid - 1
else:
left = mid + 1
return False
二、交换
以下几道题均用的是41思路,时间复杂度O(n)
leetcode41. First Missing Positive
#分三种情况,a[i] == i+1时i+=1,否则将不可能有正确位置的元素去除(包括,<1的,数值超过
#最大长度的,或是其正确位置已经有与其一样大的数占用的),剩下的是有正确位置的,所以
#将其与正确位置元素进行交换
class Solution:
def firstMissingPositive(self, nums):
n = len(nums)
i = 0
while i < n:
if i + 1 == nums[i]:
i += 1
elif nums[i] < 1 or nums[i] > n or nums[i] == nums[nums[i] - 1]:
nums[i] = nums[n - 1]
n -= 1
else:
pos = nums[i]
nums[i] = nums[pos - 1]
nums[pos - 1] = pos
return n+1
leetcode268. Missing Number
class Solution:
def missingNumber(self, nums):
n = len(nums)
i = 0
while i < n:
if nums[i] == i:
i += 1
elif nums[i] > n - 1:
nums[i] = nums[n-1]
n -= 1
else:
pos = nums[i]
nums[i] = nums[pos]
nums[pos] = pos
return n
另一种方式,很简单
class Solution:
def missingNumber(self, nums):
n = len(nums)
for i in range(n+1):
if i not in nums:
return i
leetcode287. Find the Duplicate Number
class Solution:
def findDuplicate(self, nums):
n = len(nums)
i = 0
while i < n:
if nums[i] == i + 1:
i += 1
elif nums[nums[i] - 1] == nums[i]:
return nums[i]
else:
pos = nums[i]
nums[i] = nums[pos - 1]
nums[pos - 1] = pos
三、元素最大间距离
leetcode164. Maximum Gap
**# 时间复杂度O(n)**
class Solution:
def maximumGap(self, nums):
n = len(nums)
if n < 2:
return 0
x = max(nums)
y = min(nums)
if x == y:
return 0
buckets = [[] for i in range(n+1)] #将n个数放n+1个桶里
for i in nums:
pos = (i-y)*(n+1)//(x-y)
if pos == (n+1): #注:最大的数要放最后一个桶里,因为最后一个桶是闭的
buckets[pos-1].append(i)
else:
buckets[pos].append(i)
max_gap = 0
for i in range(n+1):
if buckets[i] == []:
j = i + 1
k = i - 1
while buckets[j] == []:
j += 1
while buckets[k] == []:
k -= 1
gap = min(buckets[j])-max(buckets[k])
if gap > max_gap:
max_gap = gap
return max_gap
四、只出现1次的数
重点:想消去出现两次的数(136.260),做异或;对于出现次数不一致时(137),每一位对应相加%3;这类题也可以用字典,时间空间用的差不多
leetcode136. Single Number
class Solution:
def singleNumber(self, nums):
tmp = 0
for i in nums: #所有数做异或
tmp ^= i
return tmp
leetcode260. Single Number III
class Solution:
def singleNumber(self, nums):
tmp = 0
for i in nums: #所有数做异或
tmp ^= i
print(tmp)
pos = 1
while pos&tmp == 0: #判断出x与y两数不相等的位置pos
pos = pos<<1
print(pos)
x=y=0
for i in nums:
if i & pos == pos: #判断数是否与pos位相等,就与pos相比
x ^= i
else:
y ^= i
return x,y
leetcode137. Single Number II
class Solution:
def singleNumber(self, nums):
res = 0
for i in range(31, -1, -1):
count = 0
for num in nums:
count += (num >> i) & 1
rem = count % 3
if rem != 0:
if i == 31:
res -= 1 << 31
else:
res += 1<
1-100,缺少了两个数,求这两个数?
#这道题与260类似:将这个缺了两个数的数组arr的所有数与1-100放一块,其实就是260,其他数
#出现两次,就缺的这两个数出现一次
五、众数问题
核心:每次扔掉两个或多个不同的数,剩下的就是想要的
leetcode169. Majority Element
class Solution:
def majorityElement(self, nums):
count = 0
tmp = 0
for num in nums:
if count == 0:
tmp = num
if num == tmp:
count += 1
else:
if count != 0:
count -= 1
else:
tmp = num
return tmp
leetcode229. Majority Element II
class Solution:
def majorityElement(self, nums):
count1 = count2 = 0
tmp1 = tmp2 = 1.1
for num in nums:
if num == tmp1:
count1 += 1
elif num == tmp2:
count2 += 1
else:
if count1 == 0:
tmp1 = num
count1 = 1
elif count2 == 0:
tmp2 = num
count2 = 1
else:
count1 -= 1
count2 -= 1
res = []
if nums.count(tmp1) > len(nums)//3:
res.append(tmp1)
if nums.count(tmp2) > len(nums) // 3:
res.append(tmp2)
return res
六、前缀和的应用
给定浮点数组a,求一个数组b, b[i] = a[0] * a[1] *…*a[i – 1] * a[i + 1] * …*a[n – 1],不能使用除法,不允许再开数组
class Solution:
def mutiplies(self, a):
n = len(a)
b = [1]*n
for i in range(n):
for m in range(n-1,i,-1):
b[i] *= a[m]
for m in range(0,i):
b[i] *= a[m]
return b
求数组中连续一段和,绝对值最小?
class Solution:
def majorityElement(self, a):
n = len(a)
sum = [0] * n
for i in range(n): #创建前缀和sum
for j in range(i+1):
sum[i] += a[j]
sum.sort() #将sum排序
minsum = float('inf')
for i in range(n-1): #相邻做差去最小
dif = sum[i+1]-sum[i]
if dif < minsum:
minsum = dif
return minsum
把一个数组从中间p位置分开,使得a[0] + …+ a[p – 1]与a[p] + a[p + 1] + …+ a[n – 1]差值最小?
class Solution:
def majorityElement(self, a):
n = len(a)
sum = [0] * n
for i in range(n): #创建前缀和sum
for j in range(i+1):
sum[i] += a[j]
minsum = float('inf')
print(sum)
for i in range(1,n-1): #相邻做差去最小
dif = sum[n-1]-2*sum[i-1]
if dif < minsum:
minsum = dif
return minsum