5.替换空格
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
public class Solution {
public String replaceSpace(StringBuffer str) {
if(str==null||str.length()==0){
return str.toString();
}
int len=str.length();
StringBuffer res=new StringBuffer();
for(int i=0;i<len;i++){
if(str.charAt(i)!=' '){
res.append(String.valueOf(str.charAt(i)));
continue;
}else{
res.append("%20");
continue;
}
}
return res.toString();
}
}
20.表示数值的字符串
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
思路:先想想表示数值的字符串的特征。
A[.[B]][e|EC] .B[e|EC]
A是整数部分,B紧跟着小数点为小数部分,C紧跟着e为指数部分。
小数里面也可以没有整数部分,所以A部分不是必须的,如果一个数没有整数部分,那么小数部分不能为空!
A和C都可能是以+或者-开头的0-9的数位串;B也是0-9的数位串,但是B前面不能有正负号。
以123.45e+6为例。
判断一个字符串是否符合上述模式的时候,首先尽可能扫描A部分,遇到小数点就扫描B部分,遇到E|e就扫描C部分。
public class Solution {
public static boolean isNumeric(char[] str) {
if(str==null||str.length==0){
return false;
}
int index=0;
//首先判断有没有符号位
if(str[index]=='+'||str[index]=='-'){
index++;
}
//但是如果只有符号位也不对啊
if(index==str.length){
return false;
}
//如果不是只有符号位的话,就开始扫描数字,只要是数字,那么index往下移
index=scanInteger(str,index);
//整数部分扫描完以后,先看index是不是小于length,要是index小于length,那么开始扫描小数部分
if(index<str.length){
if(str[index]=='.'){
//开始扫描小数部分啦
index++;
index=scanInteger(str,index);
//把所有的小数扫描完以后,看index有没有超过长度,要是小于长度,再开始看指数部分!
if(index<str.length){
if(str[index]=='e'||str[index]=='E'){
index++;
return isExponential(str,index);
}
return false;
}
return true;
}else if(str[index]=='e'||str[index]=='E'){
//如果没有小数部分,有指数部分
index++;
if(index==str.length){
return false;
}
return isExponential(str,index);
}
return false;
}
return true;
}
public static boolean isExponential(char[] str,int index){
if(str[index]=='+'||str[index]=='-'){
index++;
}
index=scanInteger(str,index);
if(index==str.length){
return true;
}
return false;
}
public static int scanInteger(char[] str,int index){
while(index<str.length&&(str[index]>='0'&&str[index]<='9')){
index++;
}
return index;
}
}
38.字符串的排列
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
思路:全排列,采用递归思想。从字符串中选出一个字符当作排列的第一个字符,然后对剩余的字符进行全排列。
把一个字符分成两部分来看待,第一部分为第一个字符,第二部分为后面的所有字符,然后把结果存到一个ArrayList<String>里面。
具体过程就是先求第一个字符处于最前面的时候后面所有的全排列,然后把第一个字符挨个和后面的交换,然后递归就行了。
import java.util.ArrayList;
import java.util.Collections;
import java.util.Set;
import java.util.HashSet;
public class Solution {
public ArrayList<String> Permutation(String str) {
ArrayList<String> res=new ArrayList<>();
if(str==null||str.length()==0){
return res;
}
char[] chars=str.toCharArray();
PermutationHelp(chars,0,res);
Collections.sort(res);
return res;
}
public void PermutationHelp(char[] chars,int i,ArrayList<String> res){
if(i==chars.length-1){ //到最后一个字符为递归出口
res.add(String.valueOf(chars));
}else{
Set<Character> charSet=new HashSet<>();
for(int j=i;j<chars.length;j++){
if(j==i||!charSet.contains(chars[j])){
charSet.add(chars[j]);
swap(chars,i,j);
PermutationHelp(chars,i+1,res);
swap(chars,j,i);
}
}
}
}
public void swap(char[] chars,int i,int j){
char tmp=chars[i];
chars[i]=chars[j];
chars[j]=tmp;
}
}
46.把数字翻译成字符串
题目:给定一个数字,按照如下规则把它翻译为字符串:0翻译成“a”,1翻译成“b”,25翻译成“z”。一个数字可能有多个翻译。例如,12258有5种不同的翻译,分别是“bccfi”、“bwfi”、“bczi”、“mcfi”、“mzi”。请实现一个函数,用来计算一个数字有多少种不同的翻译方法。
思路:以12258为例,可以分为1和2258,也可以分为12和258,然后来看2258,可以分为2和258,258子问题重复出现,所以要从下往上解决问题,就可以消除重复的子问题。从数字的末尾开始,从右到左翻译并计算不同翻译的数目。
自上而下,从最大的问题开始,递归 :
12258
/ \
b+2258 m+258
/ \ / \
bc+258 bw+58 mc+58 mz+8
/ \ \ \ \
bcc+58 bcz+8 bwf+8 mcf+8 mzi
/ \ \ \
bccf+8 bczi bwfi mcfi
/
bccfi
有很多子问题被多次计算,比如258被翻译成几种这个子问题就被计算了两次。
自下而上,动态规划,从最小的问题开始 :
f(r)表示以r为开始(r最小取0)到最右端所组成的数字能够翻译成字符串的种数。对于长度为n的数字,f(n)=0,f(n-1)=1,求f(0)。
递推公式为 f(r-2) = f(r-1)+g(r-2,r-1)*f(r);
其中,如果r-2,r-1能够翻译成字符,则g(r-2,r-1)=1,否则为0。
因此,对于12258:
f(5) = 0
f(4) = 1
f(3) = f(4)+0 = 1
f(2) = f(3)+f(4) = 2
f(1) = f(2)+f(3) = 3
f(0) = f(1)+f(2) = 5
public static int count(int num){
if(num<0){
return 0;
}
return getcount(String.valueOf(num));
}
public static int getcount(String num){
int f1=1;
int f2=1;
int g=0;
int tmp;
for(int i=num.length()-2;i>=0;i--){
if(Integer.parseInt(num.charAt(i)+""+num.charAt(i+1))<=26){
g=1;
}else{
g=0;
}
tmp=f2;
f2=f2+g*f1;
f1=tmp;
}
return f2;
}
48.最长不含重复字符的子字符串
题目:请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。假设字符串中只包含a-z的字符。例如,在‘arabcacfr’中,最长的不含重复子字符串是‘acfr’,长度为4。
思路:使用动态规划算法。首先定义f(i)为以第i个字符为结尾的不包含重复字符的最长长度。从左到右逐一扫描字符串中的每个字符,当计算f(i)的时候,已经知道f(i-1)了。
如果第i个字符之前没有出现过,那么f(i)=f(i-1)+1;
如果出现过,那么情况就要复杂一点,先计算第i个字符和它上次出现在字符串中的位置的距离,记为d,然后分两种情况,
(1)d>f(i-1),第i个字符上次出现在f(i-1)对应的最长子字符串之前,所以f(i)=f(i-1)+1;
(2)d<=f(i-1),第i个字符上次出现在f(i-1)对应的最长子字符串中,所以f(i)=d,同时这也意味着第i个字符出现两次所夹的子字符串中再也没有其他重复的字符了。
public class 最长的不含重复字符的子字符串 {
public static int longestSubString(String str){
if(str==null||str.length()==0){
return 0;
}
int len=str.length();
int maxLength=0;
int curLength=0;
//一个数组,存储26个字母在字符串中上一次出现的位置
int[] position=new int[26];
for(int i=0;i<26;i++){
position[i]=-1; //首先把所有字母在字符串中上一次出现的位置都初始化为-1,即还没有出现过
}
for(int i=0;i<len;i++){ //遍历字符串的位置,从0到len-1
int preIndex=position[str.charAt(i)-'a'];
int distance=i-preIndex;
if(preIndex<0||distance>curLength){ //还没出现过或者之前出现不在最长子字符串中
curLength++;
}else{ //出现过,且出现在之前的最长子字符串中
curLength=distance; //那么当前长度就等于当前位置和上次出现位置的差值
}
if(curLength>maxLength){
maxLength=curLength;
}
position[str.charAt(i)-'a']=i;
}
return maxLength;
}
}
58.翻转字符串
题目一:翻转单词顺序
牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?
思路:先写一个reverse函数,然后先把整个字符串reverse,然后分别把每个单词reverse。