s = a[0];
for(i = 0; i < n; ++i) {
s += a[i];
}
for(i = 0; i < n; ++i) {
for(j = 0; j < n; ++j) {
s += a[i][j];
}
}
l = 1, r = n;
while(l <= r) {
mid = (l + r) >> 1;
if(a[mid] <= v) {
r = mid + 1;
}else {
l = mid + 1;
}
}
int fib(unsigned int n) {
if(n <= 1) {
return n;
}
return fib(n-1) + fib(n-2);
}
int stk[MAXN], top, has[MAXN];
void dfs(int n, int depth) {
int i;
if (depth == n) {
for (i = 0; i < n; ++i) {
printf("%d", stk[i]);
}
puts("");
}
for (i = 0; i < n; ++i) {
if (!has[i]) {
has[i] = 1;
stk[top++] = i+1;
dfs(n, depth + 1);
--top;
has[i] = 0;
}
}
}
【场景1】从长度为 n n n 的数组中查找某个数字是否存在
const int n = 100000;
void init() {
for (int i = 0; i < n; ++i) {
a[i] = 5 * i;
}
}
bool find(int target) {
for (int i = 0; i < n; ++i) {
if (target == a[i]) {
return true;
}
}
return false;
}
int countBy() {
int cnt = 0, m = 100000;
while(m--) {
if (find(6857112) ) {
// 这里举了个最坏的例子,永远找不到的情况
++cnt;
}
}
return cnt;
}
【优化1】利用哈希数组的索引来代替数组的遍历
const int n = 100000;
void init() {
memset(hashtbl, 0, sizeof(hashtbl));
for (int i = 0; i < n; ++i) {
hashtbl[ 5 * i ] = 1;
}
}
bool find(int target) {
return hashtbl[target];
}
【场景2】从长度为 n n n 的数组中查找某个字符串是否存在
【优化2】利用 STL 的 map 来代替数组的遍历
const int n = 100000;
map<string, bool> maphash;
void init() {
maphash.clear();
for (int i = 0; i < n; ++i) {
maphash[ str[i] ] = 1;
}
}
bool find(string target) {
return maphash.find(target) != maphash.end();
}
【优化3】利用 STL 的 unordered_map 来代替数组的遍历
【思考题1】
int sum = 0;
for (int i = 0; i < n; ++i) {
for(int j = 0; j < m; j++) {
if(A[i] == B[j]) {
sum += (A[i] + B[j]);
}
}
}
【场景3】计算某个玩家的属性的时候,有一步运算是除上2的幂取除数和余数
const int n = 3000000;
const int m = 30;
int doCount() {
int s = 0, cnt = n;
int pow2[MAXP] = {
1 };
for (int i = 1; i < m; ++i) {
pow2[i] = pow2[i - 1] * 2;
}
while (cnt --) {
for (int i = 0; i < m; ++i) {
s += rand() / pow2[i];
s += (rand() % pow2[i]);
}
}
return s;
}
【优化4】利用位运算进行常数优化
const int n = 3000000;
const int m = 30;
int doCount() {
int s = 0, cnt = n;
int pow2[MAXP] = {
1 };
for (int i = 1; i < m; ++i) {
pow2[i] = pow2[i - 1] * 2;
}
while (cnt --) {
for (int i = 0; i < m; ++i) {
s += rand() >> i;
s += rand() & (pow2[i]-1);
}
}
return s;
}
【思考题2】
int get(int x) {
int c = 0;
while (x % 2 == 0) {
c++;
x /= 2;
}
return (1 << c);
}
【场景4】循环内部大量调用同一个函数,参数也相同
for (i = 0; i < n; ++i) {
for(j = 0; j < m; j++) {
int v = Cal(MAX_COUNT);
A[i][j] = v * i + j;
}
}
【优化5】改变运算顺序避免重复运算
int v = Cal(MAX_COUNT);
for (i = 0; i < n; ++i) {
for(j = 0; j < m; j++) {
A[i][j] = v * i + j;
}
}
【思考题3】
for (i = 0; i < n; ++i) {
for(j = 0; j < m; j++) {
A[i][j] = Cal(i) + Del(j);
}
}
【优化6】如果可行尽量用加法代替乘法
int v = Cal(MAX_COUNT);
for (i = 0; i < n; ++i) {
for(j = 0; j < m; j++) {
if(!i) {
A[i][j] = j;
}else {
A[i][j] = (A[i-1][j] + v);
}
}
}
【思考题4】
【场景5】需要对一批数据进行求和取模
int doSumMod() {
int s = 0;
for (int i = 0; i < n; ++i) {
s = (s + val[i]) % MOD;
}
return s;
}
【优化7】不必要时不进行取模运算
int doSumMod() {
int s = 0;
for (int i = 0; i < n; ++i) {
s += val[i];
if (s >= MOD) s %= MOD;
}
return s;
}
【思考题5】
ans = -520 % 1314; //???
【场景6】求两个数字中的大者
#define MAX(a,b) ((a)>(b)?(a):(b))
MAX(for(int i = 0; i <100000; ++i) s += i, for(int i = 0; i <100000; ++i) s += i);
【优化8】宁以 const 或者 函数代替 #define
int Max(int a, int b){
return a > b ? a : b;
}
template <class T>
T Max(T a, T b){
return a > b ? a : b;
}
【思考题6】
#define ABS(x) x<0?-x:x
【场景7】循环的终止条件是一个表达式的时候
int For() {
int s = 0;
for (int i = 0; i*i < n; ++i) {
for (int j = 0; j*j < n; ++j) {
for (int k = 0; k*k < n; ++k) {
// TODO
}
}
}
return s;
}
【优化9】尽量最大限度的简化循环终止条件的逻辑运算
int For2() {
int s = 0;
int v = sqrt(n + 1e-8);
for (int i = 0; i < v; ++i) {
for (int j = 0; j < v; ++j) {
for (int k = 0; k < v; ++k) {
// TODO
}
}
}
return s;
}
【思考题7】
for(i = 0; i < vec.size(); i++) {
// TODO
}
【场景8】给定一个数,在一个有序数组中查找比它大的最小的数,不存在输出 -1
【优化10】利用二分查找优化有序数组的查找效率
#define MAXA 10
int bin[MAXA] = {
1, 2, 4, 6, 8, 9, 11, 88, 520, 1314 };
int BinarySearch(int val) {
int l = 0, r = MAXA - 1;
int m, ans = -1;
while (l <= r) {
m = (l + r) >> 1;
if (bin[m] > val) {
ans = bin[m];
r = m - 1;
}
else {
l = m + 1;
}
}
return ans;
}
【思考题8】
【场景9】计算 a b m o d c ( a , b < 2 64 ) a^b \mod c(a,b<2^{64}) abmodc(a,b<264) ,一般用在加解密算法(例如 RSA )中
【优化11】利用递归二分的性质将线性时间复杂度转换成对数时间复杂度
const int MAXDC = 100;
void DataCollect() {
vector <int> v;
for (int i = 0; i < MAXDC; ++i) {
v.push_back(i);
}
}
【优化12】对 vector 进行内存预分配
const int MAXDC = 100;
void DataCollect() {
vector <int> v;
v.reserve(MAXDC);
for (int i = 0; i < MAXDC; ++i) {
v.push_back(i);
}
}
【优化13】小数组尽量不用 vector
const int MAXDC = 100;
void DataCollect() {
int stk[MAXDC], top = 0;
for (int i = 0; i < MAXDC; ++i) {
stk[top++] = i;
}
}
【思考题9】
string s;
for(i = 0; i < n; ++i) {
s += "K";
}
const int MAXPI = 100000000;
double CalcCircle() {
double s = 0;
for (int i = 0; i < MAXPI; ++i) {
s += acos(-1.0) * i * i;
}
return s;
}
【优化14】精度允许的情况尽量用常量代替三角函数
const int MAXPI = 100000000;
double CalcCircle() {
double s = 0;
const double PI = 3.1415927;
for (int i = 0; i < MAXPI; ++i) {
s += PI * i * i;
}
return s;
}
【思考题10】
【场景10】静态类型转换 和 动态类型转换 的时耗性
const int MAXT = 100000000;
void StaticCast_Test() {
Inher *p = new Inher();
for (int i = 0; i < MAXT; ++i){
Base *pkBase = static_cast<Base*>(p);
}
}
void Dynamic_Test() {
Inher *p = new Inher();
for (int i = 0; i < MAXT; ++i){
Base *pkBase = dynamic_cast<Base*>(p);
}
}
【场景11】斐波那契数列的计算
long long fib(unsigned int n) {
if(n <= 1) {
return n;
}
return fib(n-1) + fib(n-2);
}
【优化15】记忆化搜索将指数级时间复杂度转变为多项式级时间复杂度
void init() {
memset(f, -1, sizeof(f));
}
long long fib(unsigned int n) {
if(n <= 1) {
return n;
}
if(f[n] != -1) {
return f[n];
}
return f[n] = fib(n-1) + fib(n-2);
}
f[0] = 0, f[1] = 1;
for(int i = 2; i < MAXN; ++i) {
f[i] = f[i-1] + f[i-2];
}
【场景12】计算斐波那契数列的第L项到第R项的和(L<=R)
f[0] = 0, f[1] = 1;
for(int i = 2; i <= R; ++i) {
f[i] = f[i-1] + f[i-2];
}
s = 0;
for(int i = L; i <= R; ++i) {
s += f[i];
}
【优化17】预处理数组前缀和可以做到询问时O(1)
sum[0] = 0;
for(int i = 1; i < MAXN; ++i) {
sum[i] = sum[i-1] + f[i];
}
NumberType getFib(NumberType L, NumberType R) {
return sum[R] - sum[L-1];
}
【思考题11】
【优化1】利用哈希数组的索引来代替数组的遍历
【优化2】利用 S T L STL STL 的 m a p map map 来代替数组的遍历
【优化3】利用 S T L STL STL 的 u n o r d e r e d _ m a p unordered\_map unordered_map 来代替数组的遍历
【优化4】利用位运算进行常数优化
【优化5】改变运算顺序避免重复运算
【优化6】如果可行尽量用加法代替乘法
【优化7】不必要时不进行取模运算
【优化8】宁以 c o n s t const const 或者 函数代替 # d e f i n e \#define #define
【优化9】尽量最大限度的简化循环终止条件的逻辑运算
【优化10】利用二分查找优化有序数组的查找效率
【优化11】利用递归二分的性质将线性时间复杂度转换成对数时间复杂度
【优化12】对 vector 进行内存预分配
【优化13】小数组尽量不用 v e c t o r vector vector
【优化14】精度允许的情况尽量用常量代替三角函数
【优化15】记忆化搜索将指数级时间复杂度转变为多项式级时间复杂度
【优化16】预处理能够处理所有可预见范围内的计算
【优化17】预处理数组前缀和可以做到询问时 O ( 1 ) O(1) O(1)
字数太多描述不下了,答案见下期吧