字符串
- 反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
void reverseString(vector<char>& s) {
int n = s.size();
int left = 0, right = n - 1; //双指针
while (left < right)
{
swap(s[left++], s[right--]);
}
}
题解思路:双向指针,依次交换即可。
- 整数反转
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。
int reverse(int x) {
string s=to_string(x); //变成字符串
std::reverse(s.begin(), s.end()); //翻转字符串
int ans=0;
try{
ans=stoi(s); //变回数字
if (x<0) ans=-ans; //x是负数,加上负号
}catch(exception ex){} //溢出,啥也不做,返回零
return ans;
}
题解思路:先将数字转为字符串,然后将字符串进行反转,再变回数字即可,使用try检测异常(若溢出会抛出异常),若无溢出,则返回结果即可。
- 字符串中的第一个唯一字符
给定一个字符串
s
,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回-1
。
int firstUniqChar(string s) {
int* ar = new int[26] {}; //字母出现次数
int n = s.length();
char* chr = new char[n + 1];
strcpy(chr, s.c_str());
for (int i = 0; i < n; i++)
{
ar[chr[i] - 'a']++; //ar[s[i] - 'a']++;
}
for (int i = 0; i < n; i++)
{
if (ar[chr[i] - 'a'] == 1) //(ar[s[i] - 'a'] == 1)
return i;
}
return -1;
}
题解思路:使用二维数组存储字符串中每个单词出现的次数,先将字符串存入字符数组中(太菜了,第一时间只想到使用字符数组,依次遍历)
- 有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
bool isAnagram(string s, string t) {
if (s.size() != t.size())
return false;
int* ar = new int[26]{}; //字母出现次数
int* br = new int[26]{};
int n = s.length();
char* chr_s = new char[n + 1];
char* chr_t = new char[n + 1];
strcpy(chr_s, s.c_str());
strcpy(chr_t, t.c_str());
for (int i = 0; i < n; i++)
{
ar[chr_s[i] - 'a']++;
br[chr_t[i] - 'a']++;
}
for (int i = 0; i < 26; i++)
{
if (ar[i] != br[i])
return false;
}
return true;
}
题解思路:和上题类似,均是求字母出现个数,获得ar和br后比较即可。
bool isAnagram(string s, string t) {
if (s.size() != t.size())
return false;
int* ar = new int[26]{}; //字母出现次数
int* br = new int[26]{};
int n = s.length();
for (int i = 0; i < n; i++)
{
ar[s[i] - 'a']++;
br[t[i] - 'a']++;
}
for (int i = 0; i < 26; i++)
{
if (ar[i] != br[i])
return false;
}
return true;
}
优化版。(内存消耗降低)
也可对字符串进行排序,然后进行字符串比较。如下:
bool isAnagram(string s, string t) {
if (s.size() != t.size())
return false;
sort(s.begin(), s.end());
sort(t.begin(), t.end());
if (!s.compare(t))
return true;
return false;
}
- 验证回文串
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。
bool isPalindrome(string s) {
int length = s.size();
char *chr = new char[length + 1];
strcpy(chr, s.c_str());
int left = 0, right = length;
while (left < right)
{
//忽略掉非字母和非数字
if (!isalpha(chr[left]) && !isdigit(chr[left]))
{
left++;
continue;
}
else if (!isalpha(chr[right]) && !isdigit(chr[right]))
{
right--;
continue;
}
//开始判断
if (tolower(chr[left]) == tolower(chr[right]))
{
left++;
right--;
continue;
}
else
return false;
}
return (left == right || left > right)? true : false;
}
题解思路:双向指针,left从左至右,right从右至左,若其中一个为非英文字符则令另一个等待,直至两个均为英文字符,然后进行比较。注意结果应为left==right || left > right
- 字符串转换整数 (atoi)
请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。
函数 myAtoi(string s) 的算法如下:
1. 读入字符串并丢弃无用的前导空格
2. 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
3. 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
4. 将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
5. 如果整数数超过 32 位有符号整数范围 [−231, 231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,
大于 231 − 1 的整数应该被固定为 231 − 1 。
6. 返回整数作为最终结果。
int myAtoi(string s) {
stringstream liu(s);
int n = 0;
liu >> n;
return n;
}
题解思路:stringstream类的使用
- 实现 strStr()
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。
int strStr(string haystack, string needle) {
if (haystack.size() < needle.size())
return -1;
//int location = 0;
int i = 0, j = 0;
for (; i < haystack.size(); i++)
{
if (haystack[i] == needle[0])
{
string temp = haystack.substr(i, needle.size());
if (!needle.compare(temp))
return i;
}
}
return -1;
}
题解思路:本题即为找字串的问题,对目标串进行遍历,若与模式串的的首元素相同,则截取自该元素起,模式串大小的子串与模式串进行比较,若相等则返回当前位置,反之继续遍历。
- 外观数列
给定一个正整数
n
,输出外观数列的第n
项。「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。
前五项如下:
1. 1
2. 11
3. 21
4. 1211
5. 111221
第一项是数字 1
描述前一项,这个数是 1 即 “ 一 个 1 ”,记作 "11"
描述前一项,这个数是 11 即 “ 二 个 1 ” ,记作 "21"
描述前一项,这个数是 21 即 “ 一 个 2 + 一 个 1 ” ,记作 "1211"
描述前一项,这个数是 1211 即 “ 一 个 1 + 一 个 2 + 二 个 1 ” ,记作 "111221"
string countAndSay(int n)
{
if (n > 30 || n < 1)
return "";
int temp = 2;
string pre_result = "1";
string result;
if (n == 1)
return pre_result; //基础值
else
{
while (temp <= n) //从2开始计算
{
char ch = '0';
int num = 0;
//string result;
for (int i = 0; i <= pre_result.size(); i++)
{
if (ch == '0'||pre_result[i] == ch) //直至该字符结束
{
ch = pre_result[i]; //字符覆盖
num++; //字符个数++
}
else //下一个字符
{
result.push_back(num + '0'); //压入个数
result.push_back(ch); //压入字符
ch = '0';
num = 0; //ch & num 初始化
i--;
}
}
if (!(++temp <= n)) //还需要计算
break;
pre_result = result; //目标的前一个结果
result = ""; //初始化
}
}
return result;
}
题解思路:若n==1,则直接返回"1"(基础值),当n>=2时,依次计算2,3,……,n-1,n所对应的字符串。
-
最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串
""
。
string longestCommonPrefix(vector<string>& strs) {
string result;
if (strs.size() == 1) //最小情况
return strs[0];
int index = -1, size = 201; //题设size最大为200
int i = 0;
for (; i < strs.size(); i++)
{
if (strs[i].size() == 0) //空串
return "";
index = strs[i].size() < size ? i : index; //找到最小串的索引
size = strs[i].size() < size ? strs[i].size() : size;
//cout << strs[i].size() << endl;
}
size = 0; //重利用
while (size < strs[index].size() + 1)
{
//将整个最小串和其他串进行对比,不相等则缩一位
result = strs[index].substr(0, strs[index].size() - size);
i = 0;
int temp = 0; //不匹配个数
while (i < strs.size())
{
if (i == index && i++) //跳过原串
continue;
if (strs[i++].substr(0, strs[index].size() - size) != result && temp++)//没有匹配
break;
}
if (!temp) //所有串成功匹配
break;
size++;
}
return result;
}
题解思路:首先若存在空串则返回其即可;找出字符串数组中字符串大小最小的元素,将其逐步缩小的子串并与其他字串前缀相同长度的子串进行比较,直至空串(即没有相同前缀)
2022年5月25日