AcWing 算法基础课第一节基础算法1排序、二分
1、该系列为ACWing中算法基础课,已购买正版,课程作者为yxc
2、y总培训真的是业界良心,大家有时间可以报一下
3、为啥写在这儿,问就是oneNote的内存不够了QAQ
ACwing C++ 算法笔记1 基础算法
- 一、排序
- 1.1 快排
- 1.2 归并排序
- 1.3 快速选择算法
- 二、二分
- 2.1 整数二分
- 2.2 浮点数二分
本节内容:排序(快排、归并排序)、二分(整数二分、浮点数二分)
一、排序
排序算法中稳定:如果说原序列中两个值是相同的,排完序后两个值的位置不发生变化则是稳定的,可能发生变化就是不稳定的。
推荐阅读:十大排序算法(力扣)、十大排序算法总结(ACWing)
1.1 快排
- 快排基于分治的思想,是不稳定的算法,但是如果将快排的 a i a_{i} ai变为 < a i , i > <a_{i},i> <ai,i>的二元组(相同的数变为不同的数),就是稳定的算法;
- 时间复杂度为
O(NlogN)
,最坏N^2
- 快排的步骤:
- 确定分界点:
- 确定分界点的常用方式:(1) 直接取左边界
q[l]
;(2) 取两端的中间点q[(l+r)/2]
,(3) 取右边界q[r]
;(4) 取随机点;
- 调整区间:(假设确定
x
为分界点)满足小于等于x
的在左边,大于等于x
的在右边;
- 调整区间:(假设确定
- 递归:递归的处理左右两段区间;
=============================================================
调整区间的简单实现方法1(暴力做法但时间复杂度是线性的):
- 1、先开两个额外的数组
a[],b[]
; - 2、扫描整个区间
q[l-r]
,小于等于x插到a,大于x插到b; - 3、将数组
a[],b[]
的数据放入q[]
中;
- 1、先开两个额外的数组
调整区间的实现方法2(双指针):
- 1、用两个指针
i,j
,从两边同时向中间走; - 2、先开始移动
i
,i
指向的数字小于x,则i
后移一位;直到如果数字大于等于x
(应该放在右边),则停止移动i
,开始持续移动j
; - 3、当
j
指向的数大于x
,持续移动j
;当j
指向的数小于x
,i,j
的数字错位(此时i
指向的数需要放到右边,j
指向的数需要放到左边),交换i,j
指向的两个数字,并继续移动i,j
,直到两个指针相遇;(注意,这里不需要交换的两个数字在新的区间里是有顺序的,它的顺序会在下一次递归里进行排序)
- 1、用两个指针
快排代码实现:
在C++输入大量的数字时建议用scanf
,而不是cin
;同理,JAVA中不用sanner
,而是BufferedReader
#include <iostream>using namespace std;const int N = 100010;int q[N];void quick_sort(int q[], int l, int r)
{if (l >= r) return;// 判断边界:没有数或只有1个数就returnint i = l - 1, j = r + 1, x = q[l + r >> 1];// 两侧和中间的指针while (i < j){do i ++ ; while (q[i] < x); // q[i] <= x 会发生数组越界do j -- ; while (q[j] > x);if (i < j) swap(q[i], q[j]);// 或设置第三个变量交换}quick_sort(q, l, j); quick_sort(q, j + 1, r);
}int main()
{int n;scanf("%d", &n);for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]);quick_sort(q, 0, n - 1);for (int i = 0; i < n; i ++ ) printf("%d ", q[i]);return 0;
}
注意循环
while (q[i] < x)
不能写为q[i]<=x
,否则会一直满足<=
关键值得这个条件,就会发生数组越界(如49,59,88, 37,98,97,68,54,31,3,其中x=98)两个指针交换完之后都要移动一格,因此设计
i
,j
都在边界外,不管三七二十一先移动左右指针,再判断;x可以取
q[l]
、q[(l+r)/2]
、q[r]
;如果在
quick_sort(q, l, j); quick_sort(q, j + 1, r);
时取x = r
;或在quick_sort(q, l, i-1); quick_sort(q, i, r);
时取x = l
会面临边界造成的quick_sort()
函数递归死循环的问题。例如长度为2的区间[1, 2]
,如果取x = q[l]
,那么划分结束后会分成一个长度是0的区间quick_sort(q, l, i-1)——>quick_sort(q, 0, -1)
和一个长度是2的区间quick_sort(q, i, r)——>quick_sort(q, 0, 1)
,就无限递归了。具体代码如下:以
j
为中间点:
以
i
为中间点:
注意:由于使用
do-while
循环,所以i
和j
一定会自增!!,使得循环会继续下去,但是如果采用while
循环(i
和j
的初始化做出对应的变更),i
和j
在特殊情况下不自增的话,循环就会卡死;在循环中产生的边界问题:
quick_sort(a, l, j); quick_sort(a, j + 1, r);
为什么不能换成quick_sort(a, l, i); quick_sort(a, i + 1, r)
(即将 j+1 换成 i+1 作为中间区域的边界 / 为什么不能将 i-1 换为 j-1)?- 比如
x=3, 一段数 ,2,4,5,*
,此时i走到了4下面,j走到了2下面,quick_sort(a, l, i);
中,左边区间包括了一个大于x=3的4,会导致排序错误。所以如果是 i 的话,i 要包括在右边区间里面,也就是quick_sort(a, l, i-1); quick_sort(a, i, r);
- 比如
do i++; while(q[i] < x)
和do j--; while(q[j] > x)
不能用q[i] <= x
和q[j] >= x
- 假设
q[l..r]
全相等则执行完do i++; while(q[i] <= x);
之后,i
会自增到r+1
;然后继续执行q[i] <= x
判断条件,造成数组下标越界(但这貌似不会报错) 并且如果之后的q[i] <= x
(此时i > r
) 条件也不幸成立,就会造成一直循环下去,造成内存超限(Memory Limit Exceeded)
- 假设
- while循环代替do-while:用
while(q[i] < x) i++;
和while(q[j] > x) j--;
判断, 当q[i]
和q[j]
都为 x 时,i
和j
都不会更新,导致 while 陷入死循环。(应改为while(q[i] <= x) i++;
while(q[j] >= x) j--;
)。可以代替为以下代码,这样即使循环结束时q[i]==q[j]==x
,i,j
也能更新。
另一种快排方法
int partition( int[] nums, int left, int right)
{int pivot = nums[left]; // 左边第一个数为基准数int i = left + 1;int j = right;while(true){ //向右遍历扫描while(i <= j && nums[i] <= pivot) i++;//向左遍历扫描while(i <= j && nums[j] => pivot) j--;if(i >= j)break;//交换int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}//把nums[j]和基准数交换nums[left] = nums[j];nums[j] = povit;return j;
}void quickSort(int[] nums, int l, int r) {// 子数组长度为 1 时终止递归if (l >= r) return;// 哨兵划分操作int i = partition(nums, l, r);// 递归左(右)子数组执行哨兵划分quickSort(nums, l, i - 1);quickSort(nums, i + 1, r);
}// 调用
int main()
{vector<int> nums = { 4, 1, 3, 2, 5, 1};quickSort(nums, 0, nums.size() - 1);for (int i = 0; i < nums.size(); i ++ ) printf("%d ", nums[i]);return 0;
}
- 快排的边界问题:取中间区域的值作为基准值也需要考虑向上还是向下取整的问题,想要用
i - 1 和 i
的话,需要用x = q[l + r + 1 >> 1]
或x = q[r]
作为基准值;用j 和 j + 1
的时候,需要用x = q[l + r >> 1]
或x = q[l]
。
============================================================================================
java模板1
import java.util.*; import java.io.*; public class Main{public static void main(String[] args) throws IOException{BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));int n = Integer.parseInt(reader.readLine());int[] arr = new int[n];String[] strs = reader.readLine().split(" ");for(int i = 0; i < n; i++){arr[i] = Integer.parseInt(strs[i]);}quickSort(arr, 0, arr.length - 1);for(int i = 0; i < arr.length; i++){System.out.print(arr[i] + " ");}reader.close();}public static void quickSort(int[] arr, int start, int end){if(start < end){int low = start;int high = end;int stard = arr[start];while(low < high){while(low < high && stard <= arr[high]){high--;}arr[low] = arr[high];while(low < high && arr[low] <= stard){low++;}arr[high] = arr[low];}arr[low] = stard;quickSort(arr, start, low);quickSort(arr, low+1 ,end);}} }
java模板2
public class Main {public static void main(String[] args) throws IOException {// 输入BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));int n = Integer.parseInt(reader.readLine());int[] arr = new int[n];String[] strs = reader.readLine().split(" ");for( int i=0; i<n;i++){arr[i] = Integer.parseInt(strs[i]);}quickSort(arr, 0, arr.length-1);// 输出for(int i = 0; i< arr.length;i++){System.out.print(arr[i]+ " ");}reader.close();}public static void quickSort(int[] arr, int start , int end) {if (start >= end) return;int left = start - 1, right = end + 1, mid = arr[start+((end-start) >> 1)];while (left < right) {do {left++;} while (arr[left] < mid);do {right--;} while (arr[right] > mid);if (left < right) {int tmp = arr[left];arr[left] = arr[right];arr[right] = tmp;}}quickSort(arr, start, right);quickSort(arr, right + 1, end);} }
问题证明:快速排序算法的证明与边界分析
快排虽然每次划分的区间不一定恰好是
N/2
,但是期望是N/2
的,此情况下其递归的层数期望也是 l o g 2 N log_{2}N log2N的。
1.2 归并排序
归并的基本思想也是分治,时间复杂度为
O(Nlog(N))
,且算法是稳定的。归并的步骤:
- 找分界点,以中间点为分界线,归并是先递归再分别处理(快排是先分两边再递归)
- 递归排序左边和右边,两边变为有序的链表;
- 归并,将两个有序的数组合并为一个有序的数组;
归并两个有序数组的方法(暴力方法)
- 比较两个指针位置的数的大小,找到两个数组中的最小值,直到一个指针到达终点,可以把剩下的补到结果里(新开一个存结果的数组);
- 在归并两个数组过程中,一个指针最多扫描一半的数组,因此总共扫描长度为
O(N)
,每个元素只会被比较一次,时间复杂度为O(N)
;该步骤只是算法中的递归一次执行的;
算法时间复杂度
O(Nlog(N))
的具体计算:数组为n,需要除 log 2 n \log_{2}n log2n次才能除到1,因此共有 log 2 n \log_{2}n log2n层,每一层的时间复杂度为O(n)
,因此总共O(Nlog(N))
。
C++模板
#include <iostream> using namespace std;const int N = 1000010;int q[N], tmp[N]; void merge_sort(int q[], int l, int r) {if (l >= r) return; // 元素个数是1或没有元素;int mid = l + r >> 1;merge_sort(q, l, mid), merge_sort(q, mid + 1, r);// 归并int k = 0, i = l, j = mid + 1; // k是当前已经合并的数目,ij是左右指针while (i <= mid && j <= r)if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ]; // 如果左半部分现在指的数小于右半部分,tmp[k] = q[i]; k++, j++;else tmp[k ++ ] = q[j ++ ]; // 右半部分现在指的数小于左半部分;// 处理未循环完的部分;while (i <= mid) tmp[k ++ ] = q[i ++ ];while (j <= r) tmp[k ++ ] = q[j ++ ];// 复制结果,将tmp[0..r-l+1]复制到q[l..r]中for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j]; }int main() {int n;scanf("%d", &n);for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);merge_sort(a, 0, n - 1);for (int i = 0; i < n; i ++ ) printf("%d ", a[i]);return 0; }
归并排序求逆序对:
- 将所有的逆序对分为三大类:
- (1)两个数同时出现在左半边;
- (2)两个数同时出现在右半边;
- (3)一个在左半边,一个在右半边;
- 假定归并排序的函数可以在整个区间排好序的同时,求出区间内部所有逆序对的个数(
Sj = mid-i+1
)从i
到mid
都比j
大。逆序对的个数最坏情况下是n*(n-1)/2
#include <iostream>using namespace std;typedef long long LL;const int N = 100010; int n; int q[N], tmp[N];LL merge_sort(int l, int r) {if(l>=r) return 0; // 或(l==r)int mid = l+r >> 1;LL res = merge_sort(l, mid) + merge_sort(mid+1, r);// 归并的过程int k = 0, i = l, j = mid+1;while(i<=mid && j <=r)if(q[i]<=q[j]) tmp[k++] = q[i++]; // 如果左半部分现在指的数小于右半部分else{tmp[k++] = q[j++]; // 右半部分现在指的数小于左半部分(i到mid的数都大于j);res+=mid-i+1;}//处理未循环完的部分while(i<=mid) tmp[k++] = q[i++];while(j<= r) tmp[k++] = q[j++];//物归原主,i循环原始数组,j循环临时数组for (int i = l, j=0; i <= r; i ++, j++ ) q[i] = tmp[j];return res; }int main() {cin >> n;for (int i = 0; i < n; i ++) cin >> q[i];cout << merge_sort(0, n-1) << endl;return 0; }
1.3 快速选择算法
快速选择算法的时间复杂度是O(n)(依次处理的区间长度为
n+n/2+n/4+... <= 2n
)。快速选择算法的含义是:
首先对数组进行快速排序(找到分界点;左边所有数left <=x, 右边所有数 right >=x,中间值不一定等于x;递归排序 left,递归排序 right)(Sl和Sr是左右两边数的数量)
其次选择k,如果
k<=Sl
,则递归左半边;反之,k>Sr
递归右半边,找k-Sl
的数
与快排的不同在于快排需要递归两边,快速选择每次只需要递归一边。
举例:给定一个长度为 n 的整数数列,以及一个整数 k,请用快速选择算法求出数列从小到大排序后的第 k 个数。
do-while循环,这里将第k个数转化为找k-1的下标 #include <iostream> #include <vector>using namespace std; vector<int> a;int quick_sort(int l, int r, int k) {if(l >= r) return a[k];int x = a[l], i = l - 1, j = r + 1;while (i < j) {do i++; while (a[i] < x);do j--; while (a[j] > x);if (i < j) swap(a[i], a[j]);}if (k <= j) return quick_sort(l, j, k);else return quick_sort(j + 1, r, k); }int main() {int n, k;cin >> n >> k;a = vector<int>(n, 0);for (int i = 0; i < n; i++) {cin >> a[i];}cout << quick_sort(0, n - 1, k - 1) << endl;return 0; }
while循环 #include <iostream>using namespace std;const int N = 100010; int n, k; int q[N];int quick_sort(int l, int r, int k) {if(l == r) return q[l];int x = q[l], i= l-1, j = r+1;while(i<j){while( q[++i] < x);while( q[--j] > x);if(i<j) swap(q[i], q[j]);}//查看左边数的数量int sl = j-l+1;if(k <= sl) return quick_sort(l, j, k);return quick_sort(j+1, r, k-sl); }int main() {cin >> n >> k;for (int i = 0; i < n; i ++ ) cin >> q[i];cout << quick_sort(0, n-1, k) << endl;return 0; }
快速选择算法里可以写
if(l == r) return q[l];
或if(l >= r) return q[l];
;但是在快排里必须写if(l == r) return q[l];
,因为在快排里区间可能是没有数的(即出现l>r
的情况)
二、二分
2.1 整数二分
整数二分的本质不是单调性:如果有单调性,那么一定可以二分,但是可以二分的题目不一定非要单调性。
整数二分的本质是边界:假设给定一个区间
[l,r]
,我们在区间中定义了某种性质。使得在右半边区间是满足的,在左半边区间是不满足的,整个区间可以被一分为二,二分可以寻找性质的边界(两个边界都可以)。(即找到一个性质,可以将数据一分为二)
整数二分需要注意边界问题。
整数二分有两个模板,分别适用不同的情况。两个模板核心的区别是
int mid = l + r + 1 >> 1;
要不要加一,代表了两个区域的边界点;首先讨论寻找红色区域的边界点:
- 1、找到中间点
mid = (l+r+1)/2
,并判断中间值是否满足该性质if (check(mid))
,check
为true
说明满足条件,中间值在红色区间,答案在[mid, r]
,更新方式是将[l, r]
区间更新为[mid, r]
区间(l = mid
);2、check
为false
说明,mid
取在绿色区域,答案在[l, mid-1]
,更新方式是将[l, r]
区间更新为[l, mid-1]
区间(r = mid-1
)。
- 1、找到中间点
其次讨论寻找绿色的边界点:
- 1、求
mid =(l+r)/2
并if (check(mid))
是否满足绿色的性质check
为true
说明满足条件,中间值在绿色区间,答案在[l, mid]
,更新方式是将[l, r]
区间更新为[l, mid]
区间(r = mid
);2、check
为false
说明,mid
取在红色区域,答案在[mid+1, r]
,更新方式是将[l, r]
区间更新为[mid+1, r]
区间(l = mid+1
)。
- 1、求
因此选择两个模板是看
l
还是r
等于mid
;// check 函数 bool check(int x) {/* ... */} // 检查x是否满足某种性质// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用: // mid 属于左半边 int bsearch_1(int l, int r) {while (l < r){int mid = l + r >> 1;if (check(mid)) r = mid; // check()判断mid是否满足性质else l = mid + 1;}return l; }// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用: // mid 属于右半边 int bsearch_2(int l, int r) {while (l < r){int mid = l + r + 1 >> 1;if (check(mid)) l = mid;else r = mid - 1;}return l; }
为什么
mid
要加一:- c++整数除法是下取整,当
l = r-1
时,如果mid = (l+r)/2
则mid=l
,如果寻找红色边界且check
返回true
那么区间更新为[mid, r], l = mid => l
,边界进入死循环; - 因此当
mid = (l+r+1)/2
,相同情况下mid=r
不会死循环。
- c++整数除法是下取整,当
举例(数的范围):
- 给定一个按照升序排列的长度为 n 的整数数组,以及 q 个查询。对于每个查询,返回一个元素 k 的起始位置和终止位置(位置从 0 开始计数)。如果数组中不存在该元素,则返回
-1 -1
。 - 输入格式,第一行包含整数 n 和 q,表示数组长度和询问个数。第二行包含 n 个整数(均在 1∼10000 范围内),表示完整数组。接下来 q 行,每行包含一个整数 k,表示一个询问元素。
- 输出格式。共 q 行,每行包含两个整数,表示所求元素的起始位置和终止位置。如果数组中不存在该元素,则返回
-1 -1
。
- 给定一个按照升序排列的长度为 n 的整数数组,以及 q 个查询。对于每个查询,返回一个元素 k 的起始位置和终止位置(位置从 0 开始计数)。如果数组中不存在该元素,则返回
#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;const int N = 100010;int n, m;
int q[N];int main()
{scanf("%d%d", &n, &m);for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]);while(m --){int x;scanf("%d", &x);int l = 0, r = n-1;// 查询左端点while(l < r){// x以后所有数大于等于x;int mid = l+r >> 1;if (q[mid] >=x) r = mid; else l = mid+1;}if(q[l] != x) cout<< "-1 -1"<< endl;// 如果用q[l]>x来判断,当数组中所有数都小于x时,判断就错了else {cout << l << ' ';// 查询右端点int l = 0, r = n-1;while (l<r){int mid = l+r+1 >>1;if(q[mid] <=x) l = mid;else r = mid - 1;}cout << l << endl;}}return 0;
}
2.2 浮点数二分
浮点数二分本质上也是一个边界,但没有整除,每次区间可以严格的缩小一半。
当区间长度很小时(
r-l<= 10-e^6
),认为找到了答案。浮点数二分需要注意,当求一个浮点数的平方根时,右边界需要扩大,否则二分会产生问题。(如浮点数
x=0.01
,平方根是0.1,不在0-0.01之间,需要将右边界改为x+1
或max(1, x)
,不能直接取右边界为x
)举例,开平方:
#include <iostream>using namespace std;int main()
{double x;cin >> x;double l = 0, r = 100; // r不能等于x,x的二次方根一定在这个区间里;while ( r-l >1e-6){double mid= (l+r)/2;if(mid*mid >= x) r = mid;else l = mid;}printf("%lf\n", l);return 0;
}
保留4位小数需要
r-l >1e-6
,保留5位小数需要r-l >1e-7
;保留6位小数需要r-l >1e-8
浮点数二分的另一种写法,不用精度去表示迭代,而是直接循环100次。
#include <iostream>using namespace std;int main()
{double x;cin >> x;double l = 0, r = 100;for(int i = 0; i<100, i++){double mid= (l+r)/2;if(mid*mid >= x) r = mid;else l = mid;}printf("%lf\n", l);return 0;
}
AcWing 算法基础课第一节基础算法1排序、二分相关推荐
- AcWing 算法基础课第三节基础算法3 双指针、位运算、离散化、区间合并
1.该系列为ACWing中算法基础课,已购买正版,课程作者为yxc 2.y总培训真的是业界良心,大家有时间可以报一下 3.为啥写在这儿,问就是oneNote的内存不够了QAQ ACwing C++ 算 ...
- (算法设计与分析)第一章算法概述-第一节:算法基本概念和算法复杂性分析
文章目录 一:算法与程序 (1)算法的定义 (2)算法的五大特征 (3)算法与程序的区别 (4)算法的描述方法 二:算法复杂性分析 (1)时间复杂度 A:算法时间复杂度表示方法 B:表示算法渐进时间复 ...
- yxc_第一章 基础算法(三)_区间合并
截止2022.1.19,y总的基础算法网课已经全部听完.明天上午开始学习数据结构. 接下来还剩:第一章其他剩余的打卡题目.解决完这个问题之后,y总第一章基础算法就算暂时告一段落了. 未来算法学习的路还 ...
- 信息学奥赛一本通 提高篇 第一部分 基础算法 第2章 二分与三分
信息学奥赛一本通 提高篇 提高版 第一部分 基础算法 第2章 二分与三分 信息学奥赛一本通 提高篇 提高版 第一部分 基础算法 第2章 二分与三分_mrcrack的博客-CSDN博客_信息学奥赛一本通 ...
- 【gitlab+jenkins+docker】第一节 基础环境介绍与准备
[gitlab+jenkins+docker]手把手教你搭建基于gitlab+jenkins+docker的项目的自动化部署流程 架构 环境介绍 docker安装 docker-compose安装(二 ...
- 人工智能算法:卷1基础算法+卷2受大自然启发的算法+卷3深度学习和神经网络电子书
ISBN:9787115005786 包装:平装 字数:538000 页数:598 版次:7 开本:16开 用纸:胶版纸 正文语种:中文 人工智能算法:卷1基础算法+卷2受大自然启发的算法+卷3深度学 ...
- AcWing算法基础课 第一讲小结(持续更新中)
目录 前言 一.快速排序法及其扩展 快速排序法 介绍 思路 + 步骤 模拟代入 模板 练习 扩展(求第k个数) 思路 代码 二.归并排序法 归并排序 思路 思路 + 步骤 模拟代入 模板 练习 应用( ...
- AcWing算法基础课第一讲(2):高精度加减乘除、前缀和、差分
文章目录 1. 高精度加法 2. 高精度减法 3. 高精度乘低精度 4. 高精度除以低精度 5. 一维前缀和 6. 二维前缀和 7. 一维差分 8. 二维差分 1. 高精度加法 这里讲解两个大整数的加 ...
- yxc_第一章 基础算法(一)
目录 一.快速排序 1.零散知识点 (1)swap()函数: (2)>>位运算 (3)const int N=1e6+10: 2.快速排序模板题 (1)AcWing 785 快速排序 3. ...
最新文章
- 9种设计模式在Spring中的运用,一定要非常熟练!
- Thrift RPC 系列教程(5)—— 接口设计篇:struct enum设计
- 基于SP4062电路IO接口八通道保护板
- vba手机号码归属_Android手机号码归属地的查询
- PHP返回数据json数据样式要求是对象{},而不是[]
- vSphere Data Protection 6.1.2部署与配置
- 基于表单数据的封装,泛型,反射以及使用BeanUtils进行处理
- fatal error: Eigen3/Core: 没有那个文件或目录
- pixhawk学习笔记-----mavlink
- matlab中 晶闸管整流桥导通角_逆变角如何设置,晶闸管2011-6-6
- windows下,可替换telnet的工具tcping.exe
- Node.js 清洗万恶的种子
- 微信小程序-实现保存图片功能的3种方式
- nyoj 712 探 寻 宝 藏(双线dp 第六届河南省程序设计大赛)
- 离散化-利用计算机求解y=x,离散信号处理(双语)-中国大学mooc-题库零氪
- Java SE 第三讲(原生数据类型使用陷阱 Pitfall of Primitive Data Type)
- FCN(Fully Convolutional Network)与Unet:谈到语义分割不得不提的两个网络
- PDF在线压缩、转换工具
- PyTorch官方中文文档上线啦!
- RGB与Lab颜色空间互相转换