实习期间整理了一些自己觉得比较有意思的算法题,纯属个人意见。。。
程序 = 数据结构 + 算法
这一点现在是深深地体会到了,感觉很多问题算法很重要,但是如果你采用了合适的数据结构,就可以使问题简化
位图:大数据时进行排序,去重,查找重复的整数等等
哈希表:大数据时进行排序,查找重复的整数等等
字典树:一般用来处理大量字符串了
在求解的过程中可以发现哈希是一个很有用的数据结构
1.rand()函数能产生0-4的五个整数,且这些整数的概率相等,如何利用这个函数等概率的生成0-6的7个整数
思路:利用rand()*n+rand()产生0-4n+4的整数,那n的取值就取决于是否可以使概率相等,一般产生的数的个数都会大于7的倍数,那就将超过的部分截取掉,剩下的就进行0-6的一一对应
具体的思路可以参照:http://blog.csdn.net/happyzhuque/article/details/8109401
PS:这道题腾讯面试的时候问过
2.a1 a2 a3 a4 b1 b2 b3 b4 -> a1 b1 a2 b2 a3 b3 a4 b4 时间复杂度:O(n) 空间复杂度:O(1)
完美洗牌算法 :下标从1开始
a1 a2 b1 b2 a3 a4 b3 b4 将前n部分的后n/2和后n部分的前n/2交换,形成两个部分,接着这两部分分别用完美洗牌算法
就是将a[(2*i)%(2*n+1)] =a[i] 得到b1 a1 b2 a2 b3 a3 b4 a4 (下标从1开始)
如果下标从0开始,a[2(i+1)%(2*n+1)-1] =a[i]
再将他们两两交换即可
ps:以上例子是偶数个的数据的情况,若数据的个数为奇数,可以先将最中间的数移动到末尾,之后再按照上述思想来做
之前我觉得也可以不用先交换前n部分的后n/2和后n部分的前n/2,可以直接a[(2*i)%(2*n+1)] =a[i],只是在赋值的时候可以用临时变量保存替换的那个值和位置,接着再直接移动刚刚被替换的那个值,此外,用一个计数器来累加移动的数的个数,当移动的个数=2n的时候就说明所有的数据移动完成了,后来编程实现的时候发现这种想法是有问题的,有的元素不会出现被替换
3.A,B是两个整数的集合,求A,B的交集
我自己的思路:先将A,B两个集合排序(升序),用快排或者堆排序,之后从两个集合的第一个元素即最小值开始遍历,如果A的值小于B,A往后移动,如果B的值小于A,B往后移动,如果两个值相等,即为交集的一部分,输出,接着都往后移动
时间复杂度:O(nlogn) 空间复杂度:根据具体的排序算法而定了
集合压缩法:我觉得这种算法还是挺灵活的,它的基本思想就是通过比较两个集合的最小最大值,接着不断缩减两个集合的范围直至某一个集合为空 时间复杂度:O(n)
具体可以参考:http://blog.csdn.net/thebestdavid/article/details/12056293
PS:所以说一个问题可以用多种算法去解决,关键就在于多想
4.从一个数列中选取和为某个值的两个数
假设数列已经排好序,否则先排序
第一种:穷举法 时间复杂度:O(n*2)
第二种:哈希查找 遍历数列,查找差值是否在哈希表中 时间复杂度:O(n) 空间复杂度:O(n)
第三种:设置两个指针,分别指向首尾两个元素 若指针所指向的元素和为指定值,则输出,接着头指针往后移动,尾指针往前移动,若大于指定值,则往前移动尾指针,若小于指定值,则往后移动头指针 时间复杂度:O(n) 空间复杂度:O(1)
拓展:如果选取和为某值的多个数: 动态规划
5.求字符串中最长回文串
循环:逐个逐个截取字符串,然后判断字符串是否为回文串 O(n*4)
中心拓展法:以单个字符为中心点,之后向两边延伸,判断是否对称 O(n*2) 要考虑字符串的长度为奇数还是偶数 如果是奇数的话,则j = i-1;k=i+1 如果是偶数的话j = i;k=i+1
Manacher算法:不太懂,插入字符 O(n)
6.三色球的问题
可以设置三个指针,cur,begin,end,利用快速排序的思想
cur = begin= 0 end=n-1
if a[cur] = 1 cur++
if a[cur] = 0 begin++ cur++
if a[cur] = 2 end--
PS:这个很经典了,相信大多数人都懂这个算法的思想了。。。
未完待续。。。