字符串算法总结
1.字符流中第一个只出现一次的字符
package neu.yanyingnan.offer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/*题目描述
请实现一个函数用来找出字符流中第一个只出现一次的字符。
例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。
当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
输出描述:
如果当前字符流没有存在出现一次的字符,返回#字符。*/
public class Solution_54 {
Map<Character, Integer> map = new HashMap<Character, Integer>();//map是为了记录次数
List<Character> list = new ArrayList<Character>(); //list是为了保证顺序 找第一个出现一次的
//Insert one char from stringstream
public void Insert(char ch){
list.add(ch);//插入字符元素
if(map.containsKey(ch))//利用map存放这些元素 并记录出现个数
map.put(ch, map.get(ch)+1);
else
map.put(ch, 1);
}
//return the first appearence once char in current stringstream
public char FirstAppearingOnce(){
for (Character ch : list) {//简单的遍历即可
if(map.get(ch)==1)
return ch;
}
return '#';
}
}
2.判断字符串是否表示数值(包括整数和小数)
package neu.yanyingnan.offer;
/*题目描述
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。
但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。*/
public class Solution_53 {
public static boolean isNumeric(char[] str) {//通过了 但是代码好不简洁
if(str==null)
return false;
if(str.length==0)
return false;
if(!(str[0] == '+' || str[0] == '-' || (str[0]>='0'&&str[0]<='9')))
return false;
int dot = 0;//控制小数点只能有一个
int i;
for(i=1; i<str.length && !(str[i]=='e'||str[i]=='E'); i++){//如果存在e就以它为分界点 两次for循环
if(str[i] == '.'){
dot++;
if(dot>1)
return false;
}
if(!((str[i]>='0'&&str[i]<='9')||str[i]=='.'))
return false;
}
if(i==str.length-1)//说明e在末尾 返回false
return false;
if(i==str.length-2 && (str[i+1]<='0'||str[i+1]>='9'))//说明e在倒数第二位 最后一位必须是0-9
return false;
if(i==1 && !(str[0]>='0'&&str[0]<='9'))//说明e在第二位 第一位如果不是0-9 返回false
return false;
if(i==str.length)//上面的for循环完成 不存在e 返回true
return true;
for(int j=i+1; j<str.length;j++){//e在中部
if((str[j]=='+'||str[j]=='-')&&j==i+1)
continue;
if(!(str[j]>='0' && str[j]<='9'))
return false;
}
return true;
}
public static void main(String[] args) {
char[] str = {'5','e','2'};
System.out.println(isNumeric(str));
}
}
3.正则表达式匹配
package neu.yanyingnan.offer;
/*题目描述
请实现一个函数用来匹配包括'.'和'*'的正则表达式。
模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。
在本题中,匹配是指字符串的所有字符匹配整个模式。
例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配*/
/*当模式中的第二个字符不是“*”时: (思想用到了穷举和递归)
1、如果字符串第一个字符和模式中的第一个字符相匹配, 那么字符串和模式都后移一个字符,然后匹配剩余的。
2、如果字符串第一个字符和模式中的第一个字符相不匹配,直接返回false。
而当模式中的第二个字符是“*”时:
如果字符串第一个字符跟模式第一个字符不匹配,则模式后移2个字符,继续匹配。
如果字符串第一个字符跟模式第一个字符匹配,可以有3种匹配方式:
1、模式后移2字符,相当于x*被忽略;
2、字符串后移1字符,模式后移2字符;
3、字符串后移1字符,模式不变,即继续匹配字符下一位,因为*可以匹配多位;
这里需要注意的是:Java里,要时刻检验数组是否越界。*/
public class Solution_52 {
public static boolean match(char[] str, char[] pattern) {
if (str == null || pattern == null) {
return false;
}
int strIndex = 0;
int patternIndex = 0;
return matchCore(str, strIndex, pattern, patternIndex);
}
public static boolean matchCore(char[] str, int strIndex, char[] pattern, int patternIndex) {
// 有效性检验:str到尾,pattern到尾,匹配成功
if (strIndex == str.length && patternIndex == pattern.length)
return true;
// pattern先到尾,匹配失败
if (strIndex != str.length && patternIndex == pattern.length)
return false;
// 模式第2个是*,且字符串第1个跟模式第1个匹配,分3种匹配模式;如不匹配,模式后移2位
if (patternIndex + 1 < pattern.length && pattern[patternIndex + 1] == '*') {
if ((strIndex != str.length && pattern[patternIndex] == str[strIndex])
|| (pattern[patternIndex] == '.' && strIndex != str.length)) {
return // 模式后移2,视为x*匹配0个字符
matchCore(str, strIndex, pattern, patternIndex + 2)
// 视为模式匹配1个字符
|| matchCore(str, strIndex + 1, pattern, patternIndex + 2)
// *匹配1个,再匹配str中的下一个
|| matchCore(str, strIndex + 1, pattern, patternIndex);
} else {
return matchCore(str, strIndex, pattern, patternIndex + 2);
}
} // 模式第2个不是*,且字符串第1个跟模式第1个匹配,则都后移1位,否则直接返回false
if ((strIndex != str.length && pattern[patternIndex] == str[strIndex])
|| (pattern[patternIndex] == '.' && strIndex != str.length)) {
return matchCore(str, strIndex + 1, pattern, patternIndex + 1);
}
return false;
}
public static void main(String[] args) {
char[] str = {0};
char[] pattern = {'.'};
System.out.println(match(str, pattern));
}
}
4. 将一个字符串转换成一个整数
package neu.yanyingnan.offer;
/*题目描述
将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
输入描述:
输入一个字符串,包括数字字母符号,可以为空
输出描述:
如果是合法的数值表达则返回该数字,否则返回0
示例1
输入
+2147483647
1a33
输出
2147483647
0
*/
public class Solution_49 {
public int strToInt(String str){
if(str==null || str.length()==0)//如果是空串返回零;
return 0;
if(str.equals("2147483647")) //边缘值单独判断
return 2147483647;
else if(str.equals("-2147483648"))
return -2147483648;
int res = 0;
char[] chs = str.toCharArray();
int len = chs.length;
for(int i=len-1,j=0; i>0; i--,j++){//从后向前计算 【48 57】之间为【0 9】
if(chs[i]<48 || chs[i]>57)
return 0;
else
res += (chs[i]-48)*Math.pow(10, j);
}
if(chs[0]>=48 && chs[0]<=57) //第一个字符有可能为 +- 单独判断
res += (chs[0]-48)*Math.pow(10, len-1);
else if(chs[0]==45)
res = -res;
else if(chs[0] != 43)
return 0;
else
return res;
return res;
}
}
(完成)替换空格
/*题目描述
请实现一个函数,将一个字符串中的空格替换成“%20”。
例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。*/
//主要思路是从后往前覆盖。
public class Solution_02 {
public String replaceSpace(StringBuffer str) {
int count = 0;
for(int i=0; i<str.length(); i++){
if(str.charAt(i)==' ')
count++;
}
int newLen = 2*count+str.length();
int oldLen = str.length();
str.setLength(newLen);
for(int i=oldLen-1,j=newLen-1; i>=0;i--){
if(str.charAt(i) == ' '){
str.setCharAt(j--, '0');
str.setCharAt(j--, '2');
str.setCharAt(j--, '%');
}else{
str.setCharAt(j--, str.charAt(i));
}
}
return str.toString();
/*return str.toString().replace(" ", "%20");//然而一句话就搞定了 注意replace()方法 原字符串的值是不变的 改变的只是返回值 只能直接return
*/ }