一、排序

1.快速排序q[n]

平均时间复杂度:n * log 2 n

(1)确定分界点x:q[l] 或 q[(l + r) / 2] 或 q[r] 或 随机
(2)调整区间:保证q[k]左边的数都小于等于x,q[k]右边的数都大于等于x,q[k]不一定等于x。
(3)在两个区间重复(1)(2)步

不需要开辟额外空间的做法:设两个指针i,j,i指向最左边的数,j指向最右边的数,i向右移,当遇到大于x的数时停下,j向左移,当遇到小于x的数时停下,然后交换i,j所指向的数。i,j以这一规则接着移动,直到i,j相遇为止。然后再分别对i,j分界点的两边进行此算法。

class Solution {
public:void quick_sort(int i,int j,vector<int>& nums){       int m = j - i;if(m < 0 || m == 0){return;}int x = nums[(i + j) >> 1];//参照标准int p = i;int q = j;j++;//因为要先j--再判断,所以先加一i--;//因为要先i++再判断,所以先减一while(i < j){do{i++;}while(nums[i] < x);//nums[i]<x不能加等于号。因为若恰好其它所有数都比x大或者小,会发生数组越界do{j--;}while(nums[j] > x);if(i < j){int a = nums[i];nums[i] = nums[j];nums[j] = a;}}quick_sort(p,j,nums);quick_sort(j + 1,q,nums);/*这里不能取sort(p,i - 1,nums);sort(i,q,nums);会陷入死循环,如[0,1],若想取i,则改变x的值向上取整*/return;}vector<int> sortArray(vector<int>& nums) {int n = nums.size();int i = 0;int j = n - 1;quick_sort(i,j,nums);return nums;}
};

2.快速选择

题目:给定一个长度为n的整数数列,以及一个整数k,请用快速选择算法求出数列的第k小的数是多少(假设这个数一定在区间内)。

进行一次快速排序时,假设分界点左边元素个数为SL,右边元素个数为SR,此时分为两种情况:
(1)k <= SL,递归左边
(2)k > SL,递归右边,k = k - SL

时间复杂度:n + n / 2 + n / 4 + ... = n(1 + 1/2 + 1/4 + 1/8 + ...) <= 2n,所以时间复杂度为O(n)。

#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];//因为保证k对应的值始终在区间内,所以区间内至少有一个值,所以可以不写成l >= rint 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;
}

3.归并排序

时间复杂度:n * log 2 n

(1)确定分界点mid:将整个数组平均分为左右两半。
mid = (l + r) / 2,两个区间[l,mid],[mid + 1,r]。
(2)对这两半分别进行递归排序:每次分两半,直到每对每组大小为1。
n除以2多少次等于1呢?log 2 n次,所以这一操作时间复杂度为O(log 2 n)。
(3)对于每对的两个有序数组 合并为一个有序数组:设i,j两个指针分别指向两个数组的第一个数,比较这两个指针所指向的数的大小,将小的那个取出,相应指针后移一位,再比较这两个指针所指向的数的大小,以此类推,直到一个指针移到数组的末尾,将另一个指针指向的数及其之后的数放到答案数组的最后面即可。

class Solution {
public:void merge_sort(vector<int>& nums,int l,int r){//归并排序      //数组中没有数据或只有一个数据时,返回if(l >= r){return;}       //先进行对半分int middle = (l + r) >> 1;merge_sort(nums, l, middle);merge_sort(nums, middle + 1, r);      //然后对每对数组进行排序int temp[r - l + 1];//暂存结果int n = 0;int i = l,j = middle + 1;while(i <= middle && j <= r){if(nums[i] < nums[j]){temp[n++] = nums[i++];      }else{temp[n++] = nums[j++];}}if(i > middle){while(j <= r){temp[n++] = nums[j++];}}else if(j > r){while(i <= middle){temp[n++] = nums[i++];}}//从暂存数组中取出数据int p = l,q = 0;while(p <= r){nums[p++] = temp[q++];}}vector<int> sortArray(vector<int>& nums) {int n = nums.size();int l = 0;int r = n - 1;merge_sort(nums,l,r);return nums;}
};

4.求逆序对的数量

逆序对:序列中的一对数,前面的数比后面的数大。

使用归并排序,共有三种情况:
(1)这一对数都在mid的左边:左半边内部的逆序对数量:merge_sort(L, mid)
(2)这一对数都在mid的右边:右半边内部的逆序对数量:merge_sort(mid + 1, R)
(3)一个数在mid左边,一个数在mid右边:设右边有m个数。对右边第一个点,左边有S1个数比它大,那么有S1个逆序对。以此类推,对右边第m个点,左边有Sm个数比它大,那么有Sm个逆序对。那么这种情况下一共有S1 + S2 + ... + Sm个逆序对。
        在合并过程中,设指针i指向左边,指针j指向右边,若指针i指向的数比指针j指向的数小,则i向后移一位。直到指针i指向的数比指针j指向的数大,则S = mid - i + 1,j向后移一位。

设序列中有n个数,则最多有n(n - 1) / 2个逆序对,数值可能会很大,大于int的最大值,要用long long来存。

class Solution {
public:typedef long long LL;int merge_sort(int l, int r, vector<int>& nums){if(l >= r) return 0;int mid = (l + r) >> 1;LL res = merge_sort(l, mid, nums) + merge_sort(mid + 1, r, nums);int temp[r - l + 1];int i = l, j = mid + 1, k = 0;while(i <= mid && j <= r){if(nums[i] <= nums[j]) temp[k++] = nums[i++];else{temp[k++] = nums[j++];res = res + mid - i + 1;}}//扫尾       while(i <= mid) temp[k++] = nums[i++];while(j <= r) temp[k++] = nums[j++];//物归原主for(int p = l, q = 0; p <= r; p++, q++){nums[p] = temp[q];}return res;}int reversePairs(vector<int>& nums) {int n = nums.size();int result = merge_sort(0, n - 1, nums);return result;}
};

二、二分查找

1.二分查找

(1)首先确定区间的中点位置mid
(2)将待查的K值与R[mid]比较:
若相等,则查找成功并返回此位置,
否则,①若R[mid].key>K,将查找区间变为[left,mid-1]
           ②若R[mid].key<K,将查找区间变为[mid+1,right]

当l > r时无解

class Solution {
public://假设所有元素不重复int search(vector<int>& nums, int target) {int n = nums.size();int l = 0,r = n - 1;int mid = (r + l) >> 1;//cout << mid << endl;while(l <= r){if(nums[mid] == target){return mid;}else if(nums[mid] > target){r = mid - 1;}else{l = mid + 1;}mid = (r + l) >> 1;//cout << r << " " << l << " " << mid << endl;}return -1;}
};

2.数的三次方根

假设范围内有正数也有负数,范围为(l, r)。
设mid = (l + r) / 2。
if(mid^3 == x) result = mid;
if(mid^3 > x) r = mid;
else l = mid;

如果结果保留n位小数,则r - l > 10^(-n-2)

#include <iostream>using namespace std;int main(){double x;cin >> x;double l = -10000, r = 10000;while(r - l > 1e-8){//1e-8是10的-8次方double mid = (l - r) / 2;if(mid * mid * mid >= x) r = mid;else l = mid;}printf("%lf\n",l);//float型输入用%f,double型输入用%lfreturn 0;
}

三、高精度

1.两个大的整数相加A + B(大的整数的位数一般 <= 10^6)

2.两个大的整数相减A - B

3.大的整数乘小的整数A * a(小的整数一般 <= 10^9)

4.大的整数除以小的整数A / a

注:这里假设A,B,a都大于等于0

1.两个大的整数相加A + B 可划分为两个问题
①大整数存储:将整数的每一位存到数组中
例如:A = 123456789,比较好的处理办法是从个位开始存:9存到nums[0],8存到nums[1],以此类推。从个位开始存的原因是比较好处理进位问题。
②大整数相加:注意进位。

#include<iostream>
#include<vector>using namespace std;// C = A + B, A >= 0, B >= 0
vector<int> add(vector<int> &A, vector<int> &B)
{vector<int> C;int t = 0;//进位for (int i = 0; i < A.size() || i < B.size(); i ++ ){if(i < A.size()) t += A[i];if(i < B.size()) t += B[i];C.push_back(t % 10);t /= 10;}if (t) C.push_back(1);//若加完还有一进位return C;
}
int main(){string a,b;vector<int> A,B;cin >> a >> b;//a = "123456"for(int i = a.size() - 1;i >= 0;i--) A.push_back(a[i] - '0');//A = [6,5,4,3,2,1]for(int i = b.size() - 1;i >= 0;i--) B.push_back(b[i] - '0');auto C = add(A,B);for(int i = C.size() - 1;i >= 0;i--) printf("%d",C[i]);return 0;
}

2.两个大的整数相减A - B 可划分为两个问题
①大整数存储:同1
②大整数相减:若A > B,则运算A - B;若A < B,则运算-(B - A)。注意借位。

#include<iostream>
#include<vector>using namespace std;//判断是否A >= B
bool cmp(vector<int> &A, vector<int> &B){if(A.size() != B.size()){return A.size() > B.size();}for(int i = A.size() - 1; i >= 0; i--){if(A[i] != B[i]){return A[i] > B[i];}}return true;
}//C = A - B
vector<int> sub(vector<int> &A, vector<int> &B){vector<int> C;for(int i = 0, t = 0; i < A.size(); i++){t = A[i] - t;if(i < B.size()) t -= B[i];C.push_back((t + 10) % 10);//t > 0或t < 0皆适宜if(t < 0) t = 1;else t = 0;}while(C.size() > 1 && C.back() == 0) C.pop_back();//如答案为001,则需去掉前面两个零。若答案为000,则剩余一个零。return C;
}int main(){string a, b;vector<int> A, B;cin >> a >> b;for(int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');for(int i = b.size() - 1; i >= 0; i--) B.push_back(a[i] - '0');if(cmp(A, B)){auto C = sub(A, B);for(int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]);}else{auto C = sub(B, A);printf("-");for(int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]);}
}

3.大的整数乘小的整数A * a 可划分为两个问题
①大整数存储:同1
②大整数相乘:将A的每一位与a相乘,结果加上进位所得值t,t取10的余数为当前位结果,t除以10为进位。

#include <iostream>
#include <vector>using namespace std;vector<int> mul(vector<int> &A, int b){vector<int> C;int t = 0;for(int i = 0; i < A.size() || t; i++){if(i < A.size()) t += A[i] * b;C.push_back(t % 10);t /= 10;}return C;
}int main(){string a;int b;cin >> a >> b;vector<int> A;for(int i = a.size() - 1; i >= 0; i--){A.push_back(a[i] - '0');}auto C = mul(A,b);for(int i = C.size() - 1; i >= 0; i--){printf("%d",C[i]);}return 0;
}

4.大的整数除以小的整数A / a 可划分为两个问题
①大整数存储:同1
②大整数相除:将A的每一位 加上 上一位求得的余数*10 再除以a,得到的商为当前位的值。

#include <iostream>
#include <vector>
#include <algorithm>using namespace std;// A / b = C ... r, A >= 0, b > 0
vector<int> div(vector<int> &A, int b, int &r)
{vector<int> C;r = 0;for (int i = A.size() - 1; i >= 0; i -- ){r = r * 10 + A[i];C.push_back(r / b);r %= b;}reverse(C.begin(), C.end());//需要#include <algorithm>while (C.size() > 1 && C.back() == 0) C.pop_back();return C;
}int main(){string a;int b;cin >> a >> b;vector<int> A;for(int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');int r;auto C = div(A, b, r);for(int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]);cout << endl << r << endl;return 0;
}

四、前缀和与差分

1.一维前缀和

设有一个数组:a1,a2,...,an
前缀和数组:S0 = 0,...,S[i] = a[1] + ... + a[i],...

作用:如求数组a中第l项到第r项的和,则答案等于S[r] - S[l - 1]

题目:输入一个长度为n的整数序列。接下来再输入m个询问,每个询问输入一对l,r。对于每个询问,输出原序列中从第i个数到第r个数的和。

#include <iostream>using namespace std;const int N = 100010;int n, m;
int a[N], s[N];
//假设n范围为1~100000,数列中元素的值取值范围为-1000~1000,s[N]最大取值为10^8,int的取值范围为-2^31~2^31-1,即-2147483648~2147483647,所以这里s[N]不用定义为long long类型int main(){scanf("%d%d",&n,&m);for(int i = 1; i <= n; i++) scanf("%d",&a[i]);for(int i = 1; i <= n; i++) s[i] = s[i - 1] + a[i];//前缀和初始化while(m--){int l,r;scanf("%d%d",&l, &r);printf("%d\n",s[r] - s[l -1]);}return 0;
}

2.二维前缀和

S[i,j]表示包含a[i,j]的左上角的子矩阵中数的和:一行一行求:S[i,j] = S[i - 1,j] + S[i,j - 1] - S[i -1,j - 1] + a[i,j]

作用:输出原矩阵中顶点为(x1,y1),(x2,y2)的子矩阵中数的和:S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]

题目:输入一个边长为n,m的整数矩阵。接下来再输入q个询问,每个询问输入x1,y1,x2,y2。对于每个询问,输出原矩阵中顶点为(x1,y1),(x2,y2)的子矩阵中数的和。

#include <iostream>const int N = 1010;int n,m,q;
int a[N][N], S[N][N];int main(){scanf("%d%d%d",&n,&m,&q);for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++)scanf("%d",&a[i][j]);for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++)S[i][j] = S[i - 1][j] + S[i][j - 1] - S[i - 1][j - 1] + a[i][j];//求二维前缀和while(q--){int x1,y1,x2,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);printf("%d\n",S[x2][y2] - S[x2][y1 - 1] - S[x1 - 1][y2] + S[x1 - 1][y1 - 1]);//子矩阵的和}return 0;
}

3.一维差分

给定原数组a[n],构造数组b[n],使得a[i] = b[1] + b[2] + ... + b[i]。此时,b为a的差分,a为b的前缀和。
即b[1] = a[1];
b[2] = a[2] - a[1];
b[3] = a[3] - a[2];
...
b[n] = a[n] - a[n - 1];

有了b数组,可以在O(n)的时间内得到a数组。

作用:若我们想把a数组内从a[l]到a[r]的项全部加上c,若直接对a数组操作,则需要O(r - l + 1)的时间复杂度,可若有了b数组,可以只对b[l]与b[r + 1]操作:b[l] = b[l] + c,b[r + 1] = b[r + 1] - c,时间复杂度为O(1)。

b初始化:可以将a数组的初值想象成0,然后我们需要给a的每个点加上a[i]。

题目:输入一个长度为n的整数序列。接下来再输入m个操作,每个操作包含三个整数l, r, c,表示将序列中[l, r]之间的每个数加上c。请你输出进行完所有操作后的序列。

#include <iostream>using namespace std;const int N = 100010;int n, m;
int a[N], b[N];void insert(int l, int r, int c){b[l] += c;b[r + 1] -= c;
}int main(){scanf("%d%d",&n, &m);for(int i = 1; i <= n; i++) scanf("%d", &a[i]);//a数组初始化for(int i = 1; i <= n; i++) insert(i, i, a[i]);//b数组初始化//m操作while(m--){int l, r, c;scanf("%d%d%d", &l, &r, &c);insert(l, r, c);}//m操作之后的数组for(int i = 1; i <= n; i++) a[i] = a[i - 1] + b[i];for(int i = 1; i <= n; i++) printf("%d ", a[i]);return 0;
}

4.二维差分

给定原矩阵a[i, j],构造差分矩阵b[i, j],使b[i, j]的二维前缀和为a[i, j]。

作用:假设我们需要给a矩阵的一个子矩阵(x1,y1),(x2,y2)中的所有数加上c。
(1)我们若让b[x1,y1] += c,那么a[x1,y1]这一点右下角的所有点的前缀和都会加c。
(2)我们再让b[x2 + 1,y1] -= c,b[x1,y2 + 1] -= c,b[x2 + 1,y2 + 1] += c。
这么做会让时间复杂度变成O(1)。

b初始化:可以将a数组的初值想象成0,然后我们需要给a矩阵的每个1*1的子矩阵加上a[i,j]。

题目:输入一个n行m列的整数矩阵,再输入q个操作,每个操作包含五个整数x1, y1, x2, y2, c,其中(x1, y1)和(x2, y2)表示一个子矩阵的左上角坐标和右下角坐标。每个操作都要将选中的子矩阵中的每个元素的值加上c。请将进行完所有操作后的矩阵输出。

#include <iostream>using namespace std;const int N = 1010;int n, m, q;
int a[N][N], b[N][N];void insert(int x1, int y1, int x2, int y2, int c){b[x1][y1] += c;b[x2 + 1][y1] -= c;b[x1][y2 + 1] -= c;b[x2 + 1][y2 + 1] += c;
}int main(){scanf("%d%d%d", &n, &m, &q);//a初始化for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++)scanf("%d", &a[i][j]);//b初始化for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++)insert(i, j, i, j, a[i][j]);//q操作while(q--){int x1, y1, x2, y2, c;cin >> x1 >> y1 >> x2 >> y2 >> c;insert(x1, y1, x2, y2, c);}//操作后的数组for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++)a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + b[i][j];for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++) printf("%d ", a[i][j]);return 0;
}

五、双指针算法

核心思想:将算法的时间复杂度从O(n^2)优化到O(n)

for(i = 0, j = 0; i < n; i++){while(j < i && check(i, j)) j++;//每道题目的具体逻辑
}

:输入一个英文句子,输出每个单词,假设句子中每个单词之间有一个空格。

#include <iostream>
#include <string.h>using namespace std;int main(){char str[1000];gets(str);int n = strlen(str);for(int i = 0; i < n; i++){int j = i;while(str[j] != " ") j++;//这道题的具体逻辑for(int k = i; k < j; k++) cout << str[k];cout << endl;i = j;}return 0;
}

1.最长不重复连续子序列

//朴素做法:O(n^2)
for(int i = 0; i < n; i++){//i为终点for(int j = 0; j <= i; j++){//j为起点if(check(j, i)){res = max(res, i - j + 1);break;}}
}
//改进版:O(n)
for(int i = 0, j = 0; i < n; i++){while(j <= i && !check(j, i)) j++;res = max(res, i - j + 1);
}

题目:请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。

class Solution {
public:int lengthOfLongestSubstring(string s) {int n = s.size();unordered_map<char, int> umap;//创建,前者为key,后者为valueint res = 0;for(int i = 0, j = 0; i < n; i++){umap[s[i]]++;while(umap[s[i]] > 1){//这里憋写反了umap[s[j]]--;j++; }res = max(res, i - j + 1);}return res;}
};

六、位运算

七、离散化

八、区间合并

【C++】算法笔记_01相关推荐

  1. 《算法笔记》中文版 - 包括数组,链表,树,图,递归,DP,有序表等相关数据结构与算法的讲解及代码实现...

    来源:专知本文为资源,建议阅读5分钟本文为你分享<算法笔记>中文版. https://github.com/Dairongpeng/algorithm-note 目录概览 第一节 复杂度. ...

  2. 数据结构与算法笔记 - 绪论

    数据结构与算法笔记 - 绪论 1. 什么是计算 2. 评判DSA优劣的参照(直尺) 3. 度量DSA性能的尺度(刻度) 4. DSA的性能度量的方法 5. DSA性能的设计及其优化 x1. 理论模型与 ...

  3. 数据结构与算法笔记(十六)—— 二叉搜索树

    一.二叉搜索树定义 二叉搜索树(Binary Search Tree),又名二叉排序树(Binary Sort Tree). 二叉搜索树是具有有以下性质的二叉树: 若左子树不为空,则左子树上所有节点的 ...

  4. 数据结构与算法笔记(十五)—— 散列(哈希表)

    一.前沿 1.1.直接寻址表 当关键字的全域U比较小时,直接寻址是一种简单而有效的技术.假设某应用要用到一个动态集合,其中每个元素都有一个取自全域U={0,1,-,m-1)的关键字,此处m是一个不很大 ...

  5. 《algorithm-note》算法笔记中文版正式发布!

    无论是做机器学习.深度学习.自然语言处理还是其它领域,算法的重要性不言而喻!吃透算法底层原理.掌握算法数学推导和代码实现,对提高自己的硬核实力来说非常重要!今天给大家推荐一个超赞的开源算法笔记!中文版 ...

  6. 【算法】《algorithm-note》算法笔记中文版正式发布!

    无论是做机器学习.深度学习.自然语言处理还是其它领域,算法的重要性不言而喻!吃透算法底层原理.掌握算法数学推导和代码实现,对提高自己的硬核实力来说非常重要!今天给大家推荐一个超赞的开源算法笔记!中文版 ...

  7. c++ string 删除字符_算法笔记|(5)第二章C、C++的快速入门字符数组的存放方式string.h文件...

    字符数组的存放方式 由于字符数组是由若干个char类型的元素组成的,因此字符数组的每一位都是一个char字符,除此之外,在一维字符数组或者二维字符数组的第二维的末尾都有一个空字符\0表示存放的字符串的 ...

  8. 算法笔记(JavaScript版)——排序

    算法笔记(JavaScript版)--排序 本文内容根据Rebert Sedgewick和Kevin Wayne的<算法(第四版)>整理,原代码为java语言,自己修改为JavaScrip ...

  9. 三维重建7:Visual SLAM算法笔记

    VSLAM研究了几十年,新的东西不是很多,三维重建的VSLAM方法可以用一篇文章总结一下. 此文是一个好的视觉SLAM综述,对视觉SLAM总结比较全面,是SLAM那本书的很好的补充.介绍了基于滤波器的 ...

最新文章

  1. In order to use Instant Run with this device running API 26, you must install platform API 26 in you
  2. [转]ISTQB FL初级认证考试资料(中文)
  3. 1、Hello World
  4. 用TLS搭建即时通讯的安全通道:LCS2005系列之三
  5. 关于vue+element-ui项目的分页,返回默认显示第一页的问题解决
  6. 0.7秒,完成动漫线稿上色
  7. 全球及中国微电网市场规模容量及建设运营模式分析报告2021年版
  8. boost::spirit模块将 QString 数据类型用作 Qi 属性的测试程序
  9. [css] 你了解css3的currentColor吗?举例说明它的作用是什么?
  10. 9-18 学习如何使用Python包的管理
  11. Android模拟器启动3个g,android,模拟器_android 模拟器用3.18的内核无法启动,一直黑屏。,android,模拟器,内核 - phpStudy...
  12. 计算机网络之物理层:1、接口特性、同步异步、串行并行、双工
  13. 使用TortoiseGit提交代码到Github.com上 详细步骤
  14. 前端图片压缩上传(纯js的质量压缩,非长宽压缩)
  15. React中的高阶组件
  16. delphi Hi 和 High
  17. Erlang之父Joe Armstrong去世
  18. Uni-G/ The University of Glasgow (Uni-G) ECG Analysis Program
  19. 百度十年,我从技术走到管理
  20. delphi播放wav声音

热门文章

  1. 【PTE】Windows操作系统安全
  2. BloomFilter 布隆过滤器
  3. python实现cc攻击_第二章 Requests库的使用:变相的cc攻击
  4. 你真的了解java吗?java总结八
  5. source insight 4.0下载与破解
  6. win7计算机基础网络考试题库,Win7计算机应用基础考试内容
  7. 利用apache2在树莓派上搭建简易网站
  8. DAPPER全反光羽绒服
  9. 网站策划需要具备的知识
  10. 中国科教网网站新闻发布