【July程序员编程艺术】之字符串是否包含问题
2015-10-09 17:59
656 查看
题目描述:
假设这有一个各种字母组成的字符串A,和另外一个字符串B,字符串里B的字母数相对少一些。什么方法能最快的查出所有小字符串B里的字母在大字符串A里都有?
比如,如果是下面两个字符串:
String 1: ABCDEFGHLMNOPQRS
String 2: DCGSRQPO
答案是true,所有在string2里的字母string1也都有。
如果是下面两个字符串:
String 1: ABCDEFGHLMNOPQRS
String 2: DCGSRQPZ
答案是false,因为第二个字符串里的Z字母不在第一个字符串里
我的解题思路:
1.最笨的方法
任何好的方法都是将笨方法不断改进得到,因此拿到这个题目第一反应就是笨方法。对于String 2中的每一个字符,都拿到String 1中挨个找一下。这样写出来的程序是两层遍历,假设长字符串长度为n,短字符串长度为m,那么这种算法的时间复杂度是O(mn)。肯定是不好的。
2.初步改进的思路
思考如何在笨方法的基础上进行改进。笨方法中string1中的字符被重复遍历了m次,这无疑是冗余和可以优化的地方。要想减少遍历string1的次数,那么连续的两次遍历之间需要有联系才行。于是就想到了能不能先将字符串排个序,这样第一次遍历的结果就可以为第二次遍历提供帮助了。说到排序,最容易想到的自然就是快速排序算法,即July博客中所讲到的方法1.2。编写程序如下:
最近程序练得少,写快速排序程序时候花了一番功夫。自己写一篇快排程序之后感觉对快排理解更加深刻了一些。之前对于partition的实现过程不是太理解,现在有了进一步的理解如下:
对于数组[3,1,5,2,7,8],假定取3作为基准元素进行划分,那么划分的目标就是使3的左边都是小于的,3的右边都是大于3的。刚开始3处于0位置,所以左边没有元素,那么就要想办法使得右边的元素都大于3.要使得右边的元素都大于3,那么最右边的肯定需要大于3,于是就对8进行判断,ok,然后就是7,ok,然后是2。2就不符合条件了,所以把3和2对调,得到2,1,5,3,7,8.现在3的右边元素都ok了,但是左边的还无法保证,所以再从最左边的2开始.重复这样的过程,就可以实现partition。partition算法的特点是交替着从左右两侧进行判断。
看到算法1.3的时候,就想到了利用字符的特性来进一步改进算法。假设都是大写字符,那么一共就26个,所以建立长度为26的缓存数组,遍历一次长字符串就可以知道长字符串包含哪些字符。之后对于短字符串中的每个字符,就不需要再去遍历长字符了,直接根据字符减去’A’得到下标就可以知道长字符串中有没有该字符。这种做法是很巧妙的,很好的利用了字符的特性,时间复杂度也优化到了O(m+n),空间复杂度是O(1)。2.1 2.2都是这个思路。
第三种素数的方法就比较新奇了。
博客最后给了一个扩展题。a和b两个字符串,求b串包含a串的最小长度。包含指的就是b的字串包含a中每个字符。
简单想了一下,建立26个字符的缓存数组可以较好地解决问题。当b中包含重复的字符串的时候,则需要进行一些判断方可。准备有空把这个题目的程序也写写。以后遇到字符串比较的算法题,都可以往26个字符缓存数组的思路上去想。
假设这有一个各种字母组成的字符串A,和另外一个字符串B,字符串里B的字母数相对少一些。什么方法能最快的查出所有小字符串B里的字母在大字符串A里都有?
比如,如果是下面两个字符串:
String 1: ABCDEFGHLMNOPQRS
String 2: DCGSRQPO
答案是true,所有在string2里的字母string1也都有。
如果是下面两个字符串:
String 1: ABCDEFGHLMNOPQRS
String 2: DCGSRQPZ
答案是false,因为第二个字符串里的Z字母不在第一个字符串里
我的解题思路:
1.最笨的方法
任何好的方法都是将笨方法不断改进得到,因此拿到这个题目第一反应就是笨方法。对于String 2中的每一个字符,都拿到String 1中挨个找一下。这样写出来的程序是两层遍历,假设长字符串长度为n,短字符串长度为m,那么这种算法的时间复杂度是O(mn)。肯定是不好的。
2.初步改进的思路
思考如何在笨方法的基础上进行改进。笨方法中string1中的字符被重复遍历了m次,这无疑是冗余和可以优化的地方。要想减少遍历string1的次数,那么连续的两次遍历之间需要有联系才行。于是就想到了能不能先将字符串排个序,这样第一次遍历的结果就可以为第二次遍历提供帮助了。说到排序,最容易想到的自然就是快速排序算法,即July博客中所讲到的方法1.2。编写程序如下:
#include "quick_sort.h" #include <iostream> #include <string> using namespace std; template <class T> //int src[]={72,6,57,88,60,42,83,73,48,85}; int partition(T * src,T * end) { T * sp=src; //起始位置指针 T * ep=end; //结束位置指针 T tmp; T * cp=src; while(ep>sp) { while((*ep>=*cp)&&(ep>cp)) ep--; if(ep<=cp) break; swap<T>(cp,ep); cp=ep; while((*sp<=*cp)&&(sp<cp)) sp++; if(sp>=cp) break; swap<T>(cp,sp); cp=sp; } int res = cp-src; return res; } template <class T> void swap(T * a,T * b ) { T tmp; tmp=*a; *a=*b; *b=tmp; } template <class T> void quick_sort(T *src,T * end) { if(end>src) { int q = partition(src,end); quick_sort(src,src+q-1); quick_sort(src+q+1,end); } } int compare(string & l_str,string & s_str) { char * lp,*sp,*l_end,*s_end; lp=&(l_str[0]); sp=&(s_str[0]); l_end=lp+l_str.length()-1; s_end=sp+s_str.length()-1; while((lp<=l_end)&&(sp<=s_end)) { if(*lp<*sp) lp++; else { if(*lp=*sp) { lp++; sp++; } else return 0; } } if(sp<=s_end) return 0; else return 1; } void main() { string l_str("ABCDEFGHLMNOPQRS"); string s_str("DCGSRQPOV"); //string l_str("ABCDE"); //string s_str("BE"); int result = 0; int l_len = l_str.length(); int s_len = s_str.length(); char * l_st,* l_end,* s_st,* s_end; l_st=&(l_str[0]); l_end=&(l_str[0])+l_len-1; s_st=&(s_str[0]); s_end=&(s_str[0])+s_len-1; quick_sort(l_st,l_end); quick_sort(s_st,s_end); cout << "long string" << l_str << endl; cout << "short string" << s_str << endl; result=compare(l_str,s_str); cout<<"ok"<< result<<endl; }
最近程序练得少,写快速排序程序时候花了一番功夫。自己写一篇快排程序之后感觉对快排理解更加深刻了一些。之前对于partition的实现过程不是太理解,现在有了进一步的理解如下:
对于数组[3,1,5,2,7,8],假定取3作为基准元素进行划分,那么划分的目标就是使3的左边都是小于的,3的右边都是大于3的。刚开始3处于0位置,所以左边没有元素,那么就要想办法使得右边的元素都大于3.要使得右边的元素都大于3,那么最右边的肯定需要大于3,于是就对8进行判断,ok,然后就是7,ok,然后是2。2就不符合条件了,所以把3和2对调,得到2,1,5,3,7,8.现在3的右边元素都ok了,但是左边的还无法保证,所以再从最左边的2开始.重复这样的过程,就可以实现partition。partition算法的特点是交替着从左右两侧进行判断。
看到算法1.3的时候,就想到了利用字符的特性来进一步改进算法。假设都是大写字符,那么一共就26个,所以建立长度为26的缓存数组,遍历一次长字符串就可以知道长字符串包含哪些字符。之后对于短字符串中的每个字符,就不需要再去遍历长字符了,直接根据字符减去’A’得到下标就可以知道长字符串中有没有该字符。这种做法是很巧妙的,很好的利用了字符的特性,时间复杂度也优化到了O(m+n),空间复杂度是O(1)。2.1 2.2都是这个思路。
第三种素数的方法就比较新奇了。
博客最后给了一个扩展题。a和b两个字符串,求b串包含a串的最小长度。包含指的就是b的字串包含a中每个字符。
简单想了一下,建立26个字符的缓存数组可以较好地解决问题。当b中包含重复的字符串的时候,则需要进行一些判断方可。准备有空把这个题目的程序也写写。以后遇到字符串比较的算法题,都可以往26个字符缓存数组的思路上去想。
相关文章推荐
- 记:新浪微博iOS客户端开发的电话面试
- 黑马程序员---成长之路-----OC之基础篇类的继承和派生
- 2014,甲午马年,闪电辞职,马上创业
- 各笔试面试题
- 测试人员的职业修养
- 面试题36:数组中的逆序对
- 面试题35:第一个只出现一次的字符
- 面试题34:丑数
- 面试题33:把数组排成最小的数
- 程序员笑话大全(程序员这些笑话,你都懂吗)
- 面试题32:从1到n整数中1出现的次数
- 面试题31:连续子数组的最大和
- 面试
- 人在职场,如何进行“功利性”阅读
- 海量数据处理:十道面试题与十个海量数据处理方法总结
- 黑马程序员---成长之路-----OC之基础篇self关键字
- Android面试题2( 有答案)
- 黑马程序员---Java异常和文件
- 一些编程面试题
- 【扣丁学堂】“野生”程序员