排序
快速排序
快排是不稳定的
快速排序采用的是分治的思想:
第二步进行区间的调整,最简单的做法是采取暴力的形式:
第二种做法:
第三种做法--优秀做法
分界点为x,i从左边查起,j从右边查起;i++,当i遇到一个大于等于x的值,停下;j--,当j遇到一个小于等于x的值,j停下,然后swap(q[i],q[j]),直到i==j,第一次查询结束,此时区间已经调整完毕
func quickSort(q []int,l int,r int) {
if l>=r {
return
}
x,i,j := q[l],l-1,r+1
for i < j {
for{ //类似于C++中的do...while循环
i++
if q[i] >= x {
break
}
}
for{
j--
if q[j] <= x {
break
}
}
if i < j {
swap(&q[i],&q[j])
}
}
quickSort(q,l,j)
quickSort(q,j+1,r)
}
func swap(a,b *int) {
*a,*b = *b,*a
}算法性能分析
归并排序
归并排序是稳定的
归并排序的中心思想也是分治
将两个已经排好序的数组合二为一,每次将两个数组进行比较,选择最小的那一个插入结果数组中
var n int
var q[]int
var temp [N]int
func mergeSort(q []int,l int,r int) {
if l >= r {
return
}
mid := (l + r) >> 1
mergeSort(q,l mid)
mergeSort(q,mid+1,r)
k,i,j := 0,l,mid+1
for i <= mid && j <= r {
if q[i]<=q[j] {
temp[k] = q[i]
k,i = k++,i++
}else{
temp[k] = q[j]
k,j = k++,j++
}
}
for i <= mid {
temp[k] = q[i]
k,i = k++,i++
}
for j <= r {
temp[k] == q[j]
k,j = k++,j++
}
//最后还需要把结果重新存回q数组中
for i,j = l,0 ; i<=r ;i,j = i++,j++ {
q[i] = temp[j]
}
}算法性能分析
二分
整数二分
找到一个性质,可以将整个区间一分为二,区间不一定非要满足单调的性质。
二分之后可以寻找边界点
1、寻找红色边界点
//区间[l,r]被划分成[l,mid-1]和[mid,r]时使用
func search_2(l,r int) int{
for l < r {
//这里是为了避免出现死循环的情况,比如l=r-1,此时如果不加1,则mid仍然等于l,因为这里是向下取整
mid := l + r + 1 >> 1
if check(mid) {
l = mid
}else{
r = mid-1
}
}
return l
}2、寻找绿色边界点
//区间[l,r]被划分为[l,mid]和[mid+1,r]时使用
func search_2(l,r int) int{
for(l<r){
mid := l + r >> 1
if check(mid){
r = mid
}else{
l = mid+1
}
}
return l
}浮点数二分
不需要处理边界问题
高精度
用数组将整数的每一位存进去,从低位开始存储
两个大整数相加(两数的位数<=10的6次方)
func add(A []int,B []int) []int{
var C []int
t := 0
for i := 0 ; i < len(A) || i < len(B) ; i++ {
if i < len(A){t += A[i]}
if i < len(B){t += B[i]}
C = append(C,t%10)
t = t / 10
}
if t > 0 {
C = append(C,t)
}
return C
}两个大整数相减(两数的位数<=10的6次方)
若A>=B则直接求A-B,否则求-(B-A )
func cmp(A []int,B []int) bool {
if len(A) != len(B){
return len(A) > len(B)
}
for i := len(A)-1; i >= 0 ; i-- {
if A[i] != B[i]{
return A[i] > B[i]
}
}
return true
}
//A>B
func sub(A []int,B []int) []int{
var C []int
for i,t := 0,0 ; i < len(A) ; i++ {
t = A[i] - t
if i < len(B){
t = t-B[i]
}
C = append(C,(t+10)%10)
if t < 0 {
t = 1
}else{
t = 0
}
}
for len(C) > 1 && C[len(C)-1] == 0 {
C = C[:len(C)-1]
}
return C
}一个大整数*一个较小的数(大数的位数<=10的6次方,小数<=10000)
用A的每一位分别和B相乘,再考虑后面的计算
func mul(A []int,b int) []int{
var C []int
t := 0 //这是进位
for i := 0 ; i < len(A) || t > 0 ; i++ {
if i < len(A) {
t += A[i]*b
}
C = append(C,t%10)
t = t / 10
}
return C
}一个大整数/一个较小的数
func div(A []int,b int) []int{
var C []int
t := 0
for i := len(A)-1 ; i >= 0 ; i++ {
t = t *10 + A[i]
C = append(C,t/b)
t = t % b
}
for len(C) > 1 && C[0] == 0 {
C = C[1:]
}
return C
}前缀和与差分
一维前缀和
前缀和:
for i := 1 ; i <= n ; i ++ {
S[i] = S[i-1] + a[i]
}作用:可以用来求一段区间内的和
求[l,r]上的和:S[r]-S[l-1]
var a []int = make([]int,N+1)
var s []int = make([]int,N+1)
s[0] = 0
func pre_sum(l,r int) int {
for i := 1 ; i <= N ; i++ {
s[i] = s[i-1] + a[i]
}
res := s[r] - s[l-1]
return res
}二维前缀和
Si,j是以(i,j)为界点的左上角所有元素的和
要求中间蓝色小矩形的和
var n int
var m int
var a [][]int = make([][m+1]int,n+1)
var s [][]int = make([][m+1]int,n+1)
func pre_Sum(x1 int,x2 int,y1 int,y2 int) int {
for i:= 1 ; i <= n ; i++ {
for j:= 1 ; j<= m ; j++{
s[i][j] = s[i][j-1] + s[i-1][j] - s[i-1][j-1] + a[i][j] //求前缀和
}
}
res := s[x2][y2] - s[x2][y1-1] - s[x1-1][y2] + s[x1-1][y1-1] //算子矩阵的和
return res
}
一维差分
已知数组a,构造数组b,使得数组a成为数组b的前缀和,则b就称为a的差分
用处:假如现在想让a[l]到a[r]内的数都加上一个常数c,那么只需要让b[l]+c并且b[r+1]-c即可
insert(i,i,a[i])是在构造差分数组b
二维差分
想让蓝色小方框内的元素都加常数c
位运算
操作一:n>>k & 1
n的二进制表示中第k位是几
操作二:lowbit操作
lowbit(x):返回二进制数x的最后一位1
x = 101000
lowbit(x) = 1000 (返回的是一个二进制数,该二进制数的最高位是1)
lowbit(x) = x & -x = x & (~x+1)
应用:用来统计x中1的个数
计算机在底层实现的时候是没有减法的,所以要利用加法来实现减法,因此负数要用补码来进行表示
离散化
值域跨度很大,但是值的个数很少
应用
区间合并
将所有有交集的区间合并成同一个区间
/*排序+合并
1.先对区间首部从小到大排序。
2.遍历、合并重合区间:
如果cs的尾部小于当前区间的头,即不相交,添加到结果集,并将尾部指到当前区间的尾部。
如果cs的尾部小于等于当前区间的尾,即有重合区域,合并: 将当前区间尾赋到cs的尾。
*/
func merge(intervals [][]int) [][]int {
var res [][]int
if len(intervals) == 0 || len(intervals[0]) == 0 {
return res
}
sort.Slice(intervals,func(i,j int)bool{
return intervals[i][0] < intervals[j][0]
})
l := intervals[0][0]
r := intervals[0][1]
i := 1
for i < len(intervals) {
if intervals[i][0] > r {
ans := []int{l,r}
res = append(res,ans)
l = intervals[i][0]
r = intervals[i][1]
}else{
r = max(r,intervals[i][1])
}
i++
}
res = append(res,[]int{l,r})
return res
}
func max(a,b int) int{
if a > b {
return a
}
return b
}
京公网安备 11010502036488号