目录
9.longest-substring-without-repeating-characters
10.longest-palindromic-substring
1.length-of-last-word
题目:给出一个只包含大小写字母和空格的字符串s,请返回字符串中最后一个单词的长度,如果字符串中没有最后一个单词,则返回0。注意:单词的定义是仅由非空格字符组成的字符序列。例如:s ="Hello World",返回5。
分析:先用String的trim()方法去掉前后的空格,反向遍历进行计算倒数第一个单词的长度即可。
public int lengthOfLastWord(String s) {
s = s.trim();
int count = 0;
for(int i = s.length() - 1;i >= 0;i--){
if(s.charAt(i) == ' ')
break;
count++;
}
return count;
}
2.add-binary
题目:给出两个用字符串表示的二进制数,返回他们的和(也用字符串表示)。例如:a ="11",b ="1",返回"100".
分析:先在短的字符串前面填充0让两字符串长度相同,从后往前依次相加即可,二进制相加可以用异或进行计算,可提高计算效率。
public String addBinary(String a, String b) {
if(a.length() == 0 || b.length() == 0)
return a + b;
int len = Math.max(a.length(),b.length());
while(a.length() < len)
a = "0" + a;
while(b.length() < len)
b = "0" + b;
String result = "";
int flag = 0;
for(int i = len - 1;i >= 0;i--){
int m = a.charAt(i) - '0',n = b.charAt(i) - '0';
result = (m ^ n ^ flag) + result;
if(m + n + flag < 2)
flag = 0;
else
flag = 1;
}
if(flag == 1)
result = 1 + result;
return result;
}
3.multiply-strings
题目:给出两个用字符串表示的数字,将两个数字的乘积作为字符串返回。备注:数字可以无限大,且是非负数。
分析:分治法。先举个简单的例子来说,比如99 * 33实际上会等于90 * 33 + 9 * 33,也就是把99从中间拆分,分别乘以33.所以我们可以将大数相乘a和b中的其中一个数从中间进行拆分,假设我们将a前后拆成a1、a2,那么就将问题拆成了a1*b,a2*b,最后结果就是a1*b后面添加a2.length个0与a2*b的和,问题又转化成了大数相加的问题。对于大数相加问题,可以将两个数字的后八位分离出来进行相加,再与数字其它位数的和进行拼凑,注意拼凑时有可能后8位数字相加之后的长度小于8,这时我们要进行补0,有可能长度大于9,也就是最高位为1时,这时我们要将高位数之和加上1,再与剩下8位进行拼凑。Integer.MAX_VALUE为2147483647,所以当两个数的长度均小于等于4时才进行直接相乘,长度小于等于8时才进行直接相加,以防止溢出。
public String multiply(String num1, String num2) {
int len1 = num1.length(),len2 = num2.length();
if(len1 <= 4 && len2 <= 4)//递归出口
return Integer.parseInt(num1) * Integer.parseInt(num2) + "";
if(len1 > 4){//将长度大于4的字符串从中间进行拆分
int mid = len1 >> 1;
String s1 = num1.substring(0,mid);
String s2 = num1.substring(mid);
return add(multiply(s1,num2) + zero(s2.length()),multiply(s2,num2));
}
return multiply(num2,num1);
}
private String add(String num1, String num2) {//大数相加
int len1 = num1.length(),len2 = num2.length();
if(len1 <= 8 && len2 <= 8)//递归出口
return Integer.parseInt(num1) + Integer.parseInt(num2) + "";
String a1 = "0",a2 = num1;
if(len1 > 8) {//分离出num1后8位
a1 = num1.substring(0,len1 - 8);
a2 = num1.substring(len1 - 8);
}
String b1 = "0",b2 = num2;
if(len2 > 8) {//分离出num2后8位
b1 = num2.substring(0,len2 - 8);
b2 = num2.substring(len2 - 8);
}
String result = add(a2,b2);
if(result.length() > 8)
return add(add(a1,b1),"1") + result.substring(1);
else
return add(a1,b1) + zero(8 - result.length()) + result;
}
private String zero(int n){//返回n个0的字符串
if(n == 0) return "";
if(n == 1) return "0";
String s = zero(n / 2);
return s + s + zero(n % 2);
}
4.valid-number
题目:判断给出的字符串是否是数字。一些例子:"0"=>true;" 0.1 "=>true;"abc"=>false;"1 a"=>false;"2e10"=>true
分析:见剑指offer面试题20 https://blog.csdn.net/Nibaby9/article/details/103822794
5.string-to-integer-atoi
题目:实现函数 atoi 。函数的功能为将字符串转化为整数。提示:仔细思考所有可能的输入情况。这个问题故意描述的很模糊(没有给出输入的限制),你需要自己考虑所有可能的情况。
分析:见剑指offer面试题67 https://blog.csdn.net/Nibaby9/article/details/103822794
6.roman-to-integer
题目:请将给出的罗马数字转化为整数,保证输入的数字范围在1 到 3999之间。
分析:罗马数字转换规则:I --> 1、V --> 5、X --> 10、L --> 50、C --> 100、D --> 500、M --> 1000,单个符号重复多少次,就表示多少倍。最多重复3次,比如:CCC表示300 XX表示20,但150并不用LLL表示,这个规则仅适用于I X C M;如果相邻级别的大单位在右,小单位在左,表示大单位中扣除小单位,比如:IX表示9 IV表示4 XL表示40。这里用暴力破解法,IV:4 IX:9 XL:40 XC:90 CD:400 CM:900这种组合实际上在罗马数中只会出现一次,所以可以遇到这种组合可以在计算的和中减去多加的数,比如说IV如果用I+V的值就为6,只要再减去2即可。
public int romanToInt(String s) {
int sum = 0;
for(int i = 0;i < s.length();i++) {
char c = s.charAt(i);
if(c == 'I') sum+=1;
if(c == 'V') sum+=5;
if(c == 'X') sum+=10;
if(c == 'L') sum+=50;
if(c == 'C') sum+=100;
if(c == 'D') sum+=500;
if(c == 'M') sum+=1000;
}
if(s.contains("IV") || s.contains("IX"))//4、9
sum -= 2;
if(s.contains("XL") || s.contains("XC"))// 40、90
sum -= 20;
if(s.contains("CD") || s.contains("CM"))// 400、900
sum -= 200;
return sum;
}
7.integer-to-roman
题目:请将给出的整数转化为罗马数字,保证输入数字的范围在1 到 3999之间。
分析:利用穷举法,将各位数分别转换为罗马数字即可。
public String intToRoman(int num) {
String[] one = {"","I","II","III","IV","V","VI","VII","VIII","IX"};
String[] two = {"","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"};
String[] three = {"","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"};
String[] four = {"","M","MM","MMM"};
String result = "";
result += four[num / 1000];
result += three[num % 1000 / 100];
result += two[num % 100 / 10];
result += one[num % 10];
return result;
}
8.implement-strstr
题目:实现函数 strStr。函数声明如下:char *strStr(char *haystack, char *needle),返回一个指针,指向needle第一次在haystack中出现的位置,如果needle不是haystack的子串,则返回null。例如"mississippi","issi",返回"ississippi".
分析:考查KMP算法,它是一种改进的字符串模式匹配算法,可以在O(n+m)的时间复杂度以内完成字符串的匹配操作,其核心思想在于当一趟匹配过程中出现字符不匹配时,不需要回溯主串的指针,而是利用已经得到的“部分匹配”,将模式串尽可能多地向右“滑动”一段距离,然后继续比较。KMP算法先计算模式串的next数组,next[i]表示模式串前i个字符的部分匹配值(”前缀”和”后缀”的最长的公有元素的长度),如”A”的前缀和后缀都为空集,部分匹配值为0,“ABCDAB”的部分匹配值为2。求解next数组的步骤:
- 初始化next[0]=-1, next[1]=0;(注意如果初始化next[1]的话,需保证next数组长度至少为2,所以可以暂不初始化next[1])
- 求解next[j]时,令k=next[j-1];
- 比较T[j-1]与T[k]的值:若相等,则next[j] = k +1;否则令k=next[k],若k等于-1,则next[j]=0,否则跳转到第三步。
求解完next数组后,开始遍历主串来匹配模式串,如果不匹配则利用next数组进行对模式串进行偏移。
public String strStr(String haystack, String needle) {
if(needle.length() == 0)
return haystack;
if(needle.length() > haystack.length())
return null;
int[] next = cal_next(needle);
int i = 0,j = 0;
while(i < haystack.length() && j < needle.length()){
if(haystack.charAt(i) == needle.charAt(j) ){
i++;j++;
}
else if(next[j] == -1){
j = 0;i++;
}
else
j = next[j];
}
if(j == needle.length())
return haystack.substring(i-j);//易错
return null;
}
private int[] cal_next(String needle) {
int[] next = new int[needle.length()];
next[0] = -1;//初始化
for(int i = 2;i < needle.length();i++){
int k = next[i-1];
while(k != -1 && needle.charAt(i-1) != needle.charAt(k))
k = next[k];
next[i] = k + 1;
}
return next;
}
9.longest-substring-without-repeating-characters
题目:给定一个字符串,找出最长的不具有重复字符的子串的长度。例如,“abcabcbb”不具有重复字符的最长子串是“abc”,长度为3。对于“bbbbb”,最长的不具有重复字符的子串是“b”,长度为1。
分析:见剑指offer面试题48 https://blog.csdn.net/Nibaby9/article/details/10382279
10.longest-palindromic-substring
题目:找出给出的字符串S中最长的回文子串。假设S的最大长度为1000,并且只存在唯一解。
分析:动态规划。定义一个函数f(i,j)表示字符串第i个位置到第j个位置是否为回文串,从左到右依次扫描字符将其作为子串的结束位置,让子串往前进行延伸,在计算f(i,j)时就可保证f(i+1,j-1)已计算出,那么f(i,j) = (s.charAt(i) == s.charAt(j) && f(i+1,j-1))。
public String longestPalindrome(String s) {
if(s.length() == 0)
return s;
int max = 1;
int start = 0;//保存最长回文子串的起始点
boolean [][]dp = new boolean[s.length()][s.length()];//子串s[i..j] 是否是回文子串
for(int i = 0;i < s.length();i++)
dp[i][i] = true;
for(int j = 1;j < s.length();j++){//子串结束位置
for(int i = j-1;i >= 0;i--){//子串开始位置
if(j - i < 2)
dp[i][j] = s.charAt(i) == s.charAt(j);
else
dp[i][j] = (s.charAt(i) == s.charAt(j) && dp[i+1][j-1]);
if(dp[i][j] && j-i+1 > max){
max = j - i + 1;
start = i;
}
}
}
return s.substring(start,start + max);
}