数据结构-排序/二分查找
1.排序
实现归并排序、快速排序、插入排序、冒泡排序、选择排序、堆排序(选做)(完成leetcode上的返回滑动窗口中的最大值(239)
0.1 算法分类
排序算法可以分为两大类:
比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。
非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。
0.2 算法复杂度
0.3 相关概念
稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
空间复杂度:是指算法在计算机
内执行时所需存储空间的度量,它也是数据规模n的函数。
以上内容来自以下链接:
https://www.cnblogs.com/onepixel/articles/7674659.html
1.1 冒泡排序
冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
1.1 算法描述
- 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
- 针对所有的元素重复以上的步骤,除了最后一个;
- 重复步骤1~3,直到排序完成。
1.2 代码实现
# In[]
def bubbling_sort(lista):
for i in range(len(lista)-1):
for j in range(len(lista)-i-1):
if lista[j]>lista[j+1]:
temp=lista[j]
lista[j]=lista[j+1]
lista[j+1]=temp
return lista
listb=bubbling_sort(lista)
1.2 快速排序
上面参考链接详细展示了十大经典排序算法(动图演示)快速排序法的核心思想是选定一个基准点后,两个哨兵往中间移动,对比与基准点的大小关系来决定是否要交换数值。一般来说,基准点是最左端的位置,当然也可以产生随机基准点。、、
注意要右边先移动,次序很重要
详细的原理解析见参考链接:
https://blog.csdn.net/sinat_20177327/article/details/76560079#commentBox
def swap(arr,a,b):
temp=arr[a]
arr[a] = arr[b]
arr[b] = temp
return arr
def fastsort(arr,left,right):
if left>=right:
return
i=left
j=right
temp=arr[left]
while i!=j:
while arr[j]>=temp and i<j: # 右边的先动,这个很关键
j-=1
while arr[i]<=temp and i<j:
i+=1
if i<j:
swap(arr,i,j)
if arr[i]<temp: ## i==j时,判断相遇点与temp(基准)的大小
swap(arr,left,i)
fastsort(arr,left,i-1)
fastsort(arr,i+1,right)
# In[]
#arr=[7,6,5,8]
arr = [1,4,7,2,3,6,5,8]
fastsort(arr,0,len(arr)-1)
参考链接:
https://blog.csdn.net/sinat_20177327/article/details/76560079#commentBox
还有 堆排序、 归并排序、插入排序、选择排序等,后续再展开
1.3 滑动窗口中的最大值
leetcode上的返回滑动窗口中的最大值(239)
这题目用python 来写真的挺简单的
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
s=[]
if nums==[]:
return []
elif len(nums)<=k:
s.append(max(nums))
return s
else:
for i in range(len(nums)-k+1):
s.append(max(nums[i:i+k]))
return(s)
1.4 第K 大元素
编程实现 O(n) 时间复杂度内找到一组数据的第 K 大元素(面试遇到了此问题)
结合快速排序法,排完第一轮后, left 和 right 指针相遇时,判断一下后半段的长度L与K 的大小关系,如果K 值比L 大,那么从左半段中继续寻找(K-L)大值,否则,从右半段中寻找第K大元素 开始新一轮的快速排序,直到找完第K大元素。
def swap(arr,a,b):
temp=arr[a]
arr[a] = arr[b]
arr[b] = temp
return arr
def Find_Max_K(arr,left,right,K):
# if left>=right:
# return
i=left
j=right
temp=arr[left]
while i!=j:
while arr[j]>=temp and i<j: # 右边的先动,这个很关键
j-=1
while arr[i]<=temp and i<j:
i+=1
if i<j:
swap(arr,i,j)
if arr[i]<temp: ## i==j时,判断相遇点与temp(基准)的大小
swap(arr,left,i)
if i==K:
print("第%d大值是:%d"%((len(arr)-K),arr[i]))
return i
elif i<K:
Find_Max_K(arr,i+1,right,K)
else:
Find_Max_K(arr,left,i-1,K)
# In[]
#arr=[7,6,5,8]
arr = [4,1,2,7,9,3,6,5,10,8]
mark=2
K=len(arr)-mark
Find_Max_K(arr,0,len(arr)-1,K)
2. 二分查找
二分查找常用的有这么七种:
①是否 存在数字t ——返回下标或者-1
②找到 大于t的第一个数 ——返回下标或者-1
③找到 大于等于t的第一个数 ——返回下标或者-1
④找到 小于t的第一个数 ——返回下标或者-1
⑤找到 小于等于 t的第一个数 ——返回下标或者-1
⑥是否 存在数字t,返回 第一个t ——返回下标或者-1
⑦是否 存在数字t,返回 最后一个t ——返回下标或者-1
2.1 代码实现
①是否 存在数字t ——返回下标或者-1
这是最简单原始的二分查找
# In[] 是否 存在数字t ——返回下标或者 False
def findData(lista,target):
left=0
right=len(lista)
m_last=0
while left<=right:
m=int((left+right)/2)
if m_last==m:
break
if lista[m]==target:
return m
elif lista[m]<target:
left=m
else:
right=m
m_last=m
return False
print(findData(lista,target))
②找到 大于t的第一个数 ——返回下标或者-1
# In[] 找出大于t的第一个数
def findData_2(lista,target):
left=0
right=len(lista)
m_last=0
# mark=0
while left<=right:
m=int((left+right)/2)
if m_last==m or lista[m]==target:
break
elif lista[m]<target:
left=m
else:
right=m
m_last=m
if m==len(lista):
return m
else:
while m<len(lista):
if lista[m]>target:
return m
m+=1
return False
print(findData_2(lista,target))
③找到 大于等于t的第一个数 ——返回下标或者-1
# In[] 找出大于等于t的第一个数
def findData_3(lista,target):
left=0
right=len(lista)
m_last=0
# mark=0
while left<=right:
m=int((left+right)/2)
if m_last==m or lista[m]==target:
break
elif lista[m]<target:
left=m
else:
right=m
m_last=m
if lista[m]==target: # 当前位置的值是target,往前去寻找第一个target 值
while m>=0:
if lista[m]<target:
return m+1
m-=1
else:
while m<len(lista): # 没有找到等于target值的位置,往前找第一个大于target值的数
if lista[m]>target:
return m
m+=1
return False
print(findData_3(lista,target))
④找到小于的第一个数 ——返回下标或者-1
# In[] 找到 小于t的第一个数 ——返回下标或者-1
def findData_4(lista,target):
left=0
right=len(lista)
m_last=0
# mark=0
while left<=right:
m=int((left+right)/2)
if m_last==m or lista[m]==target:
break
elif lista[m]<target:
left=m
else:
right=m
m_last=m
if m==0:
if lista[m]<target: #若当前位置是第一位,且数值比target值小,那么返回第一位,否则False
return m
else:
return False
else:
while m>=0: #若当前位置不是第一位, 向前找出最靠近target的一位
if lista[m]<target:
return m
m-=1
return False
print(findData_4(lista,target))
⑤找到小于等于 t的第一个数 ——返回下标或者-1
# In[] 找到 小于等于t的第一个数 ——返回下标或者-1
def findData_5(lista,target):
left=0
right=len(lista)
m_last=0
# mark=0
while left<=right:
m=int((left+right)/2)
if m_last==m or lista[m]==target:
break
elif lista[m]<target:
left=m
else:
right=m
m_last=m
print(m)
if m==0:
if lista[m]<=target:
return m
else:
return False # 当前位置的值是target,往前去寻找第一个target 值
else:
if lista[m]==target: # 当前位置的值是target,往前去寻找第一个target 值
while m>=0:
if lista[m]<target:
return m+1
print(m)
m-=1
else:
while m>=0: # 没有找到等于target值的位置,往前找第一个小于target值的数
if lista[m]<target:
return m
m-=1
return False
print(findData_5(lista,target))
⑥是否 存在数字t,返回 第一个t ——返回下标或者-1
# In[] 是否 存在数字t,返回 第一个t ——返回下标或者-1
def findData_6(lista,target):
left=0
right=len(lista)
m_last=0
# mark=0
while left<=right:
m=int((left+right)/2)
if m_last==m or lista[m]==target:
break
elif lista[m]<target:
left=m
else:
right=m
m_last=m
if lista[m]==target: # 当前位置的值是target,往前去寻找第一个target 值
while m>=0:
if lista[m]<target:
return m+1
m-=1
else:
return False ## 没有找到该值,返回-1
print(findData_6(lista,target))
⑦是否 存在数字t,返回 最后一个t ——返回下标或者-1
# In[] 是否 存在数字t,返回 最后t ——返回下标或者-1
def findData_7(lista,target):
left=0
right=len(lista)
m_last=0
# mark=0
while left<=right:
m=int((left+right)/2)
if m_last==m or lista[m]==target:
break
elif lista[m]<target:
left=m
else:
right=m
m_last=m
if lista[m]==target: # 当前位置的值是target,往后去寻找最后target 值
if m==len(lista): # 若当前位置已是最末端,return
return m
else:
while m<len(lista):
if lista[m]>target:
return m-1
m+=1
else:
return False ## 没有找到该值,返回-1
print(findData_7(lista,target))
参考链接
https://blog.csdn.net/Hide_in_Code/article/details/76549317
2.7 sqrt函数的实现
Sqrt(x) (x 的平方根)
英文版:https://leetcode.com/problems/sqrtx/
中文版:https://leetcode-cn.com/problems/sqrtx/
class Solution:
def mySqrt(self, x: int) -> int:
if x==1 or x==0:
return x
else:
left=0
right=x
while left<right:
temp=(left+right)/2
if int(temp)**2<=x and int((temp+1))**2>=x:
if int((temp+1))**2==x:
temp=int((temp+1))
return(int(temp))
break
elif int(temp)**2<x and int(temp+1)**2<x:
left=temp
else:
right=temp