Leetcode刷题笔记(记录答案+我遇到的问题)
坚持刷题,持续更新……欢迎监督
目录
数组
88.合并两个有序数组
题目要求:
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
来源:力扣(LeetCode)
链接:力扣
题解&问题
方法一:合并两个数组给nums,进行排序,排完再还给nums1
class Solution:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
"""
Do not return anything, modify nums1 in-place instead.
"""
nums=nums1[:m]
for i in range(n):
nums.append(nums2[i])
i+=1
nums.sort()
for i, num in enumerate(nums):
nums1[i] = num
用下面的方法print(nums1)出来的结果满足测试用例,但是平台给出的输出就和nums1给的初值一样,不清楚为什么。
知道原因啦:因为nums1的长度本身就是m+n,合并12后长度为m+2n。中间的0并没有去掉。利用新数组nums就是为了把0去掉。
class Solution:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
"""
Do not return anything, modify nums1 in-place instead.
"""
nums1=nums1[:m]
for i in range(n):
nums1.append(nums2[i])
i+=1
nums1.sort()
方法二:(参考负雪明烛)两个数组从尾部开始比较大小,更大的放在nums1的最后一位。如果nums2还有剩余,则放在nums1对应数量的最前方。
class Solution:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
"""
Do not return anything, modify nums1 in-place instead.
"""
while m>0 and n>0:
if nums1[m-1]>nums2[n-1]:
nums1[m+n-1]=nums1[m-1]
m-=1
else: #nums1[m-1]<=nums2[n-1]
nums1[m+n-1]=nums2[n-1]
n-=1
nums1[:n]=nums2[:n] # 如果nums2全部都已经添加到nums1里面,此时n=0,该句对结果没有影响。
# 如果nums2还有剩余,则全部放在nums1前方n个位置处
参考链接:【LeetCode】88. Merge Sorted Array 解题报告(Java & Python)_负雪明烛的博客-CSDN博客
240.搜索二维矩阵Ⅱ
题目要求:
编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:
每行的元素从左到右升序排列。
每列的元素从上到下升序排列。
来源:力扣(LeetCode)
链接:力扣
题解&问题:
方法一:(解题思路参考负雪明烛)因为矩阵是有顺序的,所以:
指针从矩阵左下角开始,
如果当前值<target,说明target在本行右侧;
如果当前值>target,说明target在上一行里;
如果当前值==target,return True。
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
m=len(matrix) #行
n=len(matrix[0]) #列
p=m-1 #行
q=0 #列
if not matrix or not matrix[0]:
return False
while True:
if p>-1 and q<n:
if matrix[p][q]>target:
p-=1
elif matrix[p][q]==target:
return True
else:
q+=1
else:
return False
问题:(下方代码没有通过)
我第一遍自己写的时候用的while,导致的结果:target不在matrix中的时候,会反反复复的查找。
是因为while只要没达到条件就会一直循环,而if则可以在递增到指定条件限制的时候停止?!
import numpy as np
class Solution:
def searchMatrix(self, matrix, target: int) -> bool:
matrix=np.array(matrix)
m=matrix.shape[0] #行
n=matrix.shape[1] #列
p=m-1 #行
q=0 #列
while p!=-1 or q!=n:
temp=matrix[p][q]
if temp<target:
q+=1
elif temp>target:
p-=1
else:
return True
return False
笔记:
if not 用法:
not matrix #矩阵为空??
not matrix[0] #矩阵列为空??
获得矩阵行列数目的方法:
# method 1
import numpy as np
matrix = np.array(matrix)
row = matrix.shape[0] # 行
col = matrix.shape[1] # 列
# method 2
row = len(matrix) # 行
col = len(matrix[0]) # 列: 第一行的长度
方法二:因为有顺序,所以可以用二分法
对每行都进行二分法比较
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
m=len(matrix) # 行
n=len(matrix[0]) # 列
if m==0 or n==0:
return False
elif target>matrix[m-1][n-1]:
return False
else:
for i in range(m): # 每行都用二分法比较
left,right=0,n-1 # 设置左右边界
while left<=right: # 注意此处要加边界限制条件
mid=(left+right)//2 # 设置middle
if matrix[i][mid]<target:
left=mid+1
elif matrix[i][mid]>target:
right=mid-1
else:
return True
return False
负雪明烛题解链接:
【LeetCode】240. Search a 2D Matrix II 解题报告(Python & C++)_负雪明烛的博客-CSDN博客
74.搜索二维矩阵
题目要求:
编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数
来源:力扣
题解&问题:
因为本题中所有数都是升序排列,所以把二维矩阵看作是一个完全升序的列表,然后二分查找。
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
h=len(matrix)
w=len(matrix[0])
if w==0 or h==0:
return False
left=0
right=h*w-1
while left<=right:
mid=(left+right)//2
i=mid//w
j=mid%w
if matrix[i][j]<target:
left=mid+1
elif matrix[i][j]>target:
right=mid-1
else:
return True
else:
return False
哈希表
1.两数之和
题目要求:
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
来源:力扣(LeetCode)
链接:力扣
题解&问题:
方法一:
遍历所有数,计算其余每个数是否等于(target-当前值)
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
for i in range(len(nums)):
for j in range(i+1,len(nums)):
if nums[j]==target-nums[i]:
return i,j
方法二:解题思路参考负雪明烛
用dict实现,先构建字典,然后找(target-当前值)的结果是否在字典中。
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
dic={}
for i,nums[i] in enumerate(nums):
dic[nums[i]]=i
for i,nums[i] in enumerate(nums):
if target-nums[i] in dic and dic[target-nums[i]]!=i:
return dic[target-nums[i]],i
方法三(负雪明烛解题思路【HashMap】):
代码先直接粘贴过来,等我研究明白再写思路
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
N = len(nums)
pos = dict()
for i, num in enumerate(nums):
if target - num in pos:
return [pos[target - num], i]
else:
pos[num] = i
return [0, 0]
负雪明烛原文链接:【LeetCode】1. Two Sum 两数之和_负雪明烛的博客-CSDN博客
二分法
704.二分查找(简单)
题目要求
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
来源:力扣(LeetCode)
链接:力扣
题解
思路:典型二分查找
class Solution:
def search(self, nums: List[int], target: int) -> int:
n=len(nums)
if n==0:
return -1
left,right=0,n-1
while left<=right:
mid=(left+right)//2
if nums[mid]>target:
right=mid-1
elif nums[mid]<target:
left=mid+1
else:
return mid
return -1
35. 搜索插入位置(简单)
题目要求
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
来源:力扣(LeetCode)
链接:力扣
题解
方法一:
思路:因为left和right已经发生的交叉,left>right,所以返回的应该是left。
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
n = len(nums)
left, right = 0, n-1
while left <= right:
mid = (left + right) // 2
if nums[mid] < target:
left = mid + 1
elif nums[mid] > target:
right = mid -1
else:
return mid
return left
Java
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0;
int right = nums.length -1;
int mid = 0;
while (left<=right){
mid=(left+right)/2;
if (nums[mid]<target){
left=mid+1;
}
else if(nums[mid]>target){
right=mid-1;
}
else{
return mid;
}
}
return left;
}
}
方法二:
思路:Python可以直接用bisect模块。
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
return bisect.bisect_left(nums,target)
69. x的平方根(简单)
题目要求
给你一个非负整数 x
,计算并返回 x
的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
来源:力扣(LeetCode)
链接:力扣
题解
方法一:暴力解决,从头开始算,直到找到
1.某个数的平方恰好=x,输出该数;2.某个数的平方<x,但(该数+1)的平方>x,输出该数。
但是,该方法时间超限。
class Solution:
def mySqrt(self, x: int) -> int:
if x==0 or x==1:
return x
else:
for cur in range(x):
if cur**2<x and (cur+1)**2>x:
return cur
elif cur**2==x:
return cur
方法二:直接用库函数。
import math
class Solution:
def mySqrt(self, x: int) -> int:
return int(math.sqrt(x))
方法三:牛顿法
牛顿法原理:若想求2的平方根,列公式f(x)=x^2-2。当f(x)=0时,x=根号2。
在f(x)上随便取一点,以(2,2)为例,在该点做f(x)的切线,列出切线方程y=4x-6,求该切线方程在y=0时候的x值,x=1.5,将所求x值带回f(x)=0.25,此时这点坐标为(切线方程和x轴交点,对应的f(x)值)=(1.5,0.25)。
此时对这个点做上述操作:求切线方程y=4x-5.75,切向方程与x轴交点x=1.4375。
可以发现切线方程与x轴的交点从x=1.5到x=1.4375,如果继续迭代,x会不断逼近根号二的真值1.4142……,如果最开始的初始值选择别的值,也不会耽误计算,影响的只是迭代次数。
参考链接(里面有图):如何手工开根号?(简述Newton-Raphson 法) - 知乎
数学部分讲完了,接下来是总结规律:
class Solution:
def mySqrt(self, x: int) -> int:
t=x
while t*t>x:
t=(t+x/t)//2
return int(t)
方法四:二分法
class Solution:
def mySqrt(self, x: int) -> int:
left,right=0,x+1
while left<=right:
mid=(left+right)//2
if mid**2>x:
right=mid-1
elif mid**2<x:
left=mid+1
else:
return mid
return left-1
牛顿法思路来源负雪明烛,参考链接:【LeetCode】69. Sqrt(x) 解题报告(Python & C++)_负雪明烛的博客-CSDN博客
367.有效的完全平方数(简单)
题目要求
给定一个 正整数 num ,编写一个函数,如果 num 是一个完全平方数,则返回 true ,否则返回 false 。
进阶:不要 使用任何内置的库函数,如 sqrt 。
来源:力扣(LeetCode)
链接:力扣
题解
方法一:二分法
class Solution:
def isPerfectSquare(self, num: int) -> bool:
left,right=0,num+1
while left<=right:
mid=(left+right)//2
if mid**2>num:
right=mid-1
elif mid**2<num:
left=mid+1
else:
return True
return False
方法二:利用完全平方数的性质(是从1开始若干连续奇数的和)
class Solution:
def isPerfectSquare(self, num: int) -> bool:
i=1
while num>0:
num-=i
i+=2
return num==0
方法三:牛顿法
class Solution:
def isPerfectSquare(self, num: int) -> bool:
t=num
while t**2>num:
t=(t+num/t)//2
return t**2==num
方法二(利用完全平方性质)、方法三(牛顿法)思路来源负雪明烛
参考链接:【LeetCode】367. Valid Perfect Square 解题报告(Java & Python)_负雪明烛的博客-CSDN博客
441.排列硬币(简单)
题目要求
你总共有 n 枚硬币,并计划将它们按阶梯状排列。对于一个由 k 行组成的阶梯,其第 i 行必须正好有 i 枚硬币。阶梯的最后一行 可能 是不完整的。
给你一个数字 n ,计算并返回可形成 完整阶梯行 的总行数。
来源:力扣(LeetCode)
链接:力扣
题解
方法一:暴力尝试,判断是否正好排布,如果正好就返回行数;如果不正好就返回行数-1。
class Solution:
def arrangeCoins(self, n: int) -> int:
row=0
while n>0:
row+=1
n-=row
if n==0:
return row
else:
return row-1
方法二:等差数列前n项和+二分法
#等差数列求和公式
sn=a1*n+n*(n-1)*d/2 # a1:第一项; d:公差
sn=(a1+an)*n/2 # an:第n项
class Solution:
def arrangeCoins(self, n: int) -> int:
left,right=0,n+1
while left<=right:
mid=(left+right)//2
sn=mid+mid*(mid-1)/2 # 等差数列求和公式,第一项a1=1,d=1,所以省略了
# 两个求和公式,用哪个都行
if sn>n:
right=mid-1
elif sn<n:
left=mid+1
else:
return mid
return left-1
方法三:等差数列前n项和,反向求解行数,并向下取整
sn=(a1+an)*n/2
2*sn=(1+n)*n
n**2+n+1/4=2*sn+1/4 # 中学数学,构成完全平方项
(n+1)**2=2*sn+1/4
n=math.sqrt(2*sn+1/4)-1/2 # 此处的sn是题目要求的目标值n
import math
class Solution:
def arrangeCoins(self, n: int) -> int:
return int(math.sqrt(2*n+1/4)-1/2)
33. 搜索旋转排序数组(中等)
题目要求
整数数组 nums 按升序排列,数组中的值 互不相同 。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。
来源:力扣(LeetCode)
链接:力扣
题解
二分法:根据二分法以mid为分界,划分数组左右两侧,使得各自有序,然后在用二分法在target满足的区间内进行寻找。
class Solution:
def search(self, nums: List[int], target: int) -> int:
left,right=0,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 and nums[left]<=target: # target在有序的左侧,则开始缩小区间搜索
right=mid-1
else: # target不在有序一侧,则重新划定有序区间
left=mid+1
else: #nums[mid]<nums[right]: 右侧有序
if nums[mid]<target and nums[right]>=target: # target在有序的右侧,则开始缩小区间搜索
left=mid+1
else: # target不在有序一侧,则重新划定有序区间
right=mid-1
return -1
二分法思路来源:负雪明烛。链接:【LeetCode】33. Search in Rotated Sorted Array 解题报告(Python & C++)_负雪明烛的博客-CSDN博客
34. 在排序数组中查找元素的第一个和最后一个位置(中等)
题目要求
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
来源:力扣(LeetCode)
链接:力扣
题解
二分法一:利用二分法找target,找到后确认与target相同的左右边界。
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
left,right=0,len(nums)-1
while left<=right:
mid=(left+right)//2
if nums[mid]>target:
right=mid-1
elif nums[mid]<target:
left=mid+1
else: # 当利用二分法找到target后,确认左右边界。
left,right=mid,mid # 以mid为中心向左右移动
# 指针左移直到找到与target不同的值(注意左边界不能超过0)
while left>-1 and nums[left]==nums[mid]:
left-=1
# 指针右移直到找到与target不同的值(注意右边界不能超过nums的长度)
while right<len(nums) and nums[right]==nums[mid]:
right+=1
return left+1,right-1
return -1,-1
二分法二:用python内置函数
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
left=bisect.bisect_left(nums,target) # left=第一个与target相同的元素下标
right=bisect.bisect_right(nums,target) # right=最后一个与target相同的元素下标+1
print("left= ",left,"right= ",right)
if left==right: #没找到target时,left=right=0
return -1,-1
return left,right-1
二分法三:定义两个函数,实现bisect_left,bisect_right。
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
left=self.lowwer_bound(nums,target)
right=self.higher_bound(nums,target)
if left==right:
return -1,-1
return left,right-1
# target存在时,返回第一个与target相同元素的下标;target不存在时,返回target插入位置。
def lowwer_bound(self,nums,target):
left,right=0,len(nums)-1
while left<=right:
mid=(left+right)//2
if nums[mid]<target: # 左右边界两个函数只在这个位置有区别
left=mid+1
else:
right=mid-1
return left
# target存在时,返回右侧第一个与target不同元素下标;target不存在时,返回target插入位置。
def higher_bound(self,nums,target):
left,right=0,len(nums)-1
while left<=right:
mid=(left+right)//2
if nums[mid]<=target: # 找到比target大的第一个数作为left
left=mid+1
else:
right=mid-1
return left # 此处返回是left作为右边界
二分法二,三参考负雪明烛,链接:【LeetCode】34. Find First and Last Position of Element in Sorted Array 解题报告(Python & C++)_负雪明烛的博客-CSDN博客
153.寻找旋转排序数组中的最小值(中等)
题目要求
已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]] 。
给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
来源:力扣(LeetCode)
链接:力扣
题解
二分法一:
class Solution:
def findMin(self, nums: List[int]) -> int:
n=len(nums)
left,right=0,n-1
while left<=right:
mid=(left+right)//2
if nums[mid]>nums[right]:
left=mid+1
elif nums[left]<=nums[mid]<=nums[right]: # left,mid,right是按照顺序排列的时候,返回left
return nums[left]
else: # nums[mid]<left:
right=mid
二分法二:思路类似负雪明烛方法三,传送门在下方。
class Solution:
def findMin(self, nums: List[int]) -> int:
n=len(nums)
if n==1:
return nums[0]
left,right=0,n-1
while nums[left]>nums[right]: # 当子序列也是经过旋转的时候,不断寻找有序的部分
if right==left+1: # 当左边界与有边界相邻的时候,返回右边界
return nums[right]
mid=(left+right)//2
if nums[mid]>nums[right]:
left=mid+1
else: # nums[mid]<nums[left]
right=mid
return nums[left]
二分法三:参考负雪明烛,传送门在下方。
参考链接:【LeetCode】153. Find Minimum in Rotated Sorted Array 解题报告(Python)_负雪明烛的博客-CSDN博客
162.寻找峰值(中等)
题目要求
峰值元素是指其值严格大于左右相邻值的元素。
给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。
来源:力扣(LeetCode)
链接:力扣
题解
二分法:参考负雪明烛
class Solution:
def findPeakElement(self, nums: List[int]) -> int:
n=len(nums)
if n==1:
return 0
left,right=0,n-1
while left<right:
mid=(left+right)//2
if nums[mid]<nums[mid+1]: # 找升序数组,逐渐逼近坡顶
left=mid+1
else: # nums[mid]>=nums[mid+1]的时候即为坡顶
right=mid
return left
参考链接:【LeetCode】162. Find Peak Element 解题报告(Python)_负雪明烛的博客-CSDN博客
4. 寻找两个正序(困难)
题目要求
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
来源:力扣(LeetCode)
链接:力扣
题解:
第一遍理解错了,搞了个求中值(代码就不放了),第二遍搞成了每个列表的中值再求平均(代码先放这里吧),但是题目是让我们合并数组的中值。干饭去了,明天接着弄。
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
nums1=self.median_array(nums1)
nums2=self.median_array(nums2)
nums1.extend(nums2)
nums1.sort()
n=len(nums1)
if n==0:
return 0
elif n==1:
return nums1[0]
elif n==3:
return nums1[1]
else:
return (nums1[n//2]+nums1[n//2-1])/2
def median_array(self,num):
n=len(num)
if n==0:
return []
if n==1:
return [num[0]]
mid=n//2
print(mid)
if n%2==0:
return [num[mid-1],num[mid]]
else:
return [num[mid]]
重新来过
方法一:两个数组合并,掉包排序,根据合并后的数组长度求中位数。
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
nums1.extend(nums2) # 合并数组
nums1.sort() # 排序
n=len(nums1)
if n%2==0: # 数组长度为偶数个,则返回中间两个数的平均值
return (nums1[n//2]+nums1[n//2-1])/2
else: # 数组长度为奇数个,则返回中间那个数
return nums1[n//2]
方法二:
排序
912.排序数组
题目要求
给你一个整数数组 nums
,请你将该数组升序排列。
题解&问题
方法一:快排,但是针对有序数组,快排的复杂度也会编程O(n^2),超出时间限制。
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
def partition(nums,left,right):
tmp=nums[left]
while left<right:
while left<right and nums[right]>=tmp:
right-=1
nums[left]=nums[right]
while left<right and nums[left]<=tmp:
left+=1
nums[right]=nums[left]
nums[left]=tmp
return left
def quicksort(nums,left,right):
if left<right:
mid=partition(nums,left,right)
quicksort(nums,left,mid-1)
quicksort(nums,mid+1,right)
quicksort(nums,0,len(nums)-1)
return nums
改进:
改进思路:针对有序数列倒是快排复杂度提高问题,随机选择初始值从数列的哪一侧开始。
问题:会不会随机的时候选择的刚好是顺序排列的那侧??
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
def partition(nums, low, high):
tmp_idx = random.randint(low, high) # 随机选择tmp
nums[low], nums[tmp_idx] = nums[tmp_idx], nums[low] # tmp放置到最左边
tmp = nums[low] # 选取最左边为tmp
left, right = low, high # 双指针
while left < right:
while left<right and nums[right] >= tmp:
right -= 1
nums[left] = nums[right]
while left<right and nums[left] <= tmp:
left += 1
nums[right] = nums[left]
nums[left] = tmp
return left
def quickSort(nums, low, high):
if low<high:
mid = partition(nums, low, high)
quickSort(nums, low, mid-1)
quickSort(nums, mid+1, high)
quickSort(nums, 0, len(nums)-1)
return nums
方法二:堆排序
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
#堆排,大根堆
def sift(nums,low,high):
i=low
j=2*i+1
tmp=nums[low]
while j<=high:
if j+1<=high and nums[j+1]>nums[j]:
j=j+1
if tmp<nums[j]:
nums[i]=nums[j]
i=j
j=2*i+1
else:
nums[i]=tmp
break
else:
nums[i]=tmp
def heap_sort(nums):
#建堆
n=len(nums)
for i in range((n-1-1)//2,-1,-1):
sift(nums,i,n-1)
#交换输出,向下调整
for j in range(n-1,-1,-1):
nums[0],nums[j]=nums[j],nums[0]
sift(nums,0,j-1)
heap_sort(nums)
return nums
双指针
26.删除有序数组中的重复项
题目要求
给你一个 升序排列 的数组 nums
,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
来源:力扣
链接:力扣
题解&问题
解题思路:(参考负雪明烛) 双指针:
1.慢指针指向存储位置;
2.快指针找非重复元素位置:元素重复则指针后移,不重复了就赋值。
写法一:
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
n=len(nums)
if n<=1:
return n
left,right=0,1 # left是不重复数据存放的位置
while right<n: # 在大循环中,right在条件内每次自动+1
while right<n and nums[left]==nums[right]: # 如果碰到相同的值,right+1
right+=1 # 排除重复元素干扰后的新right
left+=1 # 大循环中,left后移用于存放下一个不重复数据
if right<n:
nums[left]=nums[right] # 满足条件,更新left指向的数值
return left # 此时left所指的位置即为无重复子数组长度
同样思路,写法二:
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
n=len(nums)
if n<=1:
return n
left, right = 0, 1
while right<n:
if nums[left]!=nums[right]: # 元素不重复,则赋值
left+=1
nums[left]=nums[right]
right+=1 # 元素重复,则right后移
return left+1
参考链接:【LeetCode】26. Remove Duplicates from Sorted Array 解题报告(Python&C++&Java)_负雪明烛的博客-CSDN博客
注:示例中输出里面的下划线,代表不需要考虑那个元素是什么(因为本题是原地更新数组)。
输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。
动态规划
53.最大子数组和
题目要求
给你一个整数数组 nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
来源:力扣
链接:力扣
解题&问题:
方法一:暴力方法,把以当前数字开头的所有可能的和都存入sum_tmp,一共有len(nums)个sum_tmp。把每个sum_tmp中最大的值存入max_sum,最后返回max_sum的最大值即为所求。
class Solution:
def maxSubArray(self, nums) :
max_sum=[] # 以每个数开头的最大和
for i in range(len(nums)):
a=0
sum_tmp=[] # 以当前数字开头的所有和的可能
for j in range(i,len(nums)):
a+=nums[j]
sum_tmp.append(a)
he.append(max(sum_tmp))
return max(max_sum)
方法二:动态规划(思路来源负雪明烛)
找到(包含当前节点的)与之前节点构成的连续数组的最大和。
1.如果前一个节点的子数组最大和>0,那么当前节点的数组最大和=当前元素+前一节点的数组最大和,即dp[i] = dp[i-1] + nums[i]
2.如果前一个节点的子数组最大和<=0,那么当前节点自己的值就是最大的,即dp[i] = nums[i]。
# 以dp[i]结尾的最大子数组的和
# dp[i] = dp[i-1] + nums[i] 当 nums[i] >= 0
# dp[i] = nums[i] 当 nums[i] < 0
class Solution:
def maxSubArray(self, nums) :
pre,cur=0,0 # 指针从零开始
max_sum=float("-inf")# 最大子数组和(由于数组内元素可能为负值,所以第一次和负无穷比较)
for i in range(len(nums)):
if pre > 0: # 如果前一个节点的子数组最大和>0,那么当前节点的数组最大和=当前元素+前一节点的数组最大和
cur+=nums[i]
else: # 如果前一个节点的子数组最大和<=0,那么当前节点自己的值就是最大的
cur=nums[i]
pre=cur # 指针后移
max_sum=max(max_sum,cur) # 更新最大子数组和
return max_sum
负雪明烛原文链接:【LeetCode】53. Maximum Subarray 最大子序和 解题报告(Python & C++ & Java)_负雪明烛的博客-CSDN博客