1.概念
- 串(String)是由零个或多个字符组成的有限序列,又名叫字符串。串中的字符数目n称为串的长度,定义中谈到“有限”是指长度n是一个有限的数值。零个字符的串称为空串(null string), 它的长度为零,可以直接用两双引号""表示
- 空格串,是只包含空格的串。注意它与空串的区别,空格串是有内容有长度的,而且可以不止一个空格。
- 主串中任意个数的连续字符组成的子序列称为该串的子串,子串在主串中的位置就是子串的第一个字符在主串中的序号。
2.串的比较
给定两个串: s= “a1…an”,t= “b1…bm”
- 比较两个串是否相等,必须是它们串的长度以及它们各个对应位置的字符都相等。 比较是基于字符串中每个字符的Unicode值。
- 那么对于两个串不相等时:
- n<m,且ai=bi (i=1, 2,… n)。例如当s=“hap", t=“happy”, 就有s<t
- 存在某个k<min (m, n),使得ai=bi (i=1, 2, … k-1),ak<bk ,例如当s=“happen", t=“happy”,因为两串的前 4个字母均相同,而两串第5个字母(k 值),e<y,所以s<t。
3.常用函数
-
public char charAt(int index)
返回char指定索引处index的值。 指数范围为0至length() - 1,该序列的第一个char值在索引0 -
public int compareTo(String anotherString)
按字典顺序比较两个字符串,由该String对象表示的字符序列按字典顺序与由参数字符串表示的字符序列进行比较。 如果String对象小于参数字符串,结果小于0。如果String对象大于参数字符串,结果大于0。 如果字符串相等,结果为零; compareTo返回0 ,当equals(Object)方法将返回true 。如果它们在一个或多个索引位置具有不同的字符,则令k为最小的索引; 在这种情况下, compareTo返回两个字符串中位置k处的两个字符值的差值,this.charAt(k)-anotherString.charAt(k)
如果没有它们不同的索引位置,则较短的字符串按字典顺序位于较长的字符串之前。在这种情况下,compareTo返回字符串长度的差值:this.length()-anotherString.length()
-
public static String valueOf(char[] data,int offset,int count)
返回char数组参数的特定子阵列的字符串形式。 offset参数是子阵列的第一个字符的索引。 count参数指定被复制的子数组的长度,后两个参数可省略 -
public boolean isEmpty()
判断字符串是否为空 -
public String concat(String str)
将指定的字符串连接到该字符串的末尾:"to".concat("get").concat("her") returns "together"
… 更多函数详情见String API
4.串的存储结构
4.1顺序存储
串的顺序存储结构是用一组地址连续的存储单元来存储串中的字符序列的。按照预定义的大小,为每个定义的串变量分配一个固定长度的存储区。一般是用定长数组来定义。既然是定长数组,就存在一个预定义的最大串长度,一般可以将实际的串长度值保存在数组的0下标位置,有时候也可能在串值后面加一个不计入串长度的结束标记字符,比如“\0" 来表示串值的终结
4.2链式存储
每个节点可以存放一个字符,也可以存放多个字符,若存放多个字符,假如最后一个节点没有填满,用#或非串值字符补全
5.朴素的模式匹配算法
/*返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数返回值为0。*/
/* T非空,1≤pos≤Strength(s)。*/
int Index(string s, String T, int pos){
int i = pos; // i用于主串S中当前位置下标
int j=1; // j用于子串T中当前位置下标值
while(i<= S[0]&&j<= T[0]) /*若i小于s长度且j小于T的长度时循环*/
{
if (S[i] == T[j]) /*两字母相等则继续*/
{
++i;
++j;
}
else//指针后退重新开始匹配
{
i =i-j+2;/*i退回到上次匹配首位的下一位*/
j=1;/*j退回到子串T的首位*/
}
}
if(j>T[0]) return i-T[0];
else return 0;
最好的情况是时间复杂度为O(1)。一般来说,时间复杂度为O(n+m), 其中n为主串长度,m为要匹配的子串长度。根据等概率原则,平均是(n+m) /2 次查找,时间复杂度为O(n+m)。
最坏的情况是每次不成功的匹配都发生在串的最后一个字符。时间复杂度为O((n-m+1)*m)
6.KMP模式匹配算法
6.1原理
如果p1…pj-1 只包含一个字母,没有相等一说,属于其他情况;
如果p1…pk-1 只包含一个字母,那么代表只有一个相等,k-1=1,k=2
很能懂的借鉴链接
6.2算法实现
public class kmp_first {
public static void main(String[] args) {
String str="ababcabcacbab";
String T="abc";
System.out.println(INDEX_KMP(str,T,0));
}
// j= 1 2 3 4 5 6 7 8 9
//next[j]= 0 1 x x x x x x x
public static int[] get_next(String str){
int i,j;//i表示当前字符串长度 j用来遍历子串数组str
int []next=new int[str.length()+1];
i=0;j=-1;
next[0]=-1;
while(i<str.length())//字符第一位 表示长度
{
if(j==-1||str.charAt(i)==str.charAt(j)){
j++;
i++;
next[i]=j;
}else{
j=next[j];
}
}
return next;
}
//KMP
public static int INDEX_KMP(String str,String T,int pos){//要求使pos下标之后能否找到匹配字符串
int i=pos;//i是主串坐标
int j=-1;//子串坐标
int [] next=get_next(T);
while(i<str.length()&&j<T.length()){
if(j==-1||str.charAt(i)==T.charAt(j)){
i++;
j++;
}else{
j=next[j];
}
}
if(j==T.length()){
return i-j;
}else{
return -1;
}
}
}