- 一些算法题的总结,部分是自己所写,部分是官网所提供的答案;
- 关于刷题,虽然数量很重要,但是重点在于刷题质量和解题方法的总结;
- 撰写笔记于此,每一题都有思路总结和注释引导,希望对你有所帮助。
目录
一、两数之和
思路总结:
- 分析题干:
从数组中找到两个元素A和B,A+B = target;- 返回值:
两个元素A和B的下标;- 解题:
有元素有下标,考虑map哈希表,根据 target-A 来寻找B,最终返回A和B的下标。具体步骤见代码中的注释。注意事项:
- 每一次循环都往哈希表中添加键值对,以保证不让A或者B和自己匹配。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target)
{
// 定义无序映射的哈希表
unordered_map<int, int> hashtable;
for (int i = 0; i < nums.size(); ++i) {
// 根据两数之差,找到并返回对应的哈希表的迭代(键值对)
auto iter = hashtable.find(target - nums[i]);
// 如果找不到满足 target-nums[i] 的值,返回哈希表的end
if (iter != hashtable.end()) { // 找到了
return {it->second, i};
}
// 往哈希表中添加键值对,以保证不让nums[i]不和自己匹配!
hashtable[nums[i]] = i;
}
return {}; // 返回结果
}
};
二、回文数
扫描二维码关注公众号,回复:
14779396 查看本文章
思路总结:
- 分析题干:
回文数,即两端对称的整数;- 返回值:
bool类型,ture或者false;- 解题:
首先分析整数的范围,负数全部返回false,末尾为零的整数(非0)也返回false。然后分析奇数和偶数,对于奇数,省略中间数的影响后,判别步骤同偶数。具体步骤见注释。注意事项:
- 反转整数的方法:取整运算( / )和取余运算( % )相互结合使用;
- while循环中的判断条件,刚好限制住 revertedNumber 取到 x 的半边。即x=112233时,循环过后,x=112,revertedNumber=332,非常巧妙。
class Solution {
public:
bool isPalindrome(int x) {
// 特殊情况:
// 1、当 x < 0 时,x 不是回文数。
// 2、非零整数,末尾为0时,不是回文数
if (x < 0 || (x % 10 == 0 && x != 0)) {
return false;
}
// 1、偶数:把x从中间分开,根据取余和取整运算,判断左侧的正序和右侧的逆序是否相等
// 2、奇数:可以省略中间数的影响,判别步骤同偶数
int revertedNumber = 0;
while (x > revertedNumber) { // 注意while的判断条件,巧妙
revertedNumber = revertedNumber * 10 + x % 10;
x /= 10;
}
// x == revertedNumber:当x为偶数时,直接判断即可
// x == revertedNumber/10:当x为奇数时,去除中间数后,进行判断即可
return x == revertedNumber || x == revertedNumber / 10;
}
};
三、罗马数字转整数
思路总结:
- 分析题干:
罗马数字转整数,有条件的整数加减运算罢了;- 返回值:
返回最终的整数;- 解题:
每一个罗马文字都对应一个数字,需要创建一个映射来存储键值对。不要被特殊条件所迷惑,判断相邻的罗马数字大小,前者小,相减;反之相加即可。具体步骤见注释。注意事项:
- 判断条件很重要。
class Solution {
private:
// 根据题干条件创建映射
unordered_map<char, int> symbolValues = {
{'I', 1},
{'V', 5},
{'X', 10},
{'L', 50},
{'C', 100},
{'D', 500},
{'M', 1000},
};
public:
int romanToInt(string s) {
int ans = 0;
int n = s.length();
for (int i = 0; i < n; ++i) {
// 利用无序映射,返回数值
int value = symbolValues[s[i]];
// 判断前后位的数值大小:若前者小,相减;反之相加
if (i < n - 1 && value < symbolValues[s[i + 1]]) { // 此处的判断条件是精华
ans -= value;
} else {
ans += value;
}
}
return ans;
}
};
四、最长公共前缀
思路总结:
- 分析题干:
找到数组中所有元素的最长公共前缀;- 返回值:
返回string(最长公共前缀);- 解题:
首先需要判断数组中的最短字符串,以最短字符串的长度min_len作为限制条件,去遍历所有元素的前min_len个字符是否相等。部分情况需要直接返回,具体见注释。注意事项:
- C++中添加元素到字符串中的方法:string res; res += 'c'; ;
- 定义方式:字符串 "Faying Bulldo",字符 'g'。
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
int n_strs = strs.size(); // 字符串数组的长度
int min_len = 0; // 字符串最小长度
for (int i = 0; i < n_strs - 1; i++) {
int len_str = strs[i].length();
int len_str_latter = strs[i + 1].length();
// 冒泡比较得出最小的字符串长度
if (len_str_latter > len_str) {
min_len = len_str;
}
else {
min_len = len_str_latter;
}
}
// 两种情况:
// 1、字符串数组中只有一个元素
// 2、字符串数组中有多个元素,并且其中有一个位空字符
if (min_len == 0 && n_strs == 1) {
return strs[0];
}
else if (min_len == 0 && n_strs > 1) {
return "";
}
// 最多的一种情况:字符串中有多个数组,并且没有空字符
string temp1;
string temp2;
bool flag = true; // 存储正确结果的标志
string res; // 存储每一轮判断的正确结果
for (int j = 0; j < min_len; j++) {
// 更快一些:把temp1从内循环中拿出,每一次循环只需要把第一个字符串的一个字符作为标准即可
temp1 = strs[0][j];
for (int i = 0; i < n_strs - 1; i++) {
temp2 = strs[i + 1][j];
// 比较每相邻两个元素的相同位置的字符是否相等
if (temp1 != temp2) {
flag = false;
break;
}
}
if (flag == true) {
res += temp1; // 如果相等,融合字符
}
}
// 根据结果字符串的长度来return
if (res.length() <= 0) {
return "";
}
else {
return res;
}
}
};
五、有效的括号
思路总结:
- 分析题干:
左括号和右括号的匹配问题,特殊例子:( [ ] ) { }、{ [ ( ) ] } 正确,( [ ) ] ( ) 错误;- 返回值:
返回bool值,全部匹配成功,返回ture,反之返回false;- 解题:
利用 "栈" 的特点匹配括号,遍历字符串,只把左括号压入栈中,然后判断是否有右括号和栈顶的左括号匹配,匹配成功后,不要忘记把左括号从栈中抛出。具体步骤键注释。注意事项:
- 栈的特点:先进后出,即最后压入栈中的元素在栈顶,从栈顶开始抛出元素;
- 关于栈的基本语句需要牢记:
empty() 堆栈为空则返回真
pop() 移除栈顶元素
push() 增加元素到栈顶
size() 返回栈中元素数目
top() 返回栈顶元素
class Solution {
public:
bool isValid(string s) {
int n = s.size();
// 如果字符串长度为奇数,直接返回false
if (n % 2 == 1) {
return false;
}
// 根据题干条件创建映射
unordered_map<char, char> pairs = {
{')', '('}, // 注意:键为右括号,值为左括号
{']', '['},
{'}', '{'}
};
stack<char> stk; // 栈特点:先进后出
for (char ch: s) { // 遍历字符串s
// 限制条件:遍历所有右括号
if (pairs.count(ch)) { // 查找键ch,若存在,则返回1,反之返回0
// 栈为空 或者 栈顶的左括号匹配不到当前的右括号,返回false
if (stk.empty() || stk.top() != pairs[ch]) {
return false;
}
stk.pop(); // 匹配成功后,移除栈顶元素
}
// 添加左括号到栈中
else {
stk.push(ch); // 在栈顶增加元素
}
}
return stk.empty(); // 若所有的括号都匹配完毕,那么stk.empty()为true
}
};
>>> 如有疑问,欢迎评论区一起探讨。