您的位置:首页 > 理论基础 > 数据结构算法

算法和数据结构总结

2014-03-31 09:21 453 查看
  本文是要将一些看过的算法进行总结,目的在于总结出对于什么题、什么特点、什么形式的题使用什么样的数据结构以及算法合适,或者反之。

1.bitmap

第一个只出现一次

2.hashmap

3.双指针、倍速指针、距离双指针、尾指针

最长回文子串、

4.stack、queue、vector

5.暴力、剪枝

6.贪心

7.DP

背包问题:放与不放、无穷背包问题。

输入两个整数n 和m,从数列1,2,3.......n 中随意取几个数,
使其和等于m ,要求将其中所有的可能组合列出来.
此题可使用01背包问题,放与不放的递归解法。
伪代码:p(i,v)
if i=v cout find;
if i>v return;
p(i-1,v);//dont put in i
p(i-1,v-i);//put in i


格子取数问题-->考虑两步的DP





LCS问题:用二维图+箭头方向  用于分析的好例子






子数组的最大和:DP,以当前节点为例,考虑前一个节点和本节点得到最优就好,其他节点不管

8.递归、递推

全排列

递归中,如何对左子树最右节点和右子树最左节点同根节点进行操作:使用head,tail 节点连接。

详见微软100题:把二元查找树转变成排序的双向链表

题目:
输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。
要求不能创建任何新的结点,只调整指针的指向。
10
/ \
6 14
/ \ / \
4 8 12 16
转换成双向链表
4=6=8=10=12=14=16。
首先我们定义的二元查找树节点的数据结构如下:
struct BSTreeNode
{i
nt m_nValue; // value of node
BSTreeNode *m_pLeft; // left child of node
BSTreeNode *m_pRight; // right child of node
};ANSWER:
This is a traditional problem that can be solved using recursion.
For each node, connect the double linked lists created from left and right child node to form a full list.
/**
* @param root The root node of the tree
* @return The head node of the converted list.
*/
BSTreeNode * treeToLinkedList(BSTreeNode * root) {
BSTreeNode * head, * tail;
helper(head, tail, root);
return head;
}
void helper(BSTreeNode *& head, BSTreeNode *& tail, BSTreeNode *root) {
BSTreeNode *lt, *rh;
if (root == NULL) {
head = NULL, tail = NULL;
return;
}
helper(head, lt, root->m_pLeft);
helper(rh, tail, root->m_pRight);
if (lt!=NULL) {
lt->m_pRight = root;
root->m_pLeft = lt;
} else {
head = root;
}i
f (rh!=NULL) {
root->m_pRight=rh;
rh->m_pLeft = root;
} else {
tail = root;
}
}


9.查找:二分。。。

10.排序:堆排序、快排、归并

查找top10 ip:归并排序+topK算法

如何给10^7个数据量的磁盘文件排序:归并+topK

最大堆、最小堆:可以使用treenode,但用数组来表示树会方便很多。

11.trie、B、B+、B*、R树、后缀树
trie树用于单词检索





后缀树:寻找最长回文子串

12.数论

13.其他技巧

14.完美洗牌方法:可以将

     a1,a2,a3,a4,b1,b2,b3,b4  变成  a1,b1,a2,b2,a3,b3,a4,b4

15.分治法

16.图及BFS、DFS

最小操作数:





17.回溯法+剪枝

回溯法是基本算法的一种,可以用于解决大致这样的问题(其实回溯法可以算是暴力搜索的一种变形,可以解决大部分的问题,因为搜索了所有可能的情况):假设我们有一个N个元素的集合{N},现在要依据该集合生成M个元素的集合{M},每一个元素的生成都依据一定的规则CHECK。

一般的,回溯法需要用一个数组记录解情况,一个数组记录节点是否被访问过的情况。

CodeFrame
void Bcktrack(int t) //参数t表示当前递归深度
{
if(t>n)Output(x); //遍历到解,则将解输出或其他处理  n用来控制递归深度即解空间树的高度
else
{
//f(n,t)和g(n,t)表示当前节点(扩展节点)处未搜索过的子树的起始编号和中指编号
for(int i=f(n,t);i<=g(n,t);i++)
{
x[t]=h(i);    //h(i)表示当前节点(扩展节点)处x[i]的第i个可选值
if(Constarint(t)&&Bound(t)) //剪枝函数:约束函数,限界函数
Bcktrack(t+1);
}
}
}


用回溯法解决此问题,我们可以划分为三个重要组成部分。
步骤
从第一步开始至第M步,每一步都从{N}中选取一个元素放入结果{M}中。
界定
每次选择一个元素时,我们都要用规则CHECK来界定{N}中的元素谁合适。界定规则的描述将决定算法的效率和性能。
回溯
如果第k步不能找到合适的元素或者需要得到更多的结果,返回到第k-1步,继续选择下一个第k-1步的元素。

例如:旅行售票员问题.

        某售货员要到若干城市去推销商品,一直各城市之间的路程,他要选定一条从驻地出发,经过每个城市一遍,最后回到住地的路线,使总的路程最短. 

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