char temp; ... if(temp>='0' && temp<='9'){ //保证字符为数字 ... } //end if if( (temp>='A' && temp<='Z') || (temp>='a' && temp<='z') ){ //保证字符为A-Z或a-z字符 ... } //end if
将一个字符常量放到一个字符变量中,实际是将该字符的相应的ASCII代码放到存储单元中。如‘a’的ASCII代码为十进制数97,c1='a',在内存中是以97的二进制01100001存储的。
字符数据以ASCII码存储,它的存储形式就与整数的存储形式类似。这样使字符型数据和整型数据之间可以通用。
在JAVA中一个字符类型占两个字节,它只能存放0~255范围内的整数。
A-Z的ASCII值范围65-90 (26个字符 65+26-1)
a-z 的ASCII值范围97-122
//C Language
//大小写字母转换:每一个小写字母比它相应的大写字母的ASCII码大32
void transfer(){
char c;
c='a';
c=c-32;
printf("%c",c); //A
printf("%d",c); //65
}//end transfer()
//字符转换为ASCII码
int a=(int)'a';
//ASCII码转换为字符串
int c=97;
char b='0'+c;
public static boolean isUniqueChar(String str){
//输入控制
if(str==null ||str=="") //空字符串长度为0
return true;
//只有一个字符
int length=str.length();
if(length==1)
return true;
//多于2个字符
char a,b;
for(int i=0;i<=length-2;i++){
a=str.charAt(i);
for(int j=i+1;j<=length-1;j++){
//compare
b=str.charAt(j);
if(a==b)
return false;
}//end for
}//end for
return true;
}//end isUnitqueChar()
//测试用例
public static void testCase() {
//测试
//字符串为null
System.out.println("字符串为null:"+isUniqueChar(null));
//字符串长度为0,空字符串
System.out.println("空字符串:"+isUniqueChar(""));
//字符串长度为1
System.out.println("字符串长度为1:"+isUniqueChar("a"));
//字符串中无重复字符
System.out.println("字符串中无重复字符:"+isUniqueChar("abc"));
//字符串中有重复字符
System.out.println("字符串中有重复字符:"+isUniqueChar("abbc"));
}
算法2:如果字符串中的内容可以破坏的话。我们可以将字符串中的字符排序(时间复杂度为O(nlogn)),然后遍历字符串中的某个字符相邻的字符是否相同(时间复杂度O(n))。但是要注意有些排序算法是需要额外的存储空间的。总的时间复杂度是O(n).
算法3:用hashmap统计每个字符出现的次数,然后遍历hashmap看是否有出现次数多余一次的字符。这种算法需要用到额外的数据结构hash表。
算法4:先假设字符串中的字符均为ASCII码(如果不是的可以增大存储空间,而算法的逻辑是相同的),那么每个字符用ASCII码表示为整数,即可用0-255的一个数组表示,如果某个字符在数组对应位置出现次数超过一成则表示该字符串中有重复字符出现。
时间复杂度O(n),空间复杂度O(n),n为字符串的长度
//有重复字符出现,返回false
public static boolean isUniqueChar(String str){
//输入控制
if(str==null)
return true;
boolean[] char_set=new boolean[256];
for(int i=0;i<str.length-1;i++){
int val=str.charAt(i);
if(char_set[val])
return false; //如果有重复字符出现,则在数组对应位置上会提前将值设置为ture
char_set[val]=true;
}//end for
return true;
}//end isUniqueChar()
测试用例
//test cases
//字符串为null
//字符串为空""
//字符串没有重复字符abcd
//全重复字符aaaa
//连续重复字符aaaabbbcd
//非连续重复字符abcadbc
1)问题1:如果某个字符重复复出现,则删除该字符,如google变为le(删除重复字符g和o,变为gole)
算法1:用一个空的数组保存结果字符串,你将原字符串一个个的字符扫描,看每个字符是不是在结果字符串中,如果不在就加在结果字符串中,否则就跳过,扫描下一个字符。时间复杂度O(n*n),空间复杂度O(n)
public static String removeDuplicates(String str) {
// 输入控制
if (str == null || str == "")
return str;
char[] c = removeDuplicates(str.toCharArray());
String strResult = new String(c);
return strResult;
}// end removeDuplicates()
private static char[] removeDuplicates(char[] c) {
int length = c.length;
char[] result = new char[length]; // 临时存储空间
int resultIndex = 0; // reuslt数组的指针
result[resultIndex]=c[0];
//c中字符a与result中比较,如果a在result中,跳过,否则加入reuslt中
for(int i=0;i<length;i++){ //c 中字符
char a=c[i];
int j;
for(j=0;j<=resultIndex;j++){ //reuslt中字符
char b=result[j];
if(a==b)
break;
}//end for
//条件符合的加入result
if(j>resultIndex)
result[++resultIndex]=a;
}//end for
return result;
}// end removeDuplicates()
算法2:不需要额外存储空间,在原数组中处理,原数组也同时是结果数组,如果不在就加在结果字符串中,否则就跳过,扫描下一个字符。时间复杂度O(n*n),空间复杂度为0
private static char[] removeDuplicates2(char[] c) {
int length = c.length;
int resultIndex=0;
//c中字符a与result中比较,如果a在result中,跳过,否则加入reuslt中
for(int i=1;i<length;i++){ //c 中字符
char a=c[i];
int j;
for(j=0;j<=resultIndex;j++){ //result中字符
char b=c[j];
if(a==b)
break;
}//end for
//条件符合的加入result
if(j>resultIndex)
c[++resultIndex]=a;
}//end for
//剩余字符处理
if(resultIndex<length-1){
for(int i=resultIndex+1;i<length;i++)
c[i]='0';
}
return c;
}// end removeDuplicates()
2)问题2:如果某个字符连续重复复出现,则删除重复的字符,如google变为gogle(删除连续重复字符o)
题目:实现一个函数,把字符串中的每个空格替换成“%20”。例如输入“We are happy.”,则输出"We%20are%20happy."
思路:空格为一个字符,替换后“%20”为3个字符
1)计算出替换后字符串的长度
2)原字符串从后向前替换
//c language void replace(char[] str,int length){ //输入控制 if(str==null && length<0) return ; int spaceCount=0; //计算要替换字符的数目 int newLength; //和替换后字符串的长度 for(int i=0;i<length;i++){ if(str[i]==' ') spaceCount++; }//end for newLength=length+spaceCount*2; //替换 for(int i=length-1;i>=0;i--){ if(str[i]==' '){ str[newLength-1]='0'; str[newLength-1]='2'; str[newLength-1]='%'; newLength=newLength-3; }//end if else{ str[newLength-1]=str[i]; newLength=newLength-1; }//end else }//end for }//end replace()
//没有考虑特殊情况的代码---------------------------------------------------------------
public int strToInt(String str){
char[] strArray=str.toCharArray();
int number=0;
for(int i=0;i<strArray.length;i++){
number=number*10+(int)strArray[i];
}//end for
}//end strToInt()
测试用例设计
1)功能测试
int a=stringToInt("123");
2)边界测试
转换后的整数超出最大整数和最小整数范围,发生溢出
3)负面测试
int a=stringToInt(null); //字符串为null
int a=stringToInt(""); //字符串为“”
int a=stringToInt("+"); //只有一个加号的字符串
int a=stringToInt("-"); //只有一个减号的字符串
int a=stringToInt("-12a3"); //字符串中有非数字字符
想一想,还有其他情况会使程序崩溃吗?
程序代码如下:
//正确代码-------------------- public int strToInt(String str) throw Exception { //input control if(str==null || str==""){ throw new Exception("input can not be null or empty string!"); }//end if char[] strArray=str.toCharArray(); int strLength=strArray.length; //input only have one + or - char if(strLength==1){ char firstChar=strArray[0]; if(firstChar=='+' or firstChar=='-') throw new Exception("input is invalid number"); }//end if //开始算法 int numer=0; //store result //flag positive and negitive number, if it's false present positive nubmer,otherwise negitive number boolean minus=false; //标识字符串中数字开始的位置,若有正负号,则从1开始,否则从0开始 int index=0; if(strArray[0]=='+') index++; else if(strArray[0]=='-'){ index++; minus=true; }//end else number=strToIntCore(strArray,index); //处理正负号数据 if(minus) number=0-number; return number; }//end strToInt() //字符串数字部分转换为整数 private int strToIntCore(char[] strArray,int index) throw Exception{ int number=0; for( ;index<strArray.length;index++){ if(strArray[index]>='0' && strArray[index]<='9'){ //非字符数字控制 number=number*10+strArray[index]; if(number>Integer.MAX_VALUE){ //Integer.MAX_VALUE为正整数最大值 throw new Exception("input is out of int bound"); }//end if }//end if else{ throw new Exception("input is a invalid number"); }//end else }//end for }//end strToIntCore()
//---------------------------- public String intToStr(int number){ //negitive number flag boolean minus=false; //the convert result String str=""; //hanlde negitive number to positive if(number <0){ minus=true; number=0-number; }//end if //convert positive number to string while(number){ int singleNum=number % 10; str=str+singleNum; number=number/10; }//end while //if number is negitive, convert to it if(minus){ str="-"+str; }//end if return str; }//end intToStr()
http://blog.csdn.net/zhongyangzhong/article/details/9165083
算法一:KMP算法
kmp算法时间复杂度为O(m+n),思路如下:
移动位数 = 已匹配的字符数 - 对应的部分匹配值
"前缀"和"后缀"。 "前缀"指除了最后一个字符以外,一个字符串的全部头部组合;"后缀"指除了第一个字符以外,一个字符串的全部尾部组合。
"部分匹配值"就是"前缀"和"后缀"的最长的连续共有元素的长度,即最长前缀和最长后缀的最长公共子串。
http://blog.csdn.net/zhongyangzhong/article/details/9174155
算法二:后缀树
如字符串a匹配字符串b,可先生成b的后缀树,然后查询a是否在b的后缀树中。
【面试题】
腾讯面试题:假设两个字符串中所含有的字符和个数都相同我们就叫这两个字符串匹配, 比如:abcda和adabc,由于出现的字符个数都是相同,只是顺序不同, 所以这两个字符串是匹配的。要求高效!
解法一:用哈希表统计字符及出行次数,然后比较2个哈希表是否一样
解法二:假定字符串中都是ASCII字符。如下用一个数组来计数,前者加,后者减,全部为0则匹配。
static bool IsMatch(string s1, string s2)
{
if (s1 == null && s2 == null) return true;
if (s1 == null || s2 == null) return false;
if (s1.Length != s2.Length) return false;
int[] check = new int[128];
foreach (char c in s1)
{
check[(int)c]++;
}
foreach (char c in s2)
{
check[(int)c]--;
}
foreach (int i in check)
{
if (i != 0) return false;
}
return true;
}
原地翻转字符串函数,如abc,翻转结果为cba
对地
JAVA语言版本
//原地翻转字符串函数 private char[] reverse(char[] arr,int pBegin,int pEnd){ while(pBegin<pEnd){ char temp=arr[pBegin]; arr[pBegin]=arr[pEnd]; arr[pEnd]=temp; pBegin--; pEnd--; }//end while return arr; }//end reverse()
C语言版本
void reverse(char *pBegin, char *pEnd){ if(pBegin==null || pEnd==null) return; while(pBegin < pEnd){ char temp=*pBegin; *pBegin=*pEnd; *pEnd=temp; pBegin++,pEnd--; }//end while }//end reverse()
问题1:翻转句子,如abc def efg,翻转后结果为efg def abc
算法1:利用上述函数先翻转整个句子,然后翻转句中的每个单词。
char* reverseSentence(char *pData){ if(pData==null) return null; char *pBegin=pData; char *pEnd=pData; while(*pEnd!='\0') pEnd++; pEnd--; //翻转整个句子 reverse(pBegin,pEnd); //翻转句子中的每个单词 pBegin=pEnd=pData; while(*pBegin!='\0'){ if(*pBegin==' '){ //空格判断单词 pBegin++; pEnd++; }//end if else if(*pEnd==' ' || *pEnd=='\0'){ reverse(pBegin,--pEnd); pBegin=++pEnd; }//end if else{ pEnd++; }//end else }//end while return pData; }//end reverseSentence()
算法2:翻转可以用栈“先进后出”的性质,完成翻转
翻转句子,以单词为对象入栈,如abc def efg
入栈:abc,def,efg
出栈:efg def abc (出栈后在各单词间加入空格)
问题2:翻转字符串前n个字符到字符串末尾
算法1:将前n个字符放到临时空间中,将原字符串中剩余字符前移n位,再将临时空间中的字符串复制到字符串末尾。空间复杂度为O(n)//算法2代码 char* leftRotateString(char* pStr,int n){ //n为翻转字符串前n个字符 if(pStr!=null){ int nLength=static_cast<int> (strlen(pStr)); if(nLength>0 && n>0 && n<nLength){ char* pFirstStart=pStr; char* pFirstEnd=pSttr+n-1; char* pSecondeStart=pStr+n; char* pSecondEnd=pStr+nLength=1; //翻转字符串的前面n个字符 reverse(pFirstStart,pFirstEnd); //翻转字符串的后面部分 reverse(pSecondeStart,pSecondEnd); //翻转整个字符 reverse(pFirstStart,pSecondEnd); }//end if }//end if }//end leftRotateString()
签名是用某种规则等价定义各个元素(对元素进行预处理),这样相同规则下的元素具有相同的签名,而其他元素则没有。
2.1 变位词
给定一本英语单词词典,请找出所有的变位词集。例如,因为“pots”、"stop"、"tops"相互之间都是由一个词的各个字母改变序列而构成的,因此这些词相互之间就是变位词。
思路:只要考虑如何求解某个单词中各个字母的所有置换(即全排列),注定是失败的算法。因为n个字母组成的单词,有n!个变位词。
算法:对字典中的每个单词都进行签名(即将每个单词中的字母排序后的结果为该单词的签名),这样同一变位词类中的单词会具有相同的签名,然后统计具有相同签名的单词。这样将原来的变位词问题转换为两个子问题:选择一个签名;统计具有相同签名的单词(这里可以对具有签名的字典按照签名进行排序,然后用二分查找找到字典中某个单词首次出现和最后出现的位置,然后输出从首次出现位置到最后出现位置的单词)。
2.2 转置矩阵
给一个m*n的矩阵,要求实现矩阵的转置。
算法:
1)签名:预先记录矩阵中元素所在的行号和列号(为每个元素签名标识),如2*2矩阵在一维数组中的记录如下(obj1<1,1>,obj2<1,2>,obj3<2,1>,obj4<2,2>)。
2)排序:因为转置以前矩阵是按以下规则排序的:先按行排序,行号相同时,按列排序。
因此转置矩阵需要先按列排序,列号相同时按行排序,上述排序结如下(obj1<1,1>,obj3<2,1>,obj2<1,2>,obj4<2,2>)
3)删除元素的行号和列号
字符串相似算法用来描述两段文字之间的“相似度”,即它们的雷同程度,从而能够用来辨别抄袭。主要的算法有基于编辑距离(Edit Distance)的LD算法(时间复杂度为O(mn))和最长公共子序列算法(时间复杂度为O(mn))见博客“动态规划(5)-字符串相似度算法”。
见博客 动态规划(4)最大连续子串问题