字符串包含问题

问题描述:

两个字符串S1和S2,假设S1长度大于等于S2长度,判断S2是否为S1的一个子集。
例如:S1=ABCDEFGHI, S2=ACEFG,由于S2中的每个元素都出现在S1中,说明S1包含S2.
若S2=ACEFGK, 由于K不在S1中,因此S1不包含S2。


设S1长度为m,S2长度为n
方法1:
Brute-Force 两个for loop,复杂度为O(m*n)

public static boolean compare(String[] s1, String[] s2){
	//s1:longString[]; s2:shortString[]
	int i,j;
	
	for(i = 0; i<s2.length;i++)
	{
		for(j = 0; j<s1.length; j++)
		{
			if(s2[i].compareTo(s1[j])==0)
				break;
		}
		//s2中的一个字符遍历了s1还是没找到,即没有执行break使得j达到了s1.length
		if (j==s1.length) return false;
	}
	return true;
}

方法2:
对s1和s2先排序,例如quicksort,则复杂度为O(mlgm)+O(nlgn)+O(m+n)
首先是quicksort部分

public static int partition(String[] array,int lo, int hi){
	String pivot = array[lo];
	int i = lo;
	int j = lo + 1;
	while(j<=hi){
		if(array[j].compareTo(pivot)<0){
			i++;
			exch(array,i,j);
		}
		j++;
	}
	exch(array,lo,i);
	return i;
}
private static void exch(String[] array, int i, int j){
	String temp = array[i];
	array[i] = array[j];
	array[j] = temp;
}
public static void quickSort(String[] array){
	quickSort(array, 0, array.length-1);
}
private static void quickSort(String array[], int lo, int hi){
	if(hi<=lo) return;
	int i = partition(array,lo,hi);
	quickSort(array,lo,i-1);
	quickSort(array,i+1,hi);
}

在执行下面的代码前,要对s1和s2用quicksort重新排好序。

public static boolean compare(String[] s1, String[] s2){
	int p1 = 0;
	int p2 = 0;
	while(p1<s1.length && p2<s2.length){
		while(s1[p1].compareTo(s2[p2])<0 && p1<s1.length-1) p1++;
		if(s1[p1].compareTo(s2[p2])!=0) break;
		p2++;
	}
	if(p2==s2.length) return true;
	else return false;
}



方法3
利用counting sort,可以将复杂度降低至线性。即O(m) + O(n) + O(m+n) = O(m+n)
计数排序的代码如下:

public static String[] countingSort(String[] array){
	int[] c = new int[26];
	for (int i = 0; i <26; i++)
	{
		c[i] = 0;
	}
	String[] b = new String[array.length];
	//初始化辅助数组
	for (int i = 0; i<array.length; i ++)
	{
		int ind = ((int)array[i].toCharArray()[0] - (int)("a".toCharArray())[0]);
		c[ind] = c[ind] + 1;
	}
	for (int i = 1; i<26; i++)
	{
		c[i] = c[i] + c[i-1];
	}
	for(int i = array.length-1; i>=0; i--)
	{
		int ind = ((int)array[i].toCharArray()[0] - (int)("a".toCharArray())[0]);
		b[c[ind]-1] = array[i];
		c[ind] = c[ind] - 1;
	}
	return b;
}

之后如同方法2,调用compare即可

方法4
用hashtable,将短的字符串的每个元素存储在一张hash table中,O(n)。然后对长字符串进行遍历,看hash(s1[i])映射到的slot是否已经有元素了。如果全部都有,则说明s1包含s2,如果有一个slot是空的,则说明s1不包含s2. 复杂度O(m)。所以总的复杂度是线性的。O(m+n)

public static boolean compare(String[] s1, String[] s2){
	int[] hash = new int[26];//初始化hash
	for(int i = 0; i<hash.length-1; i++)
	{
		hash[i] = 0;
	}
	int num = 0;
	for(int i = 0; i<s2.length;i++)//扫描短字符串
	{
		int ind = ((int)s2[i].toCharArray()[0] - (int)("a".toCharArray())[0]);
		if (hash[ind] == 0)
		{
			hash[ind] = 1;
			num++;
		}
	}

	for(int i = 0; i<s1.length; i++)//扫描长字符串
	{
		int ind = ((int)s1[i].toCharArray()[0] - (int)("a".toCharArray())[0]);
		if(hash[ind] == 1)
		{
			hash[ind] = 0;
			num--;//一个字符匹配到
			if(num==0) break;
		}
	}
	if(num==0) return true;
	else return false;
}
点赞