哈希表
242. 有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
class Solution {
public:
bool isAnagram(string s, string t) {
vector<int> res(26,0);
for(char c : s) res[c - 'a']++;
for(char d : t)
{
if(res[d - 'a'] == 0) return false;
res[d-'a']--;
}
for(int i = 0; i < res.size(); i++)
{
if(res[i] != 0) return false;
}
return true;
}
};
383. 赎金信
给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串 ransom 能不能由第二个字符串 magazines 里面的字符构成。如果可以构成,返回 true ;否则返回 false。
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
vector<int>res(26,0);
for(char c : magazine) res[c-'a']++;
for(char d : ransomNote){
if(res[d-'a'] == 0) return false;
res[d-'a']--;
}
return true;
}
};
1002. 查找常用字符(☆)
给定仅有小写字母组成的字符串数组 A,返回列表中的每个字符串中都显示的全部字符(包括重复字符)组成的列表。例如,如果一个字符在每个字符串中出现 3 次,但不是 4 次,则需要在最终答案中包含该字符 3 次。
class Solution {
public:
vector<string> commonChars(vector<string>& A) {
vector<string> result;
if (A.size() == 0) return result;
int hash[26] = {0}; // 用来统计所有字符串里字符出现的最小频率
for (int i = 0; i < A[0].size(); i++) { // 用第一个字符串给hash初始化
hash[A[0][i] - 'a']++;
}
int hashOtherStr[26] = {0}; // 统计除第一个字符串外字符的出现频率
for (int i = 1; i < A.size(); i++) {
memset(hashOtherStr, 0, 26 * sizeof(int));
for (int j = 0; j < A[i].size(); j++) {
hashOtherStr[A[i][j] - 'a']++;
}
// 更新hash,保证hash里统计26个字符在所有字符串里出现的最小次数
for (int k = 0; k < 26; k++) {
hash[k] = min(hash[k], hashOtherStr[k]);
}
}
// 将hash统计的字符次数,转成输出形式
for (int i = 0; i < 26; i++) {
while (hash[i] != 0) { // 注意这里是while,多个重复的字符
string s(1, i + 'a'); // char -> string
result.push_back(s);
hash[i]--;
}
}
return result;
}
};
349. 两个数组的交集
给定两个数组,编写一个函数来计算它们的交集。
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> set;
vector<int> res;
for(int c : nums1) set.insert(c);
sort(nums2.begin(), nums2.end());
for(int i = 0; i < nums2.size(); i++){
if(i > 0 && nums2[i] == nums2[i-1]) continue;
if(set.find(nums2[i]) != set.end()) res.push_back(nums2[i]);
}
return res;
}
};
350. 两个数组的交集 II
给定两个数组,编写一个函数来计算它们的交集。
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
unordered_map<int, int> map1;
unordered_map<int, int> map2;
vector<int> res;
for(int c : nums1) map1[c]++;
for(int d : nums2) map2[d]++;
sort(nums1.begin(), nums1.end());
for(int i = 0; i < nums1.size(); i++)
{
if(i > 0 && nums1[i] == nums1[i-1]) continue;
int k = min(map1[nums1[i]], map2[nums1[i]]);
while(k != 0)
{
res.push_back(nums1[i]);
k--;
}
}
return res;
}
};
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
//利用双指针
sort(nums1.begin(),nums1.end());
sort(nums2.begin(), nums2.end());
int left = 0, right = 0;
vector<int> res;
while(left < nums1.size() && right < nums2.size()) {
if(nums1[left] < nums2[right]) {
left++;
} else if(nums1[left] > nums2[right]) {
right++;
} else {
res.push_back(nums1[left]);
left++;
right++;
}
}
return res;
}
};
202. 快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 true ;不是,则返回 false 。
其中对于无限循环,那么需要有一个集合来存储以前的sum如果存在则立刻退出,如果不存在就加入几何
class Solution {
public:
// 取数值各个位上的单数之和
int getSum(int n) {
int sum = 0;
while (n) {
sum += (n % 10) * (n % 10);
n /= 10;
}
return sum;
}
bool isHappy(int n) {
unordered_set<int> set;
while(1) {
int sum = getSum(n);
if (sum == 1) {
return true;
}
// 如果这个sum曾经出现过,说明已经陷入了无限循环了,立刻return false
if (set.find(sum) != set.end()) {
return false;
} else {
set.insert(sum);
}
n = sum;
}
}
};
1. 两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
std::unordered_map <int,int> map;
for(int i = 0; i < nums.size(); i++)
{
auto iter = map.find(target - nums[i]);
if(iter != map.end())
{
return {iter->second, i};
}
map[nums[i]] = i;
}
return {};
}
};
15. 三数之和(☆)
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
双指针
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
sort(nums.begin(), nums.end());
// 找出a + b + c = 0
// a = nums[i], b = nums[left], c = nums[right]
for (int i = 0; i < nums.size(); i++) {
// 排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
if (nums[i] > 0) {
return result;
}
// 错误去重方法,将会漏掉-1,-1,2 这种情况
/*
if (nums[i] == nums[i + 1]) {
continue;
}
*/
// 正确去重方法
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1;
int right = nums.size() - 1;
while (right > left) {
// 去重复逻辑如果放在这里,0,0,0 的情况,可能直接导致 right<=left 了,从而漏掉了 0,0,0 这种三元组
/*
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
*/
if (nums[i] + nums[left] + nums[right] > 0) {
right--;
} else if (nums[i] + nums[left] + nums[right] < 0) {
left++;
} else {
result.push_back(vector<int>{nums[i], nums[left], nums[right]});
// 去重逻辑应该放在找到一个三元组之后
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
// 找到答案时,双指针同时收缩
right--;
left++;
}
}
}
return result;
}
};
18. 四数之和(☆)
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:答案中不可以包含重复的四元组。
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> result;
sort(nums.begin(), nums.end());
for (int k = 0; k < nums.size(); k++) {
// 这种剪枝是错误的,这道题目target 是任意值
// if (nums[k] > target) {
// return result;
// }
// 去重
if (k > 0 && nums[k] == nums[k - 1]) {
continue;
}
for (int i = k + 1; i < nums.size(); i++) {
// 正确去重方法
if (i > k + 1 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1;
int right = nums.size() - 1;
while (right > left) {
if (nums[k] + nums[i] + nums[left] + nums[right] > target) {
right--;
} else if (nums[k] + nums[i] + nums[left] + nums[right] < target) {
left++;
} else {
result.push_back(vector<int>{nums[k], nums[i], nums[left], nums[right]});
// 去重逻辑应该放在找到一个四元组之后
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
// 找到答案时,双指针同时收缩
right--;
left++;
}
}
}
}
return result;
}
};
字符串
179. 最大数
给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。
注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。
class Solution {
public:
static bool cmp (const int &a, const int &b) {
//str_a+str_b > str_b+str_a
string sa = to_string(a);
string sb = to_string(b);
return sa + sb > sb + sa;
}
string largestNumber(vector<int>& nums) {
//重点在排序
sort(nums.begin(), nums.end(),cmp);
string str;
for(int num : nums) {
if(!(num == 0 && str[0] == '0')) {
str += to_string(num);
}
}
return str;
}
};
28. 实现 strStr()
实现 strStr() 函数。
class Solution {
public:
int strStr(string haystack, string needle) {
//直接遍历,当然也可以利用昨天的固定滑动窗口
if(haystack.size() < needle.size()) return -1;
if(needle.size() == 0) return 0;
for(int i = 0; i <= haystack.size() - needle.size(); i++) {
if(haystack[i] == needle[0]) {
string str = haystack.substr(i, needle.size());
if(str == needle) return i;
}
}
return -1;
}
};
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。
541. 反转字符串 II(☆)
给定一个字符串 s 和一个整数 k,你需要对从字符串开头算起的每隔 2k 个字符的前 k 个字符进行反转。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
class Solution {
public:
void reverse(string& s, int start, int end) {
for (int i = start, j = end; i < j; i++, j--) {
s[i] ^= s[j];
s[j] ^= s[i];
s[i] ^= s[j];
}
}
string reverseStr(string s, int k) {
for (int i = 0; i < s.size(); i += (2 * k)) {
// 1. 每隔 2k 个字符的前 k 个字符进行反转
// 2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符
if (i + k <= s.size()) {
reverse(s, i, i + k - 1);
continue;
}
// 3. 剩余字符少于 k 个,则将剩余字符全部反转。
reverse(s, i, s.size() - 1);
}
return s;
}
};
剑指 Offer 05. 替换空格
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
class Solution {
public:
string replaceSpace(string s) {
int count = 0;
int oldsize = s.size();
for(int i = 0; i < s.size(); i++)
{
if(s[i] == ' ') count++;
}
s.resize(s.size() + 2 * count);
for(int i = s.size() - 1, j = oldsize - 1; i > j; j--, i--)
{
if (s[j] != ' ') {
s[i] = s[j];
} else {
s[i] = '0';
s[i - 1] = '2';
s[i - 2] = '%';
i -= 2;
}
}
return s;
}
};
151. 翻转字符串里的单词(☆)
给你一个字符串 s ,逐个翻转字符串中的所有 单词 。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
请你返回一个翻转 s 中单词顺序并用单个空格相连的字符串。
说明:
输入字符串 s 可以在前面、后面或者单词间包含多余的空格。
翻转后单词间应当仅用一个空格分隔。
翻转后的字符串中不应包含额外的空格。
class Solution {
public:
string reverseWords(string s) {
//翻转整个字符串
reverse(s.begin(), s.end());
int sz = s.size();
int index = 0;
for(int start = 0; start < sz; start++) {
if(s[start] != ' ') {
//填一个空白字符然后将index移动到下一单词的开头
if(index!= 0) s[index++] = ' ';
//循环遍历至单词的末尾
int end = start;
while(end < sz && s[end] != ' ') {
s[index++] = s[end++];
}
//反转整个单词
reverse(s.begin() + index - (end - start), s.begin() + index);
//更新start去寻找下一个单词
start =end;
}
}
s.erase(s.begin()+index, s.end());
return s;
}
};
395. 至少有 K 个重复字符的最长子串(☆☆)
给你一个字符串 s 和一个整数 k ,请你找出 s 中的最长子串, 要求该子串中的每一字符出现次数都不少于 k 。返回这一子串的长度。
class Solution {
public:
int longestSubstring(string s, int k) {
//分治:对于一个字符串来说,如果要求子串最少出现k次,那么如果某些字母出现的次数小于k,
//这些字母一定不会出现在最长的子串中,并且这些字母将整个字符子串分割成小段,这些小段有可能是最长的
//但是由于被分割了,还是要检查这一小段,如果某些字母出现的次数小于k,会将小段继续分割下去,
//比如字符串"aacbbbdc",要求最少出现2次,我们记录左右闭区间,,
//第一轮[0,7],处理"aacbbbdc",d只出现了一次不满足,于是递归解决区间[0,5]、[7,7]
//第二轮[0,5],处理"aacbbb", c只出现了一次不满足,于是递归解决区间[0,1]、[3,4]
//第二轮[7,7],处理"c", c只出现了一次不满足,不继续递归
//第三轮[0,1],处理"aa", 满足出现次数>=2,ret=2
//第三轮[3,4],处理"bbb", 满足出现次数>=2 ret=3;
if(k <= 1) return s.size();
if(s.empty() || s.size() < k) return 0;
vector<int> hash(128, 0);
for(char c : s) ++hash[c];
int i = 0;
while( i < s.size() && hash[s[i]] >= k) ++i;
if(i == s.size()) return s.size();
int left = longestSubstring(s.substr(0, i), k);
while(i < s.size() && hash[s[i]] < k) ++i;
int right = longestSubstring(s.substr(i), k);
return max(left, right);
}
};
438. 找到字符串中所有字母异位词(☆☆)
给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。
字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100
567. 字符串的排列
给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。
换句话说,第一个字符串的排列之一是第二个字符串的 子串 。
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
//滑动窗口
vector<int> res;
if(s.size() < p.size()) return res;
vector<int> hash_s(26,0), hash_p(26,0);
int left = 0, right = 0;
//初始化代码
for(int i = 0; i < p.size(); i++) {
hash_p[p[i] - 'a']++;
hash_s[s[right++] - 'a']++;
}
if(hash_s == hash_p) res.push_back(left);
//固定长度的滑动窗口
while(right < s.size()) {
hash_s[s[right++] - 'a']++;
hash_s[s[left++] - 'a']--;
if(hash_s == hash_p) res.push_back(left);
}
return res;
}
};
459. 重复的子字符串(☆)
给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
class Solution {
public:
bool repeatedSubstringPattern(string s) {
/*
*KMP
*时间复杂度
*空间复杂度
*/
if (s.size() == 0) return false;
int len = s.size();
int next[len];
getNext(next,s);
if (next[len - 1] != 0 && len % (len - next[len - 1]) == 0) //如果len % (len - (next[len - 1] + 1)) == 0 ,则说明 (数组长度-最长相等前后缀的长度) 正好可以被 数组的长度整除,说明有该字符串有重复的子字符串。
return true;
return false;
}
void getNext (int* next, const string& s) {
next[0] = 0;
int j = 0;
for(int i = 1; i < s.size(); i++) {
while (j > 0 && s[i] != s[j]) j = next[j-1];//不相同就进行回溯
if (s[i] == s[j]) j++;
next[i] = j;
}
}
};
class Solution {
public:
bool repeatedSubstringPattern(string s) {
/*
假设母串S是由子串s重复N次而成, 则 S+S则有子串s重复2N次, 那么现在有: S=Ns, S+S=2Ns, 其中N>=2。
如果条件成立, S+S=2Ns, 掐头去尾破坏2个s,S+S中还包含2*(N-1)s, 又因为N>=2,
因此S在(S+S)[1:-1]中必出现一次以上
*/
return (s + s).find(s, 1) != s.size();
}
};
位运算
172. 阶乘后的零(☆)
给定一个整数 n,返回 n! 结果尾数中零的数量。
class Solution {
public:
int trailingZeroes(int n) {
/*
理解题意:
题目给定一个整数 n
需要返回 n 的阶乘尾数有几个 0
整体思路
首先得知道有 2 * 5 这个因式才能得出末尾有 0 的数
就可以把问题转换成:题目给定的 n! 中有几个 2 * 5 末尾就有几个 0,而 2 是任何偶数都有的因子,所以只要考虑 n! 中一共有多少个 5 就可以了
那么可以分这几种情况:
首先是 5 的倍数,它们就包含至少一个因子 5,比如 5、10、15、20,这几个都是 5 的倍数且只包含一个因子 5
除了 5、10、15、20,比如 25 = 5 * 5,包含两个因子 5,所以 25 的倍数 50、75 这些都包含了两个因子 5
还有一个特殊点的数 125 = 5 * 5 * 5,包含了三个因子 5
现在就拿 125! 来举例算出它的末尾有多少个 0
先去掉 5 的倍数,125 / 5 = 25,首先得出 有 25 个数是 5 的倍数(这 25 个数包含了 5 的倍数,也说明包含着 25 的倍数,125 的倍数),那么第一轮运算可以得出提供因子 5 个数有至少 25 个
然后去掉 25 的倍数,125 / 25 = 5,可以得出有 5 个数是 25 的倍数,由于第一轮算出的 5 的倍数的数包含了这 5 个数,所以这 5 个数每个数额外提供了 5 个因子 5
最后计算 125 的倍数,125 / 125 = 1,同上 125 再额外提供一个因子 5
最后可以算出三轮一共提供因子 5 的个数为 25 + 5 + 1 = 31
*/
//其实就是含有5的个数
int count = 0;
while(n/5 != 0) {
count += n / 5;
n /= 5;
}
return count;
}
};
190. 颠倒二进制位
颠倒给定的 32 位无符号整数的二进制位。
class Solution {
public:
uint32_t reverseBits(uint32_t n) {
uint32_t res;
int i = 32;
while(i--) {
res <<= 1;
res += n & 1;
n >>= 1;
}
return res;
}
};
338. 比特位计数(☆)
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
class Solution {
public:
vector<int> countBits(int n) {
//动态规划思想
/*
i & (i - 1)可以去掉i最右边的一个1(如果有),因此 i & (i - 1)是比 i 小的,而且i & (i - 1)的1的个数已经在前面算过了,所以i的1的个数就是 i & (i - 1)的1的个数加上1
*/
vector<int> dp(n+1);
for(int i = 1; i <= n; i++) {//注意要从1开始,0不满足
dp[i] = dp[i & (i-1)] + 1;
}
return dp;
}
};
class Solution {
public:
vector<int> countBits(int n) {
//动态规划思想
/*
i >> 1会把最低位去掉,因此i >> 1 也是比i小的,同样也是在前面的数组里算过。当 i 的最低位是0,则 i 中1的个数和i >> 1中1的个数相同;当i的最低位是1,i 中1的个数是 i >> 1中1的个数再加1
*/
vector<int> dp(n+1);
for(int i = 0; i <= n; i++) {
dp[i] = dp[i >> 1] + (i & 1); //注意i&1需要加括号
}
return dp;
}
};
461. 汉明距离
两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。
给你两个整数 x 和 y,计算并返回它们之间的汉明距离。
思路:首先直接进行^运算。如果位相同就是0,否则就是1,
接下来就是统计1的个数,可以利用&运算,如果相同就是1,否则0
class Solution {
public:
int hammingDistance(int x, int y) {
int res = 0;
int z = x ^ y;
while(z) {
res += z & 1;
z >>= 1;
}
return res;
}
};
136. 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
class Solution {
public:
int singleNumber(vector<int>& nums) {
int res = 0;
for(int num : nums) {
res ^= num;
}
return res;
}
};
剑指 Offer 56 - I. 数组中数字出现的次数
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
vector<int> res;
sort(nums.begin(), nums.end());
for(int i = 0; i < nums.size(); i++) {
if(res.empty()) res.push_back(nums[i]);
else if(res.back() == nums[i]) res.pop_back();
else res.push_back(nums[i]);
}
return res;
}
};
剑指 Offer 56 - II. 数组中数字出现的次数 II
在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
class Solution {
public:
int singleNumber(vector<int>& nums) {
sort(nums.begin(), nums.end());
for(int i = 0; i < nums.size()-1; i += 3) {
if(nums[i] != nums[i+1]) return nums[i];
}
return nums.back();
}
};
696. 计数二进制子串(☆)
给定一个字符串 s,计算具有相同数量 0 和 1 的非空(连续)子字符串的数量,并且这些子字符串中的所有 0 和所有 1 都是连续的。
重复出现的子串要计算它们出现的次数。
class Solution {
public:
int countBinarySubstrings(string s) {
//先统计连续的0和1分别有多少个,如:111100011000,得到4323;在4323中的任意相邻两个数字,取小的一个加起来,就是3+2+2 = 7.
int last = 0, res = 0, cur = 1;
for(int i = 1; i < s.size(); i++) {
if(s[i] == s[i-1]) cur++;
else {
last = cur;
cur = 1;
}
if(last >= cur) res++;
}
return res;
}
};
50. Pow(x, n)(☆)
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。
class Solution {
public:
double myPow(double x, int n) {
/*
使用折半计算,每次把n缩小一半,这样n最终会缩小到0,任何数的0次方都为1,这时候我们再往回乘,
如果此时n是偶数,直接把上次递归得到的值算个平方返回即可,如果是奇数,则还需要乘上个x的值。
还有一点需要引起我们的注意的是n有可能为负数,对于n是负数的情况,我们可以先用其绝对值计算出一个结果再取其倒数即可。
我们让i初始化为n,然后看i是否是2的倍数,是的话x乘以自己,否则res乘以x,i每次循环缩小一半,直到为0停止循环。最后看n的正负,如果为负,返回其倒数。
*/
double res = 1;
for(int i = n; i != 0; i /= 2) {
if(i % 2 != 0) res *= x;
x *= x;
}
return n < 0? 1/res : res;
}
};
栈和队列
20. 有效的括号
给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
class Solution {
public:
bool isValid(string s) {
stack<char> st;
for(int i = 0; i < s.size(); i++) {
if(s[i] == '(' || s[i] == '[' || s[i] == '{') st.push(s[i]);
else if (s[i] == ')') {
if(st.empty() || st.top() != '(') return false;
st.pop();
} else if(s[i] == ']') {
if(st.empty() || st.top() != '[') return false;
st.pop();
} else if(s[i] == '}') {
if(st.empty() || st.top() != '{') return false;
st.pop();
}
}
return st.empty();
}
};
1047. 删除字符串中的所有相邻重复项
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
class Solution {
public:
string removeDuplicates(string S) {
string result;
for(char s : S) {
if(result.empty() || result.back() != s) {
result.push_back(s);
}
else {
result.pop_back();
}
}
return result;
}
};
150. 逆波兰表达式求值
根据 逆波兰表示法,求表达式的值。
有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> st;
for(string str : tokens) {
if(str == "+" || str == "-" || str == "/" || str == "*") {
int num1 = st.top();
st.pop();
int num2 = st.top();
st.pop();
if(str == "+") {
st.push(num2 + num1);
} else if(str == "-") {
st.push(num2 - num1);
} else if(str == "/") {
st.push(num2 / num1);
} else if(str == "*") {
st.push(num2 * num1);
}
} else {
st.push(stoi(str));
}
}
int res = st.top();
st.pop();
return res;
}
};
227. 基本计算器 II
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
整数除法仅保留整数部分。
【笔记】一般需要符号栈、数据栈,两个。但是,看到网上一个写的不错的算法,只用了一个数据栈。符号栈用一个变量sign代替了,只存储上一个符号,主要思想如下:
将减法转化为加法(取相反数)
由于乘除法优先级高,直接计算
整数不仅一位,会>10
表达式中没有括号
注意:加减乘除空格的ASCII码都小于’0’,ASCII对照表如下
class Solution {
public:
int calculate(string s) {
/*
*逆波兰法
*/
int res = 0, sum = 0;
char sign = '+';
stack<int> nums;
for(int i = 0; i < s.size(); i++) {
//判断是不是大于10
if(s[i] >= '0') {//加减乘除和空格ASCII码都小于'0'
sum = sum * 10 - '0'+ s[i]; //进位(先减法)
}
if((s[i] < '0' && s[i] != ' ') || i == s.size()-1) {
if(sign == '+') {
nums.push(sum);
} else if(sign == '-') {
nums.push(-sum);
} else if(sign == '*' || sign == '/') {
int tmp = (sign == '*'? nums.top() * sum : nums.top() / sum);
nums.pop();
nums.push(tmp);
}
sign = s[i];
sum = 0;
}
}
while (!nums.empty()) {
res += nums.top();
nums.pop();
}
return res;
}
};