Chaptert1--Arrays_and_Strings

1.1Implement an algorithm to determine if a string has all unique characters. What if you can not use additional data structures?

即:实现一个算法来判断一个字符串中所有的字符是否都是唯一的(没有重复字符)。如果你不能使用额外的数据结构。

        作为简化,假设字符集是ASCII(如果不是,我们需要增加存储空间,其余的逻辑都是一样的)。注意:如果把这个问题指出给面试官将会是很出彩的表现。

#include<iostream>
#include<string>
#include<stdlib.h>
#include<algorithm>
#include<memory.h>
using namespace std;

//时间复杂度是O(n),空间复杂度是O(n)
bool isUniqueChars1(string str)
{
	bool char_set[256];
	memset(char_set,0,sizeof(char_set));
	for(int i=0;i<str.length();i++)
	{
		int val=(int)str[i];   //把char类型转换成为int类型,用val来指示相应字符的ASCII码
		if(char_set[val])  return false;   //如果所对应的字符存在,即有相同字符,那么返回false
		char_set[val]=true;       //如果相应字符第一次出现,那么将其标记为true		
	}
	return true;                //遍历所有字符都没有重复,则返回true
}

//时间复杂度为O(n),我们还可以通过位运算来减少空间的使用量。 用每一位表征相应位置字符的出现。
//对于ASCII字符,我们需要256位,即一个长度为8的int 数组a即可。这里的关键是要把字符对应的数字,
//映射到正确的位上去。比如字符'b'对应的代码是98,那么我们应该将数组中的哪一位置为1呢?
//用98除以32,得到对应数组a的下标: 3。98对32取模得到相应的位:2
bool isUniqueChars2(string str)
{
	int a[8];
	for(int i=0;i<str.length();i++)
	{
		int val=(int)str[i];
		int row=val/32,col=val%32;
		if(a[row]&(1<<col))  return false;  //将1相左移动col位
		a[row] |= (1<<col);
	}
	return true;
}

//情况与2类似,但是有一个限制就是字符str[i]与'a'的距离不能太大以至于超过32,因为int checker最多32bit
//太大会造成移位越界
bool isUniqueChars3(string str)
{
	int checker=0;
	for(int i=0;i<str.length();i++)
	{
		int val=(int)(str[i]-'a');
		if(checker & (1<<val))   return false;
		checker |= (1<<val);
	}
	return true;
}

//时间复杂度O(n^2),空间复杂度为零,暴力匹配,时间复杂度最低
bool isUniqueChars4(string str)
{
	for(int i=0;i<str.length();i++)
	{
		for(int j=i+1;j<str.length();j++)
		{
			if(str[i]==str[j])  return false;
		}
	}
	return true;
}

//排序的时间复杂度为O(nlogn),遍历数组时间复杂度O(n)
bool isUniqueChars5(string str)
{
	sort(str.begin(),str.end());       //调用sort对str进行排序
	for(int i=0;i<str.length()-1;i++)
	{
		if(str[i]==str[i+1]) return false;
	}
	return true;
}

int main()
{
	string str1="I come from China.";
	string str2="abcdefghijklmnopqrstuvwxyz";
	cout<<"Case 1 : "<<isUniqueChars1(str1)<<","<<isUniqueChars1(str2)<<endl;
	cout<<"Case 2 : "<<isUniqueChars2(str1)<<","<<isUniqueChars2(str2)<<endl;
	cout<<"Case 3 : "<<isUniqueChars3(str1)<<","<<isUniqueChars3(str2)<<endl;
	cout<<"Case 4 : "<<isUniqueChars4(str1)<<","<<isUniqueChars4(str2)<<endl;
	cout<<"Case 5 : "<<isUniqueChars5(str1)<<","<<isUniqueChars5(str2)<<endl;
	return 0;
}
运行结果:

Chaptert1--Arrays_and_Strings_第1张图片


1.2:Write code to reverse a C-Style String. (C-String means that “abcd” is represented as five characters, including the null character.)

即:写一段代码来转置C-类型的字符串.(C类型的字符串说明"abcd"代表五个字符,其中包括空字符.)

代码:

#include<iostream>
#include<string.h>
using namespace std;


void 
reverse1(char *str)
{
	char *p=str;
	if(str)      //如果str!=NULL则继续
	{
		while(*p)   //直到*p为空字符
			p++;
	}
	p--;        //跳过空字符
	char tmp;
	while(str<p) //指针str从左向右移动,指针p从右向左移动
	{
		tmp=*str;
		*str++=*p;
		*p--=tmp;
	}
}

//代码相对于reverse1更简洁
void
reverse2(char* str)
{
	char tmp;
	for(int i=0,j=strlen(str)-1 ; i<j ; i++,j--)
	{
		tmp=str[i];
		str[i]=str[j];
		str[j]=tmp;
	}
}


int main()
{
	char str1[]="abcdefghijklmnopqrstuvwxyz";
	char str2[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	reverse1(str1);
	cout<<"str1 : "<<str1<<endl;
	reverse2(str2);
	cout<<"str2 : "<<str2<<endl;
	return 0;
}
运行:



1.3:Design an algorithm and write code to remove the duplicate characters in a string without using any additional buffer. NOTE: One or two additional variables are fine. An extra copy of the array is not.
FOLLOW UP Write the test cases for this method.

即:设计一个算法来写出代码去除一个字符串中重复的字符,不能使用任何额外的数组。注意:一个或者两个变量时可以的,但是整个数组的拷贝时不能接受的。

测试用例:

1).不包含任何重复字符,例如:abcde

2).全都是重复字符,例如:aaaa

3).空字符

4).连续重复的字符,例如:aaabbb

5).不连续重复的字符,例如:abababa

代码:

#include<iostream>
#include<string.h>
#include<memory.h>
using namespace std;

//时间复杂度为O(n^2),有点像是尾插法,第i(2,3,...,n)个元素,依次和前tail个各不相同的元素比较,
//没有匹配的,那么插入尾部。
void 
rmDumplicate0(char* str)
{
	if(str==NULL)  return ;
	int len=strlen(str);
	if(len<2)  return ;
	int i,j;
	int tail=1;
	for(i=1;i<len;i++)    //遍历所有元素
	{
		for(j=0;j<tail;j++)    //判断str[i]和前tail项是否有匹配
		{
			if(str[j]==str[i])  break;
		}
		if(j==tail)            //如果没有匹配的那么就插入尾部            
		{
			str[tail]=str[i];
			tail++;
		}	
	}
	str[tail]='\0';
}

//时间复杂度为O(n^2),和rmDumplicate1相反,这是把每个元素和后面的元素相比较,如果相同就替换为
//空格
void 
rmDumplicate1(char* str)
{
	if(str==NULL)  return ;
	int len=strlen(str);
	if(len<2) return ;
	for(int i=0;i<len-1;i++)
	{
		for(int j=i+1;j<len;j++)
		{
			if(str[i]==str[j])        
			{
				str[j]=' ';
			}
		}
	}
}

//时间复杂度为O(n),假设输入的字符为ASCII码,那么就可以把每个元素映射到一个布尔类型长度为256的数组中去
void rmDumplicate2(char* str)
{
	if(str==NULL) return ;
	int len=strlen(str);
	if(len<2)  return ;
	bool hit[256];
	memset(hit,0,sizeof(hit));
	hit[str[0]]=true;
	int tail=1;
	for(int i=1;i<len;i++)
	{
		if(hit[str[i]]==false)   
		{
			str[tail++]=str[i];		
			hit[str[i]]=true;     //把出现过的字符映射设置为true
		}
	}
	str[tail]='\0';
}

//假设输入的字符为'a'--'z'的情况下,算法的时间复杂度为O(n),定义一个int类型的变量,可以表示32位,通过
//
void 
rmDumplicate3(char* str)
{
	if(str==NULL)  return ;
	int len=strlen(str);
	if(len<2) return ;
	int checker=0,tail=0;
	for(int i=0;i<len;i++)
	{
		int val=(int)(str[i]-'a');
		if( ( checker & (1<<val) ) == 0 )
		{
			str[tail++]=str[i];
			checker |= (1<<val);
		}
	}
	str[tail]='\0';
}

int main()
{
	char s1[][10]={"abcde","abcde","abcde","abcde"};
	char s2[][10]={"aaabbb","aaabbb","aaabbb","aaabbb"};
	char s3[][10]={"","","",""};
	char s4[][10]={"abababa","abababa","abababa","abababa"};
	char s5[][10]={"aaaa","aaaa","aaaa","aaaa"};
	/*对数组s1进行操作*/
        cout<<"Case 1 :"<<endl;
	rmDumplicate0(s1[0]);
	cout<<s1[0]<<endl;
	rmDumplicate1(s1[1]);
	cout<<s1[1]<<endl;
	rmDumplicate2(s1[2]);
	cout<<s1[2]<<endl;
	rmDumplicate3(s1[3]);
	cout<<s1[3]<<endl;
	
	/*对数组s2进行操作*/
        cout<<"Case 2 :"<<endl;
	rmDumplicate0(s2[0]);
	cout<<s2[0]<<endl;
	rmDumplicate1(s2[1]);
	cout<<s2[1]<<endl;
	rmDumplicate2(s2[2]);
	cout<<s2[2]<<endl;
	rmDumplicate3(s2[3]);
	cout<<s2[3]<<endl;

	/*对数组s3进行操作*/
        cout<<"Case 3 :"<<endl;
	rmDumplicate0(s3[0]);
	cout<<s3[0]<<endl;
	rmDumplicate1(s3[1]);
	cout<<s3[1]<<endl;
	rmDumplicate2(s3[2]);
	cout<<s3[2]<<endl;
	rmDumplicate3(s3[3]);
	cout<<s3[3]<<endl;

	/*对数组s4进行操作*/
        cout<<"Case 4 :"<<endl;
	rmDumplicate0(s4[0]);
	cout<<s4[0]<<endl;
	rmDumplicate1(s4[1]);
	cout<<s4[1]<<endl;
	rmDumplicate2(s4[2]);
	cout<<s4[2]<<endl;
	rmDumplicate3(s4[3]);
	cout<<s4[3]<<endl;

	/*对数组s5进行操作*/
        cout<<"Case 5 :"<<endl;
	rmDumplicate0(s5[0]);
	cout<<s5[0]<<endl;
	rmDumplicate1(s5[1]);
	cout<<s5[1]<<endl;
	rmDumplicate2(s5[2]);
	cout<<s5[2]<<endl;
	rmDumplicate3(s5[3]);
	cout<<s5[3]<<endl;

	return 0;
}
运行结果:

Chaptert1--Arrays_and_Strings_第2张图片



1.4:Write a method to decide if two strings are anagrams or not.

即:写一个函数来判断两个字符串是否是变位词。所谓的变位词就是指两个字符串的组成字符一样,但是字符的顺序可能会不一致。

算法1:时间复杂度为O(n).去检测两个字符串中每个独立的字符是否具有相同的个数。

算法2:时间复杂度为O(nlogn).首先对字符串进行排序,然后再进行比对。

通过代码进行分析:

#include<iostream>
#include<string.h>
#include<memory.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;

//算法1:时间复杂度为O(n).去检测两个字符串中每个独立的字符是否具有相同的个数。
bool IsAnagram1(string s,string t)
{
	if(s.length()!=t.length()) return false;//如果两个字符串长度不同,一定不会是变位词
	int len = s.length();
	int flag[256]={0} , i;
	memset(flag,0,sizeof(flag));
	int num_unique_chars=0;    //互不相同的字符的个数
	int num_completed_t=0;
	for(i=0;i<len;i++)      //对字符串s进行处理
	{
		int loc=(int)s[i];  //得到每个字符s[i]的ASCII码,将他们映射到数组flag中,并统计同一字符出现的频次
		if(flag[loc]==0) ++num_unique_chars;
		++flag[loc];
	}
	for(i=0;i<len;i++)      //对字符串t进行处理
	{
		int loc=(int)t[i];
		if(flag[loc]==0)  return false;
		--flag[loc];
		if(flag[loc]==0)
		{
			++num_completed_t;
			if(num_unique_chars == num_completed_t)
			{
				return (i == len-1)?true:false;
			}
		}
	}
	return false;
}

//算法2:时间复杂度为O(nlogn).首先对字符串进行排序,然后再进行比对。
bool IsAnagram2(string s,string t)
{
	if( s.length()!=t.length() ) return false;//如果两个字符串长度不同,一定不会是变位词
	sort(s.begin(),s.end());    //对s进行排序
	sort(t.begin(),t.end());    //对t进行排序
	return ( s==t ) ? true:false;    //如果相同则说明是变位词,否则不是
}

int main()
{
	/*测试用例*/
	string s="abcde";
	string t="edcba";
	string s1="abcabcabc";
	string t1="cbacbacba";
	string s2="aaabbb";
	string t2="bbbccc";

	if(IsAnagram1(s,t))  cout<<"IsAnagram"<<endl;
	else cout<<"IsNotAnagram"<<endl;

	if(IsAnagram1(s1,t1))  cout<<"IsAnagram"<<endl;
	else cout<<"IsNotAnagram"<<endl;

	if(IsAnagram1(s2,t2))  cout<<"IsAnagram"<<endl;
	else cout<<"IsNotAnagram"<<endl;

	return 0;
}

运行结果:

Chaptert1--Arrays_and_Strings_第3张图片


1.5:Write a method to replace all spaces in a string with ‘%20’.

即:写一个函数来把一个字符串中的所有空格代替成为'%20'。

算法:

1). 首先遍历一遍字符串统计空格的总数;
2). 然后从后向前再次对字符串进行解析:
·如果遇到了空格,那么将它替换为"%20";

·否则,把这个字符移动到新的空间中去。


代码:

#include<iostream>
#include<string.h>
using namespace std;

void ReplaceFun(char *str)
{
	int NumOfSpace = 0 ,newLength,i=0;
	int len=strlen(str);
	/*统计空格的总个数*/
	for(i=0;i<len;i++)
	{
		if(str[i]==' ')  NumOfSpace++;
	}
	newLength=len+2*NumOfSpace;    //得到将空格替换为'%20'后的字符串新长度
	str[newLength--]='\0';
	for(i=len-1;i>=0;i--)
	{
		if(str[i]!=' ')  str[newLength--]=str[i];    //如果字符不是空格那么赋值即可
		else                                         //否则将空格替换为'%20' 
		{
			str[newLength--]='0';
			str[newLength--]='2';
			str[newLength--]='%';
		}
	}
}

int main()
{
	/*测试用例*/
	char s1[100]="I am the best one!";
	char s2[100]="   he he he   !";
	ReplaceFun(s1);
	ReplaceFun(s2);
	cout<<s1<<endl;
	cout<<s2<<endl;
	return 0;
}
运行结果:




1.6:Given an image represented by an NxN matrix, where each pixel in the image is 4 bytes, write a method to rotate the image by 90 degrees. Can you do this in place?

即:给你一张由N*N表示的图片,图像中的每一个像素为4个字节,写一个算法来把这张图片旋转90度。你能原地完成吗?(即不使用额外的空间)

算法:我们假设按照逆时针对对矩阵进行旋转,假设逆时针旋转90度。例如

1  2  3           3  6  9

4  5  6  ==> 2  5  8

7  8  9           1  4  7

第一步:交换主对角线两侧的对称元素。

第二步:交换第i行和第n-1-i行,即得到结果。(只需要循环遍历半个列长度的矩阵)

代码:

#include<iostream>
#include<stdlib.h>
#include<math.h>
using namespace std;

void Swap(int &a, int &b)    //原地交换两个整数
{
	a^=b;
	b^=a;
	a^=b;
}

void rotate(int *matrix[],int n)
{
	for(int i=0;i<n;i++)	    //第一步:交换主对角线两侧的对称元素。
		for(int j=i+1;j<n;j++)
		{
			Swap( *((int*)matrix+n*i+j),*((int*)matrix+n*j+i) );    //相当于:Swap(matrix[i][j],matrix[j][i])
			
		}

	for(int i=0;i<n/2;i++)    //交换第i行和第n-1-i行,即得到结果。(只需要循环遍历半个列长度的矩阵)
		for(int j=0;j<n;j++)
		{
			Swap( *((int*)matrix+n*i+j),*((int*)matrix+n*(n-1-i)+j) );  //相当于:Swap(matrix[i][j],matrix[n-1-i][j])
		}
}

void display(int **matrix,int n)    //输出矩阵
{
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
			cout<<*((int*)matrix+n*i+j)<<" ";    //matrix[i][j]
		cout<<endl;
	}
	cout<<endl;
}

int main()
{
	int dimension;
	
	int a[4][4]=
	{
		{1,2,3,4},
		{5,6,7,8},
		{9,10,11,12},
		{13,14,15,16}
	};
	dimension=(int)sqrt(sizeof(a)/4);
	cout<<"dimension:"<<dimension<<endl;
	cout<<"before rotate:"<<endl;
	display((int**)a,dimension);
	rotate((int**)a,dimension);
	cout<<"after rotate:"<<endl;
	display((int**)a,dimension);

	int b[3][3]=
	{
		{1,2,3},
		{4,5,6},
		{7,8,9}
	};
	dimension=(int)sqrt(sizeof(b)/4);
	cout<<"dimension:"<<dimension<<endl;
	cout<<"before rotate:"<<endl;
	display((int**)b,dimension);
	rotate((int**)b,dimension);
	cout<<"after rotate:"<<endl;
	display((int**)b,dimension);
	return 0;
}
运行结果:

Chaptert1--Arrays_and_Strings_第4张图片

关于函数传递不同纬度的二维数组的方法和原理:http://blog.csdn.net/liyongbao1988/article/details/7463481


1.7:Write an algorithm such that if an element in an MxN matrix is 0, its entire row and column is set to 0.

即:实现一个算法,如果一个M*N的矩阵中的某个元素为0,那么把这个元素所在的行和列的元素全部置0。

算法:

1)一个这个题目好像很简单,只需要遍历矩阵中的每个元素,遇到一个0,那么就将它的行和列全都置0,但是如果这么下去,无法标记矩阵中的0是原来的0还是变化之后的0,最后整个矩阵全都会被变为0。

2)还有一种方法就是另外设置一个矩阵来标记0的位置。然后再第二次遍历矩阵来设置0.这样将会花费O(M*N)的空间。

3)实际上我们只需要O(M+N)的空间来进行,设置一个行数组row[m],列数组column[n]来记录原矩阵中某0元素所在行和列的情况,然后遍历row和column数组,将原矩阵相应的行和列置0。

代码:

#include<iostream>
#include<memory.h>
#include<string>
using namespace std;

void setZeros(int **matrix,int m,int n)
{
	int row[m],column[n];
	memset(row,0,sizeof(row));
	memset(column,0,sizeof(column));
	//store the row and column index with value 0
	for(int i=0;i<m;i++)
	{
		for(int j=0;j<n;j++)
		{
			if( *((int*)matrix+n*i+j) == 0 )// matrix[i][j]==0
			{
				row[i]=1;
				column[j]=1;
			}
		}
	}
	//set arr[i][j] to 0 if either row i or column j has a 0
	for(int i=0;i<m;i++)
	{
		for(int j=0;j<n;j++)
		{
			if( row[i]==1 || column[j]==1  )
			{
				*((int*)matrix+n*i+j)=0;//matrix[i][j]=0;
			}
		}
	}
}

void display(int **matrix , int m ,int n)
{
	for(int i=0;i<m;i++)
	{
		for(int j=0;j<n;j++)
			cout<<*((int*)matrix+n*i+j)<<" ";
		cout<<endl;
	}
}

int main()
{
	int a[3][4]=
	{
		{0,1,1,0},
		{1,1,1,1},
		{0,1,0,1}
	};
	setZeros((int**)a,3,4);
	cout<<"a:"<<endl;
	display((int**)a,3,4);
	
	int b[5][4]=
	{
		{1,0,1,0},
		{0,1,1,0},
		{0,0,1,1},
		{1,0,1,1},
		{1,1,1,1}
	};
	setZeros((int**)b,5,4);
	cout<<"b:"<<endl;
	display((int**)b,5,4);

	return 0;
}

运行结果:

Chaptert1--Arrays_and_Strings_第5张图片


1.8:Assume you have a method isSubstring which checks if one word is a substring of another. Given two strings, s1 and s2, write code to check if s2 is a rotation of s1 using only one call to isSubstring (i.e., “waterbottle” is a rotation of “erbottlewat”).

即:假设有一个函数isSubstring,它可以判断一个单词是否是另一个单词的子串。现在有两个string类型的字符串s1,s2,写代码来判断只调用一次isSubstring,s2是不是s1的自转。(例如,"waterbottle"是"erbottlewat"的自转)

算法:只需要做如下的检验:

1).判断s1和s2的长度是否相等。如果不等,那么返回false。

2).然后将s1自身串联起来得到s1s1,然后观察s2是不是s1s1的子串即可。

input: s1 = apple, s2 = pleap ==> apple is a substring of pleappleap
input: s1 = apple, s2 = ppale ==> apple is not a substring of ppaleppale

代码:

#include<iostream>
#include<string>
using namespace std;

bool isSubstring(string s1,string s2)    //判断s1是否包含s2子串的函数 
{
	if(s1.find(s2)!=string::npos) return true;    //关于npos的定义参考:http://www.cnblogs.com/web100/archive/2012/12/02/cpp-string-find-npos.html 
	else return false;
}

bool isRotation(string s1,string s2)
{
	if( s1.length()!=s2.length() ) return false;
	string s1s1=s1+s1;
	return isSubstring(s1s1,s2);
}


int main()
{
	string s1="apple",s2="pleap";
	string s3="waterbottle",s4="bottlewater";
	string s5="apple",s6="ppale";

	if(isRotation(s1,s2)) cout<<"isRotation"<<endl;
	else cout<<"notRotation"<<endl;
	if(isRotation(s3,s4)) cout<<"isRotation"<<endl;
	else cout<<"notRotation"<<endl;
	if(isRotation(s5,s6)) cout<<"isRotation"<<endl;
	else cout<<"notRotation"<<endl;
	return 0;
}
运行结果:





        转载请注明文章出处:http://blog.csdn.net/lavorange/article/details/9771993


你可能感兴趣的:(二维数组,算法,位操作,变位词,字符串逆序)