
文章目录
-
- [1. 最长的公共前缀](#1. 最长的公共前缀)
-
- 1.思路一
- [2. 思路二](#2. 思路二)
- [2. 最长回文串](#2. 最长回文串)
- [3. 二进制求和](#3. 二进制求和)
- [4. 字符串相乘](#4. 字符串相乘)
1. 最长的公共前缀
我们提供两个思路,我们先说思路一
1.思路一
我们每次取两个字符串,两两进行比较,提取其公共前缀部分
现在问题是如果找到两个字符串的公共前缀呢?
我们可以定义双指针,一旦一个指针越界了或者是两个指针值不相等了就说明结束了

java
class Solution {
public String longestCommonPrefix(String[] strs) {
String ret = strs[0];
for(int i = 1;i < strs.length;i++){
ret = findSame(ret,strs[i]);
}
return ret;
}
private String findSame(String s1,String s2){
StringBuilder str = new StringBuilder();
char [] ch1 = s1.toCharArray();
char [] ch2 = s2.toCharArray();
int pos = 0;
int length1 = ch1.length;
int length2 = ch2.length;
while(pos < length1 && pos < length2 && ch1[pos] == ch2[pos]){
str.append(ch1[pos]);
pos++;
}
return str.toString();
}
}
2. 思路二
我们直接一次性全部比较,但凡有一个字符和其他字符不同的直接返回

java
class Solution {
public String longestCommonPrefix(String[] strs) {
for(int i = 0;i < strs[0].length();i++){//根据第一个字符串,对应其他字符串
char ch = strs[0].charAt(i);
for(int j = 1;j < strs.length;j++){//让除第一个字符串以外的字符串逐个比较
if(i == strs[j].length() || strs[j].charAt(i) != ch){//如果比较的字符串在其他字符串中不存在(越界)
return strs[0].substring(0,i);
}
}
}
return strs[0];
}
}
2. 最长回文串
这题我们使用中间扩展算法,我们每次选取一个下标字符,然后让两个指针指向它,然后两个指针分别往两侧扩展
扩展条件就是当两个指针所指的字符相同的时候
如果两个指针所指的字符不同,我们扩展就结束
然后我们去定义两个变量,一个是标记每一次遍历的最长的回文链表的起始位置
再用一个遍历去标记最长回文链表的长度
java
class Solution {
public String longestPalindrome(String s) {
int srart = 0;
int maxLenght = 0;//不含左端点回文串的区间长度
//定义每一次的中心位置
char [] ss = s.toCharArray();
int length = ss.length;
for(int i = 0;i < length;i++){
int left = i;
int right = i;
while(left >= 0 && right < length && ss[left] == ss[right]){
left--;
right++;
}
//判断回文区间长度
if(right-left-1 > maxLenght){
srart = left+1;//此时left位置不是回文字符了,下一位才是
maxLenght = right-left-1;
}
//再扩展偶数长度的回文串
left = i;
right = i+1;
while(left >= 0 && right < length && ss[left] == ss[right]){
left--;
right++;
}
if(right-left-1 > maxLenght){
srart = left+1;
maxLenght = right-left-1;
}
}
return s.substring(srart,srart+maxLenght);
}
}
注意maxLength
表示的是回文链表的长度,因此我们截取的时候虽然截取是左闭右开
但是由于我们加上了一个长度,会让我们的下标落在最长回文链表的尾部的下一个字符位置
自然就可以把回文链表截取完毕了
如果实在有困惑,可以自己举个例子去模拟下就知道了
3. 二进制求和
这个和我们写链表求和的题类似,这里就不再赘述了
需要注意的是我们两个字符串遍历的时候注意如果循环后字符串还有剩下的数,也要加起来
而且如果全部都遍历完了,进位还存在,也要加上
如果是最开始把链表反转了,最后也要把结果反转回来
java
class Solution {
public String addBinary(String a, String b) {
char [] ch1 = a.toCharArray();
char [] ch2 = b.toCharArray();
int length1 = ch1.length;
int length2 = ch2.length;
int pos1 = length1-1;
int pos2 = length2-1;
StringBuilder str = new StringBuilder();
int sum = 0;
while(pos1 >= 0 && pos2 >= 0){
sum += (ch1[pos1]-'0')+(ch2[pos2]-'0');
str.append(sum%2);
sum /= 2;
pos1--;
pos2--;
}
while(pos1 >= 0){
sum += ch1[pos1]-'0';
str.append(sum%2);
sum /= 2;
pos1--;
}
while(pos2 >= 0){
sum += ch2[pos2]-'0';
str.append(sum%2);
sum /= 2;
pos2--;
}
if(sum != 0){
str.append(sum);
}
str = str.reverse();
return str.toString();
}
}
4. 字符串相乘
这一题最简单的思路就是去模拟我们的列竖式运算
但是在列竖式的时候,我们对于相乘不同的位要注意补前导0
1 2 3
4 5 6
x ______
7 3 8
6 1 5 0 <--这里要补前导0,这是最棘手的
4 9 2 0 0 <--这里要补两个前导0
_________
5 6 0 8 8
这里给上代码,太复杂了,想=看着就头疼呀QAQ
java
class Solution {
public String multiply(String num1, String num2) {
// 处理特殊情况:如果任意一个数为"0",则乘积为"0"
if ("0".equals(num1) || "0".equals(num2)) {
return "0";
}
StringBuilder str1 = new StringBuilder(num1).reverse();
StringBuilder str2 = new StringBuilder(num2).reverse();
num1 = str1.toString();
num2 = str2.toString();
char[] nums1 = num1.toCharArray();
char[] nums2 = num2.toCharArray();
// 存储每一行的乘法结果
String[] strs = new String[nums1.length];
for (int i = 0; i < nums1.length; i++) {
StringBuilder str = new StringBuilder();
int step = 0;
// 补前导零(对应竖式中的错位)
for (int k = 0; k < i; k++) {
str.append('0');
}
for (int j = 0; j < nums2.length; j++) {
int product = (nums1[i] - '0') * (nums2[j] - '0') + step;
str.append(product % 10);
step = product / 10;
}
if (step != 0) {
str.append(step);
}
strs[i] = str.toString();
}
// 结果相加:将所有部分积相加
String result = "0";
for (String s : strs) {
result = addStrings(result, s);
}
// 反转得到最终结果
return new StringBuilder(result).reverse().toString();
}
// 辅助方法:计算两个字符串表示的数字之和(字符串已反转)
private String addStrings(String num1, String num2) {
StringBuilder result = new StringBuilder();
int i = 0, j = 0, carry = 0;
while (i < num1.length() || j < num2.length() || carry != 0) {
int digit1 = i < num1.length() ? num1.charAt(i++) - '0' : 0;
int digit2 = j < num2.length() ? num2.charAt(j++) - '0' : 0;
int sum = digit1 + digit2 + carry;
result.append(sum % 10);
carry = sum / 10;
}
return result.toString();
}
}
我们可以尝试下优化代码,在列竖式的时候我们不进行进位相加,直接保留值
我们定义一个数组,将每次计算的值累加到数组对应的下标中
最后再把数组中每一个值进行进位相加,结果直接返回就好了
1 2 3
4 5 6
x _____
6 12 18
5 10 15
4 8 12
__________
4 13 28 27 18
最后我们再把这些数字进行进位相加,得出最后的结果56088
好,我们数组长度是两个字符串的长度减一,这个是数学原理
我们怎么样让每一次无进位计算在数组中找到正确位置呢?
我们遍历两个字符串的时候,我们会定义两个指针,每一次计算的值在数组中对应的位置就是
两个指针下标之和
我们先把两个字符串反转,即现在我们原字符最右边是字符的0下标
比如刚刚的竖式中3*6=18
结果放在数组下标arr[0+0]
又比如1*6=6
结果放在数组下标arr[2+0]
java
class Solution {
public String multiply(String num1, String num2) {
//处理前导0
StringBuilder s1 = new StringBuilder(num1);
StringBuilder s2 = new StringBuilder(num2);
s1 = s1.reverse();
s2 = s2.reverse();
num1 = s1.toString();
num2 = s2.toString();
char [] nums1 = num1.toCharArray();
char [] nums2 = num2.toCharArray();
int length1 = nums1.length;
int length2 = nums2.length;
int [] tmp = new int[length1+length2-1];
//不进位相加
for(int i = 0;i < length1;i++){
for(int j = 0;j < length2;j++){
tmp[i+j] += (nums1[i]-'0')*(nums2[j]-'0');
}
}
//处理进位
int step = 0;
StringBuilder ret = new StringBuilder();
for(int i = 0;i < tmp.length;i++){
int number = tmp[i]+step;
ret.append(number%10);
step = number/10;
}
//如果进位还存在
if(step != 0){
ret.append(step);
}
//处理前导0问题
while(ret.length() > 1 && ret.charAt(ret.length() - 1) == '0'){
//至少要保留一个0,因此循环条件是>1
ret.deleteCharAt((ret.length() - 1));
}
//处理完毕后再逆置
ret = ret.reverse();
return ret.toString();
}
}
希望本篇文章对您有帮助,有错误您可以指出,我们友好交流
END