基础算法python(1)

def quick_sort(l,r,data):
if l >= r:
return
i = l - 1 # 左端指针
j = r + 1 # 右端指针
pivot = data[(i+j) // 2] #中间值,随意取;但是一般选择中间值
while i < j:
while 1:
i += 1 # 左边指针向右移
if data[i] >= pivot: #找到不小于privot的然后break
break
while 1: # 右边指针向左移
j -= 1
if data[j] <= pivot: # 找到不大于privot的然后break
break
if i < j:
data[i],data[j] = data[j],data[i] # 如果此时i小于j,则交换
quick_sort(l,j,data) #对左边子区间进行排序
quick_sort(j+1,r,data) #对右半子区间进行排序

def main():
l = 0
r = n-1
quick_sort(l,r,data)

if name == “__main__”:
n = int(input()) #输入数组长度
data = [int(x) for x in input().split()] #输入数组
main()
print(’ '.join(list(map(str, data))))


###### 找到第k个数:


![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=%2FUsers%2Fmac%2FDocuments%2F%E5%AD%A6%E4%B9%A0%2Fpython%2FAlgorithm%2FAcwing_start%2Fimage-20240326203252589.png&pos_id=img-3CUM7bPJ-1711731100738)


答案:



n, k = map(int,input().split())
nums = list(map(int,input().split()))

def quick_sort(nums):
if (len(nums) <= 1): return nums;

privot = nums[len(nums) // 2]
left = [x for x in nums if x < privot]
mid = [x for x in nums if x == privot]
right = [x for x in nums if x > privot]
return quick_sort(left) + mid + quick_sort(right)

if name == “__main__”:
nums = quick_sort(nums)
print(nums[k -1])


#### 归并排序


区别于快排:快排的分界值可以是任意的


但是归并排序是**下标的中间值**


##### 核心:


一个是将数组一分为二,一个无序的数组成为两个数组.


另外一个操作就是,合二为一,将两个有序数组合并成为一个有序数组.


##### 方法:


1. 先一分为二
2. 递归排序
3. 归并,将左右两个有序序列合并为一个序列



def merge_sort(data, l, r): # 数组的两个边界是l\r
if l >= r:
return
mid = (l + r) // 2 # 划分数据
merge_sort(data, l, mid)
merge_sort(data, mid + 1, r)
tmp = [] # 创建一个临时列表
i = l
j = mid + 1
while (i <= mid) and (j <= r): # 两指针i/j向中间移动,比较数值,添加到tmp中
if data[i] <= data[j]:
tmp.append(data[i])
i += 1
else:
tmp.append(data[j])
j += 1
# 两数组合并
tmp += data[i:mid + 1] # 将左侧分区的所有元素添加到tmp列表中
tmp += data[j:r + 1] # 将右侧分区的所有元素添加到tmp列表中
data[l:r + 1] = tmp # tmp替换原来的data

if name == “__main__”:
n = int(input())
data = list(map(int,input().split()))
merge_sort(data, l, r)
print(merge_sort(0,n-1))


###### 逆序队数量:


![image-20240326221203414](https://img-blog.csdnimg.cn/img_convert/327bad8a00e0aade11a84b015831e93b.png)


##### 三类:


1. 逆序对都在左半边
2. 逆序对都在右半边
3. 逆序对都在两边都有


![image-20240326221727215](https://img-blog.csdnimg.cn/img_convert/f5794fbcb32203237b9f34c5b546d87d.png)



def merge_sort(l,r):
if l >= r:
return 0
mid = (l + r) // 2
i = l
j = mid + 1
tmp = []
num = merge_sort(l,mid) + merge_sort(mid+1,r)
while i <= mid and j <= r:
if data[i] <= data[j]:
tmp.append(data[i])
i += 1
else:
tmp.append(data[j])
j += 1
num += mid - i + 1 # 如果不满足,那么第一个数组中剩余的所有数,都会和它构成逆序对
tmp.extend(data[i:mid+1])
tmp.extend(data[j:r+1])
data[l:r+1] = tmp
return num

if name == “__main__”:
n = int(input())
data = list(map(int,input().split()))
print(merge_sort(0,n-1))


#### 二分


* ##### 整数二分:

 有单调性一定可以二分,可以二分的题不一定二分  
 找到某个性质,可以将区间一分为二,二分可以寻找边界


	1. 二分前,先将搜索范围分为两个部分并定义check函数以检验是否满足其中一个区间的性质
	2. l和r的范围内一定包含了最终的边界点
	3. 此模板更像是边界二分法
	
	 右边界:True: [mid,r];False:[l,mid-1]
	
	 左边界:True:[l,mid];False:[mid+1,r]
	4. **为什么寻找右边界(x⩽c)时,mid = (l+r+1) // 2,而寻找左边界(x⩾c)时,mid = (l+r) // 2**
	
	 因为寻找右边界…],需要不断往后移动,所以必须得向后多一位
	
	 因为寻找左边界[…,需要不断迁移,所以必须向前多一位
* 注意⚠️:所谓的二分算法,就是我们**知道当前的候选区间**中,一定存在我们要找到的答案,而且我们发现这个区间拥有**单调性质**此类的性质,那么我们可以**不停地缩减候选区间的范围**,达到排除无用答案的效果.


###### 数的范围:


![image-20240328165614324](https://img-blog.csdnimg.cn/img_convert/fd58e62fb6aa0473d4013f1b8631b9fb.png)



n,m=map(int,input().split())
data=list(map(int,input().split()))

def dichotomous(data,n,m):
while m:
target=int(input())
l=0
r=n-1
# 先寻找左边界,即>=target的分界点
while l<r:
mid=(l+r)//2 # 左边界
if data[mid]>=target:
r=mid
else:
l=mid+1
if data[l]!=target:
print(“-1-1”)
else:
print(l,end=" ")
l=0
r=n-1
# 寻找右边界,即<=target的分界点
while l<r:
mid=(l+r+1)//2 # 右边界
if data[mid]<=target:
l=mid
else:
r=mid-1
print(l)

if name == “__main__”:
for k in range(m):
dichotomous(data,n,m)


###### 数的三次方根


![image-20240328204002666](https://img-blog.csdnimg.cn/img_convert/1b14e2eaac487e58d8ca53a72981c833.png)



给定一个浮点数n,求它的三次方根

方法一 :没有用到二分法

def cubic_root(n):
if n>=0:
return “{:.6f}”.format(n ** (1/3))
else:
n = -n
root=format(n ** (1/3))
return “{:.6f}”.format(-float(root))

if name== ‘__main__’:
n = float(input())
print(cubic_root(n))


* ##### 浮点二分


除了上面有提到的整数二分法,这个题就是很典型的浮点数二分


⏰**整数二分和浮点数二分的区别:**  
 唯一区别是浮点数没有整除, 区间长度可以严格的缩小一半



> 
> l=mid;
> 
> 
> r=mid;
> 
> 
> 


过程:


1. 首先输入x在区间-10000~10000
2. 寻找p点(也就是x的三次方根)
3. 二分找边界值



if name == ‘__main__’:
n = float(input())
st = 0 # 标记位,用来标记n是否是负数
if n < 0:
st = 1
n = -n
l, r = 0, 100
while ((r - l) > 1e-8):
mid = (l + r) / 2.0
if (mid**3 >= n):
r = mid # 边界移动
else:
l = mid
if st:
l = -l
print(“{:.6f}”.format(l)) # 保留6位小数


#### 高精度


注意⚠️:其实python自带高精度哈哈哈!



print(int(input())-int(input()))
print(int(input())+int(input()))
print(int(input())*int(input()))
print(int(input())/int(input()))

这样输出也是高精度


##### 高精度加法


**思路:**  
 模拟手动加法计算



> 
> 例如计算:567 + 28
> 
> 
> 1. 先个位相加: 7 + 8 = 15,所以结果的个位是5,向十位进 1
> 2. 再十位相加: 6 + 2 + 1(进位)= 9, 所以十位是 9,向百位进 0
> 3. 再百位相加: 5 + 0 = 5, 所以结果的百位是 5
> 4. 综上,计算结果为 595
> 
> 
> 


**算法**:



> 
> 计算 567 + 28
> 
> 
> 1. 用 a, b 两个字符串存储输入。a = 567, b = 28
> 2. 为了方便计算,将两个数分别 倒序 存放在 A, B 两个整数数组中。 A = [7, 6, 5], B = [8, 2]
> 3. 新建整数数组 C 保存结果,整型变量 t 保存进位,初始 t = 0.
> 4. 将各个位上的数字相加,求出结果对应位上的数字和进位。
> 
>  例如对个位计算: A[0] + B[0] = 7 + 8 = 15, 结果个位上是 5, 进位是 1. 所以 C[0] = 5, 进位 t = 1
> 5. 最后把结果数组 C 中就保存了计算倒序结果,倒序输出就是答案
> 
> 
> 


**模版:**



高精度加法

a=list(input())
b=list(input())
def add(a,b):
a.reverse() # 倒叙相加嘛
b.reverse()
c = [0]*max(len(a),len(b)+1) # 生成一个长度为a和b中最长的数+1的数组
for i in range(len(a)):
c[i] = int(a[i])
for i in range(len(b)):
c[i] += int(b[i])
for i in range(len©-1):
if c[i] >= 10: # 如果c[i]大于10,则进位
c[i] -= 10
c[i+1] += 1
while len© > 1 and c[-1] == 0:
c.pop() # 如果最后一位是0,则删除(也就是最高位)
c.reverse()
combined = int(‘’.join(map(str, c))) # 将数组转化为字符串,再转化为整数
print(combined)

if name == ‘__main__’:
add(a,b)


##### 高精度减法


**思路:**


1. 减法的借位处理
2. 相减为负数处理
3. 高位为0处理


**模版:**



def subtract(a, b):
a.reverse()
b.reverse()
c = [0]*max(len(a),len(b)+1)
for i in range(len(a)):
c[i] = int(a[i])
for i in range(len(b)):
c[i] -= int(b[i])
for i in range(len©-1):
if c[i] < 0:
c[i] += 10
c[i+1] -= 1
while len© > 1 and c[-1] == 0:
c.pop()
c.reverse()
if c[0] == 0 and len© > 1:
c[0] = ‘-’
combined = ‘’.join(map(str, c))
else:
combined = int(‘’.join(map(str, c)))
return combined

if name == ‘__main__’:
a = list(input())
b = list(input())
combined2 = ‘’.join(map(str, a))
combined3 = ‘’.join(map(str, b))
if int(combined2) < int(combined3): #判断a和b的大小,如果a<b,则输出负数
num=0-subtract(b, a)
print(num)
else:
num=subtract(a, b)
print(num)


##### 高精度乘法


**思路:**


1. a/b循环相乘
2. 注意进位
3. 注意高位为0处理


**模版:**



def multiply(a, b):
a.reverse()
b.reverse()
c = [0]*(len(a)+len(b))
for i in range(len(a)): # 循环a
for j in range(len(b)): # 循环b
c[i+j] += int(a[i]) * int(b[j])
for i in range(len©-1):
c[i+1] += c[i] // 10 # 除以10的进位,这样直接取整就是进位,不用和10比较
c[i] %= 10 # 取余
while len© > 1 and c[-1] == 0:
c.pop()
c.reverse()
return ‘’.join(map(str, c))

if name == ‘__main__’:
a = list(input())
b = list(input())
print(multiply(a, b))


##### 高精度除法


**思路:**


1. a变为数组,b不变
2. 不需要倒置
3. 余数需要注意
4. 高位处理


**模版:**



def divide(a, b):
r = 0 # 余数
res = []
for i in range(len(a)):
r = r * 10 + int(a[i])
res.append(str(r // b)) # 商
r = r % b # 余数
while len(res) > 1 and res[0] == ‘0’:
res.pop(0)
return ‘’.join(res)

if name == ‘__main__’:
a = list(input())
b = int(input())
print(divide(a, b))


#### 前缀与差分


##### 前缀和:


什么是前缀和


原数组: a[1], a[2], a[3], a[4], a[5], …, a[n]  
 前缀和 Si为数组的前 i项和  
 前缀和: S[i] = a[1] + a[2] + a[3] + … + a[i]


注意: 前缀和的下标一定要从 1开始, 避免进行下标的转换



> 
> s[0] = 0  
>  s[1] = a[1]  
>  s[2] = a[1] + a[2]
> 
> 
> 


![image-20240329161207527](https://img-blog.csdnimg.cn/img_convert/0b65574b128675c3722f3622a529a143.png)


**作用:**  
 快速求出元素组中某段的和


###### 一维例题:


![image-20240329152010787](https://img-blog.csdnimg.cn/img_convert/b412196fb54d3ed3921996ef7d29f3c4.png)


**模版:**



n,m=map(int,input().split())
a=list(map(int,input().split()))

计算前缀和

prefix_sum = [0]*(n+1)
for i in range(1, n+1):
prefix_sum[i] = prefix_sum[i-1] + a[i-1]

def query(l, r):
return prefix_sum[r] - prefix_sum[l-1] # 返回区间和

if name == ‘__main__’:
for _ in range(m): # 这里_表示一个临时变量,不会被使用
l,r=map(int,input().split())
print(query(l,r))


###### 二维例题:


![image-20240329161512632](https://img-blog.csdnimg.cn/img_convert/38853acefb0dfc01dc9aa636e5026ab2.png)


**思路:**


1. S 
 
 
 [ 
 
 
 i 
 
 
 , 
 
 
 j 
 
 
 ] 
 
 
 
 S[i, j] 
 
 
 S[i,j] 即为图1红框中所有数的的和为:


 
 
 
 
 
 S 
 
 
 [ 
 
 
 i 
 
 
 , 
 
 
 j 
 
 
 ] 
 
 
 = 
 
 
 S 
 
 
 [ 
 
 
 i 
 
 
 , 
 
 
 j 
 
 
 − 
 
 
 1 
 
 
 ] 
 
 
 + 
 
 
 S 
 
 
 [ 
 
 
 i 
 
 
 − 
 
 
 1 
 
 
 , 
 
 
 j 
 
 
 ] 
 
 
 − 
 
 
 S 
 
 
 [ 
 
 
 i 
 
 
 − 
 
 
 1 
 
 
 , 
 
 
 j 
 
 
 − 
 
 
 1 
 
 
 ] 
 
 
 + 
 
 
 a 
 
 
 [ 
 
 
 i 
 
 
 , 
 
 
 j 
 
 
 ] 
 
 
 
 S[i, j]=S[i, j-1]+S[i-1, j]-S[i-1, j-1]+a[i, j] 
 
 
 S[i,j]=S[i,j−1]+S[i−1,j]−S[i−1,j−1]+a[i,j]


2. ( 
 
 
 
 x 
 
 
 1 
 
 
 
 , 
 
 
 
 y 
 
 
 1 
 
 
 
 ) 
 
 
 
 , 
 
 
 
 ( 
 
 
 
 x 
 
 
 2 
 
 
 
 , 
 
 
 
 y 
 
 
 2 
 
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

**深知大多数Python工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

**因此收集整理了一份《2024年Python开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

![img](https://img-blog.csdnimg.cn/img_convert/4e13e5b9e65485d196e9a575ffc9a5ed.png)

 

![img](https://img-blog.csdnimg.cn/img_convert/da7fb42162b62ba680743df124c2d767.png)

![img](https://img-blog.csdnimg.cn/img_convert/46506ae54be168b93cf63939786134ca.png)

![img](https://img-blog.csdnimg.cn/img_convert/252731a671c1fb70aad5355a2c5eeff0.png)

![img](https://img-blog.csdnimg.cn/img_convert/6c361282296f86381401c05e862fe4e9.png)

![img](https://img-blog.csdnimg.cn/img_convert/9f49b566129f47b8a67243c1008edf79.png)

 

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!**

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**

**如果你觉得这些内容对你有帮助,可以扫码获取!!!(备注Python)**

厂,18年进入阿里一直到现在。**

**深知大多数Python工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

**因此收集整理了一份《2024年Python开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

[外链图片转存中...(img-1iP2LP7v-1712671495939)]

 

[外链图片转存中...(img-R7d5GxAN-1712671495940)]

![img](https://img-blog.csdnimg.cn/img_convert/46506ae54be168b93cf63939786134ca.png)

![img](https://img-blog.csdnimg.cn/img_convert/252731a671c1fb70aad5355a2c5eeff0.png)

![img](https://img-blog.csdnimg.cn/img_convert/6c361282296f86381401c05e862fe4e9.png)

![img](https://img-blog.csdnimg.cn/img_convert/9f49b566129f47b8a67243c1008edf79.png)

 

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!**

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**

**如果你觉得这些内容对你有帮助,可以扫码获取!!!(备注Python)**

<img src="https://img-community.csdnimg.cn/images/fd6ebf0d450a4dbea7428752dc7ffd34.jpg" alt="img" style="zoom:50%;" />
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值