您的位置:首页 > 其它

最惊讶的算法

2015-07-14 20:22 211 查看

最长回文字串算法

今天在逛知乎的时候有个问题是什么算法让你最惊讶。这里面这的有很多有趣的算法,我决定等下把这个问题看完。目前我仅仅看到了三个回答。

1遗传算法

感觉回答这个的人应该对搜索的模拟生物算法都会感到惊讶。比如蚁群算法,神经网络算法。这类算法有很大的随机性,都有点科学抽奖的意思。关于遗传算法任何一个数学建模的书上都有介绍。如果没有接触过这种算法的人应该是一个不错的思想启发。

2reservoir sampling

这里我直接摘抄维基百科的东西,阅读上没有什么难度(中文的被墙)

Reservoir sampling is a family of randomized algorithms for randomly choosing a sample of k items from a list S containing n items, where n is either a very large or unknown number. Typically n is large enough that the list doesn’t fit into main memory. The most common example was labelled Algorithm R by Jeffrey Vitter in his paper on the subject.

This simple O(n) algorithm as described in the Dictionary of Algorithms and Data Structures consists of the following steps (assuming that the arrays are one-based, and that the number of items to select, k, is smaller than the size of the source array, S)

array R[k];    // result
integer i, j;

// fill the reservoir array
for each i in 1 to k do
R[i] := S[i]
done;

// replace elements with gradually decreasing probability
for each i in k+1 to length(S) do
j := random(1, i);   // important: inclusive range
if j <= k then
R[j] := S[i]
fi
done


这算法一应用到了数学上概率的一些性质。能够确保最后选择出来的数都是随机抽取的。每个数被取出来的可能性相等。这个算法很漂亮,1首先你不知道到底有多少个数,但是结果却能做到每个数都是等概率。2其次这个算法适用于流处理,时间复杂度和空间复杂度都是最小的了。

3Manacher’s algorithm

判断一个字符串里面最长的回文是有多长。

#include <string.h>
#include <stdio.h>
#include <iostream>
using namespace std;
void preprocess(char str[],char result[]);
int min(int a, int b);
int p[2020];
int main(){
int center,i,i_,L,R,j;
char str[1010],result[2020];
int maxlen, index,len;
cin.getline(str,1000,'\n');
preprocess(str,result);
/*printf("%s",result);*/
//handle the string
center=0,R=0;
p[0]=0;
len = strlen(result);
//i from 1,so the begging position is placed '$' to avoid the segment error
for(i=1;i<len-1;i++){
i_=center*2-i;//the symmetric position
L=center*2-R;
p[i] = (R > i) ? min(R - i, p[i_]) : 0;
while (i + p[i] + 1<len&&result[i + p[i] + 1] == result[ i- p[i] - 1])
p[i]++;
//if R expands,then modify it
if (R - i <p[i]){
center = i;
R = i + p[i];
}
}
//find the maximum length in p
maxlen = 0, index = 0;
for (i = 0; i < strlen(result); i++){
if (maxlen < p[i]){
maxlen = p[i];
index = i;
}
}
printf("%d", maxlen);
return 0;
}
void preprocess(char str[],char result[]){
int len=strlen(str),i,j;
result[0]='$';//indicates the start
for(i=0,j=1;i<len;i++){
result[j++]='#';
result[j++]=str[i];
}
result[j]='#';
result[j+1]='\0';
}
int min(int a, int b){
if (a < b)
return a;
else
return b;
}


这个算法的核心代码如下

p[i] = (R > i) ? min(R - i, p[i_]) : 0;
//这个就是充分利用对称性,利用之前已经得出的半径给当前开始字母为中心的回文判断提供一个尽可能大的初值。和kmp算法的辅助数组有异曲同工直面
while (i + p[i] + 1<len&&result[i + p[i] + 1] == result[ i- p[i] - 1])
p[i]++;//这句就是试探如果用i做中心的话最大的回文能多大
if (R - i <p[i]){//如果当前字母为中心比较大那么更改中心,不大于之前的字母中心那么保留原来的字母。(类似贪心)
center = i;
R = i + p[i];
}


龟兔赛跑算法

用于盘算一维链表里面有没有回路

struct list_node {
struct list_node *next;
void *data;
};

#define FALSE 0
#define TRUE 1
typedef unsigned char bool;

bool is_list_exist_loop(struct list_node *head)
{
/*
快指针步进长度,之前我认为可以为其它值,但是从Bean_lee的回复中知道,不能为超过循环节点个数的值。
当超过循环节点个数时,而慢结点还未步入这个循环时,快节点会一直在循环中步进直至慢节点也步入这个循环。
*/
#define FAST_POINT_STEP        2

if (!head) return FALSE;

struct list_node *fast, *slow;
unsigned int i;

/* 快慢指针都处于同一起跑线,即头指针位置 */
fast = slow = head;

while (fast) {
/* 快指针步进 */
for (i = 0; i < FAST_POINT_STEP; ++i) {
fast = fast->next;
if (fast == slow) {
/* 又碰到了慢指针,循环存在 */
return TRUE;
}
else if (!fast) {
/* 快指针跑到头了,循环不存在 */
return FALSE;
}
}

/* 慢指针步进 */
slow = slow->next;
}

return FALSE;
}


未完待续。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: