目录
- 最长公共前缀
- 题目解析
- 算法原理
- 代码
- 最长回文子串
- 题目解析
- 算法原理
- 代码
- 二进制求和
- 题目解析
- 算法原理
- 代码
- 字符串相乘
- 题目解析
- 算法原理
- 代码
最长公共前缀
题目链接
题目解析
只需找出字符串中的公共的最长字符串即可
算法原理
1.法一:两两字符串比较,比较完和下一个字符串比较,找出所有字符串中共同的子串
2.法二:统一比较,固定i不变,逐一比较每行的第i个元素,存在不同就比较完成
3.法三:先算出最小字符串的长度,(统一比较)然后逐一比较每个字符串中字符是否相同
代码
// 解法一
// N:字符串的个数 M:字符串的平均长度
// 时间复杂度:O(N*M)
// 空间复杂度:O(1)
class Solution
{
public:
string longestCommonPrefix(vector<string>& strs)
{
// 2. 统一比较
for(int i = 0;i < strs[0].size();++i)// 列
{
char ch = strs[0][i];
for(int j = 1;j < strs.size();++j)// 行
{
if(i == strs[j].size() || ch != strs[j][i])
return strs[0].substr(0,i);
}
}
return strs[0];
}
};
// 解法二
// N:字符串的个数 M:字符串的平均长度
// 时间复杂度:O(N*M)
// 空间复杂度:O(1)
class Solution
{
public:
string longestCommonPrefix(vector<string>& strs)
{
// 2. 统一比较
for(int i = 0;i < strs[0].size();++i)// 列
{
char ch = strs[0][i];
for(int j = 1;j < strs.size();++j)// 行
{
if(i == strs[j].size() || ch != strs[j][i])
return strs[0].substr(0,i);
}
}
return strs[0];
}
};
// 解法三
// N:字符串的个数 M:字符串的平均长度
// 时间复杂度:O(N*M)
// 空间复杂度:O(M)
class Solution
{
public:
string longestCommonPrefix(vector<string>& strs)
{
// 3. 取出最小字串的长度
// 然后逐一比较各位字符
if(strs.size() == 1)
return strs[0];
string ret;
int m = 200;
for(int i = 0;i < strs.size();i++)
{
int k = strs[i].size();
m = min(m,k);
}
// 列
for(int i = 0;i < m;i++)
{
// 行
int flag = 1;
char t = 0;
for(int j = 0;j < strs.size()-1;++j)
{
t = strs[j][i];
if(strs[j][i] != strs[j+1][i])
{
flag = 0;
break;
}
}
if(flag == 1)
{
ret.push_back(t);
}
else break;
}
return ret;
}
};
最长回文子串
题目链接
题目解析
找出字符串的最长回文子串 bab aba 子串
算法原理
解法一:暴力枚举,每次枚举一个字符串,用O(N^2),再判断是否是回文串用O(N),三层循环,O(N^3),固定i = 0,每次从j = i开始枚举字符串,再判断字符串
解法二:从中间开始向两边扩展,固定一个中点,i遍历n次,第一种情况left和right都从i位置向两边扩展(字符串是奇数个字符),第二种情况,left从i位置,right从i+1位置向两边扩展(字符串是偶数个字符),这样字符串是奇数和偶数的情况都覆盖到了,两种情况遍历字符串2*n次,时间复杂度是O(N*N)
代码
class Solution
{
public:
string longestPalindrome(string s)
{
int n = s.size();
int begin = 0,len = 0;// 起始位置和长度
// 时间复杂度:O(N^2) -> n * 2n
// 空间复杂度:O(1)
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);
}
};
二进制求和
题目链接
题目解析
按照二进制的加法求和
算法原理
高精度算法
用t来记录两个字符串各个位上的加和,t%2是相加之后的值,t/2是进位,t再和下一次两个字符串各位上的值相加如此往复即可得到答案,可以自己模拟一遍
代码
class Solution
{
public:
string addBinary(string a, string b)
{
// 高精度加法
// 时间复杂度:O(ab字符串长的那个)
// 空间复杂度:O(ab字符串长的那个)
string ret;
int t = 0;
int cur1 = a.size() - 1,cur2 = b.size() - 1;
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;
}
};
字符串相乘
题目链接
题目解析
两个字符串相乘
算法原理
法一:模拟,固定一个字符和其他字符串相乘,两个for循环,注意要先逆置后计算,先要加入前导零,<高位相乘的时候要补上零>,表示逆序,加完后就是逆序的结果了 <最后处理前导零并且要逆序回来>
法二:1. 无进位相乘然后相加(注意是逆序的)并且最后乘出来的数组大小是m+n-1(按下标相加的大小来看)
- 处理进位 (t表示数组中的值,t%10 -> 该位的数值 ,t / 10 ->进位)
- 处理前导零
- 逆序
代码
class Solution
{
public:
string multiply(string num1, string num2)
{
// 高精度乘法
// 先无进位相乘再相加,处理进位,和前导零
// 1. 准备工作
int n = num1.size(),m = num2.size();
// 逆置字符串
reverse(num1.begin(),num1.end());
reverse(num2.begin(),num2.end());
vector<int> tmp(n+m-1);
// 2.无进位相乘再相加
for(int i = 0;i < n;++i)
for(int j = 0;j < m;++j)
tmp[i + j] += (num1[i] - '0') * (num2[j] - '0');
// 3.处理进位
string ret;
int cur1 = 0,t = 0;// cur1 下标 t 进位
while(cur1 < m+n-1 || t != 0)
{
if(cur1 < m + n - 1) t += tmp[cur1++];
ret += t % 10 + '0';// 该位的数值
t /= 10;// 进位
}
// 4. 处理前导零 逆置后零在后面 0 02 -> 20
//while(ret.size() > 1 && ret[ret.size()-1] == '0') ret.pop_back();
// ret.back()
while(ret.size() > 1 && ret.back() == '0') ret.pop_back();
reverse(ret.begin(),ret.end());
return ret;
}
};