iOS移动开发社区程序员数据结构和算法分析

从零开始的暴力算法之旅

2016-11-06  本文已影响270人  编码的哲哲

这几天没更算法,一个主要的原因是我发现自己在解决一个问题时没有一个系统的思考方法,我意识到这个问题的严重性。想必大家都经历过,面对复杂的问题只是傻乎乎的盯着显示器,或者不经过深思熟虑就开始敲打键盘,结果还要辛辛苦苦修改一塌糊涂的代码。
一本书上说道:与通常所想不同,支配设计算法的并不是一时出现的灵感,而是许多策略性的选择。构想算法不仅需要理解问题的特性,还要理解执行时间和占用内存空间之间的对立关系,而且还要选择适当的数据结构。有些算法会共享出解决问题时最重要的领会,将之积累起来就会领悟到一种模式。
只读这一段会觉得有点难以理解但好似有很有道理,其实,我这几天学到了一种如何思考问题的方法,总结起来就一句话:化繁为简。接下来的文章我会通过实例逐一诠释我的领悟所得。
我们最常见的错误就是把简单的问题复杂化,比如前几天去饭店吃饭,一个二年级的小朋友有一道数学题:一根木棍长22米,请问需要截取几次才能将其分为长度都为2米的木棍。答案很简单:22/2。但是我却本能的告诉那孩子是log2(22/2)。现在想来我都笑了,二分算法写多了。
所以,为了避免类似的错误,每当我们遇到问题时应当先自问:能否用暴力的方法解决,并且是否能否优雅的解决【这体现了一个程序员是否有一颗优雅编程的心】。
接下来看一道问题:
求从0开始按顺序标号的n个元素中,选择4个元素的所有可能的组合。假设n=7,那么大家就会想到写一个4重循环就好,看起来是这个样子:
for(int i = 0; i < n; ++i)
for(int j = i+1; j < n; ++j)
for(int k = j+1; k < n; ++k)
for(int l = k+1; l < n; ++l)
cout<<i<<j<<k<<l<<endl;
但是若是选择5个数字的全排列呢,7个,8个呢,是不是得手动在增加循环次数,比追女生都麻烦是不是。要是我们将每一个循环看成一个递归的话,就很容易优雅解决了。
//n:元素总量
//picked:已选元素的序号
//toPick:还需选择元素的数量
则构成的飘逸的代码是下面这样的:

include<iostream>

include<vector>

using namespace std;

void printPicked(vector<int> & picked){
for(int i = 0; i<picked.size(); i++){
cout<<picked[i];
}
cout<<endl;
}
void pick(int n, vector<int>& picked, int toPick){
if(toPick == 0) {
printPicked(picked);return;
}
int smallest = picked.empty() ? 0 : picked.back() + 1;
for(int next = smallest; next < n; ++next){
picked.push_back(next);
pick(n,picked,toPick-1);
picked.pop_back();
}
}
int main(){
int n = 0;
cin >> n;
vector<int> picked;
pick(10,picked,n);
}

是不是很棒。。。

上一篇下一篇

猜你喜欢

热点阅读