今天,写两个字符串的题目,因为这一块刚开始的题目比较简单,思路也不是太多,所以两个写到一篇博客。
字符串中的第一个唯一字符
给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。
案例:
s = “leetcode”
返回 0.
s = “loveleetcode”,
返回 2.
注意事项:您可以假定该字符串只包含小写字母。
这个题思路比较单一, 遍历一遍数组,并统计每个字符的个数,我用的unordered_map,因为碰到字符计数的,第一感觉就想到了map, 然后遍历一遍unordered_map,看第一个值为1的就是答案。返回坐标。
class Solution {
public:
int firstUniqChar(string s) {
int len = s.size();
int res = -1;
unordered_map <int, int> m;
for (int i=0; i<len; i++)
{
m[s[i]]++;
}
for (int i=0; i<len; i++)
{
if (m[s[i]] == 1)
{
res = i;
break;
}
}
return res;
}
};
这个题思路比较单一。 最好别用暴力,第一次用暴力超时了。
有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
示例 1:
输入: s = “anagram”, t = “nagaram”
输出: true
示例 2:
输入: s = “rat”, t = “car”
输出: false
说明:
你可以假设字符串只包含小写字母。
进阶:
如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?
1. 思路一 - 基于排序
这个是我的初始思路,就是给两个字符串排序,如果是字母异位词,两个字符串应该相等,否则,就不是,所以这个用C++实现,代码挺短的。
class Solution {
public:
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!=t)
return false;
return true;
}
};
这个思路比较清晰,但是时间复杂度有点高,涉及到了两次排序,时间复杂度O(nlogn)。
思路二 - 基于map
第一个思路的时间复杂度有点高,所以就又想起了计数的思想, 可以再用map,遍历第一个字符串,用map自增计数,然后遍历第二个字符串,用map自减计数。如果两个是异位字符串,那么最后map 的值应该是0,否则,不是。
class Solution {
public:
bool isAnagram(string s, string t) {
map <char, int> m;
int lens = s.size();
int lent = t.size();
if (lens != lent)
return false;
for (int i =0; i<lens; i++)
{
m[s[i]]++;
}
for (int i=0; i<lent; i++)
{
m[t[i]]--;
}
map <char, int>::iterator it;
for (it=m.begin(); it!=m.end(); it++)
{
if (it->second != 0)
return false;
}
return true;
}
};
这个效率要比上面的思路一高一些。
思路三 - 基于数组统计个数
由于这个题里面只说了可以假设都是小写字母,那么只需要统计26个小写字母的个数即可,所以,用一个数组统计会快很多,因为直接基于下标访问,时间复杂度会是O(1)。所以这个效率是最高的。
class Solution {
public:
bool isAnagram(string s, string t) {
if (s.size() != t.size())
return false;
int *a = new int[26]();
for (int i=0; i<s.size(); i++)
{
a[s[i]-'a']++;
a[t[i]-'a']--;
}
for (int i=0; i<26; i++)
{
if (a[i] != 0)
return false;
}
return true;
}
};
但是,这个也要注意,就是适用于都是字母的,如果有Unicode字符,不适用。