算法沉淀——字符串
- 01.最长公共前缀
- 02.最长回文子串
- 03.二进制求和
- 04.字符串相乘
01.最长公共前缀
题目链接:https://leetcode.cn/problems/longest-common-prefix/
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""
。
示例 1:
输入:strs = ["flower","flow","flight"]
输出:"fl"
示例 2:
输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。
提示:
1 <= strs.length <= 200
0 <= strs[i].length <= 200
strs[i]
仅由小写英文字母组成
思路
这里我们可以两两比较,也可以同时比较,这里我使用的是同时比较相同下标的字母,遇到不同或者其中一个字符串越界直接返回即可,若循环结束没有返回,则说明只有一个字符串,返回第一个字符串即可。
代码
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
for (int i = 0; i < strs[0].size(); ++i) {
for (int j = 1; j < strs.size(); ++j) {
// 检查当前位置是否越界或者字符不相等,如果是则返回前缀
if (i == strs[j].size() || strs[0][i] != strs[j][i])
return strs[0].substr(0, i);
}
}
return strs[0]; // 没进入第二个for循环,说明只有一个字符串
}
};
02.最长回文子串
题目链接:https://leetcode.cn/problems/longest-palindromic-substring/
给你一个字符串 s
,找到 s
中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
示例 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd"
输出:"bb"
提示:
1 <= s.length <= 1000
s
仅由数字和英文字母组成
思路
这里我们可以采用中心扩散的方式,计算以每一个字母为中心向左右两边扩散的奇数和偶数的回文串最大长度和该回文串的起始位置,最后返回最长回文串。
代码
class Solution {
public:
string longestPalindrome(string s) {
int begin = 0, len = 0, n = s.size();
for (int i = 0; i < n; ++i) {
// 以当前字符为中心,向左右扩展,检查奇数回文串
int left = i, right = i;
while (left >= 0 && right < n && s[left] == s[right]) {
left--;
right++;
}
// 更新最长回文子串的起始位置和长度
if (right - left - 1 > len) {
begin = left + 1;
len = right - left - 1;
}
// 以当前字符和下一个字符为中心,向左右扩展,检查偶数回文串
left = i;
right = i + 1;
while (left >= 0 && right < n && s[left] == s[right]) {
left--;
right++;
}
// 更新最长回文子串的起始位置和长度
if (right - left - 1 > len) {
begin = left + 1;
len = right - left - 1;
}
}
return s.substr(begin, len);
}
};
03.二进制求和
题目链接:https://leetcode.cn/problems/add-binary/
给你两个二进制字符串 a
和 b
,以二进制字符串的形式返回它们的和。
示例 1:
输入:a = "11", b = "1"
输出:"100"
示例 2:
输入:a = "1010", b = "1011"
输出:"10101"
提示:
1 <= a.length, b.length <= 104
a
和b
仅由字符'0'
或'1'
组成- 字符串如果不是
"0"
,就不含前导零
思路
其实和之前链表中的两数之和的原理是一样的,只不过那个是十进制,而这里是二进制,我们累加进位拼接字符串,计算完之后,不要忘了我们是逆序相加的,所以最后还需要翻转字符串。
代码
class Solution {
public:
string addBinary(string a, string b) {
string ret;
int cur1=a.size()-1,cur2=b.size()-1,t=0;
while(cur1>=0||cur2>=0||t){
if(cur1>=0) t+=a[cur1--]-'0';
if(cur2>=0) t+=b[cur2--]-'0';
ret+=(t%2)+'0';
t/=2;
}
reverse(ret.begin(),ret.end());
return ret;
}
};
04.字符串相乘
题目链接:https://leetcode.cn/problems/multiply-strings/
给定两个以字符串形式表示的非负整数 num1
和 num2
,返回 num1
和 num2
的乘积,它们的乘积也表示为字符串形式。
**注意:**不能使用任何内置的 BigInteger 库或直接将输入转换为整数。
示例 1:
输入: num1 = "2", num2 = "3"
输出: "6"
示例 2:
输入: num1 = "123", num2 = "456"
输出: "56088"
提示:
1 <= num1.length, num2.length <= 200
num1
和num2
只能由数字组成。num1
和num2
都不包含任何前导零,除了数字0本身。
思路
整体思路就是模拟我们小学列竖式计算两个数相乘的过程。但为了我们书写代码的方便性,我们选择一种优化版本,在计算两数相乘的时候,先不考虑进位,等到所有结果计算完毕之后,再去考虑进位。
代码
class Solution {
public:
string multiply(string num1, string num2) {
int m = num1.size(), n = num2.size();
// 反转两个字符串,方便从低位开始相乘
reverse(num1.begin(), num1.end());
reverse(num2.begin(), num2.end());
// 存放每一位相乘的结果
vector<int> tmp(m + n - 1, 0);
// 逐位相乘
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
tmp[i + j] += (num1[i] - '0') * (num2[j] - '0');
}
}
string ret;
int cur = 0, carry = 0;
// 处理进位和构建结果字符串
while (cur < m + n - 1 || carry) {
if (cur < m + n - 1) carry += tmp[cur++];
ret += carry % 10 + '0';
carry /= 10;
}
// 去除结果字符串前导零,保留最后一位 '0'
while (ret.size() > 1 && ret.back() == '0') ret.pop_back();
// 反转结果字符串
reverse(ret.begin(), ret.end());
return ret;
}
};