LeetCode 11. 盛最多水的容器
双指针算法。
if(a[i] > a[j]) j --
else i ++
这一步为本题的核心,接着迭代更新最大值即可
class Solution {
public:
int maxArea(vector<int>& height) {
int res = 0;
for(int i = 0, j = height.size() - 1; i < j;) {
res = max(res, min(height[i], height[j]) * (j - i));
if(height[i] > height[j]) j -- ;
else i ++ ;
}
return res;
}
};
LeetCode 12. 整数转罗马数字
- 小的数字在大的数字的右边,所表示的数等于这些数字相加得到的数,如:VIII=8, XII=12
- 小的数字在大的数字的左边(限于 IV、IX、XL、XC、CD和CM),所表示的数等于大数减小数得到的数,如:IV=4, IX=9
- 相同的数字连写,所表示的数等于这些数字相加得到的数,如:III=3
- 正常使用时,连写的数字重复不得超过三次
根据以上几点规律,可以将罗马数字整理出下面的表格
M | CM | D | CD | C | XC | L | XL | X | IX | V | IV | I |
---|---|---|---|---|---|---|---|---|---|---|---|---|
1000 | 900 | 500 | 400 | 100 | 90 | 50 | 40 | 10 | 9 | 5 | 4 | 1 |
可以根据罗马数字的规律,优先使用数值较大的单位将整数转换成罗马数字
class Solution {
public:
string intToRoman(int num) {
int values[] = {
1000,
900, 500, 400, 100,
90, 50, 40, 10,
9, 5, 4, 1
};
string reps[] = {
"M",
"CM", "D", "CD", "C",
"XC", "L", "XL", "X",
"IX", "V", "IV", "I"
};
string res;
for(int i = 0; i <= 12; i ++ ) {
while(num >= values[i]) {
num -= values[i];
res += reps[i];
}
}
return res;
}
};
LeetCode 13. 罗马数字转整数
思路类比LeetCode 12. 整数转罗马数字,使用一张哈希表记录各个罗马数字对应的数值
线性扫描字符串,如果发现 s[i + 1]
的数值比s[i]
的数值大,则累加s[i + 1] - s[i]
这个差值,否则累加 s[i]
即可
class Solution {
public:
int romanToInt(string s) {
unordered_map<char, int> values;
values['I'] = 1;
values['V'] = 5;
values['X'] = 10;
values['L'] = 50;
values['C'] = 100;
values['D'] = 500;
values['M'] = 1000;
int res = 0;
for(int i = 0; i < s.size(); i ++ ) {
if(i + 1 < s.size() && values[s[i]] < values[s[i + 1]])
res -= values[s[i]];
else
res += values[s[i]];
}
return res;
}
};
LeetCode 14. 最长公共前缀
暴力枚举
可以从字符串数组里面找到最短的那个字符串,并记录长度为m
将答案从这个最短字符串的第一位开始枚举到第m位判断其他字符串是否有这样的前缀即可
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
string res;
if(strs.size() == 0) return res;
for(int i = 0; ; i ++ ) {
if(i >= strs[0].size()) return res;
char c = strs[0][i];
for(auto& str : strs)
if(str.size() <= i || str[i] != c)
return res;
res += c;
}
return res;
}
};
LeetCode 15. 三数之和
排序 + 双指针
- 枚举每个数,表示该数的
nums[i]
已确定, 通过双指针l = i + 1
和r = n - 1
往中间靠拢,直到找到nums[i] + nums[l] + nums[r] == 0
所有符合条件的搭配 - 在找符合条件搭配的过程中,假设
sum = nums[i] + nums[l] + nums[r]
若sum > 0
,则r往左走,使sum变小
若sum < 0
,则l往右走,使sum变大
若sum == 0
,则表示找到了与nums[i]
搭配的组合nums[l]
和nums[r]
,存到res中 - 判重处理
确定好nums[i]
时,l 需要从i + 1开始
当nums[i] == nums[i - 1]
,表示当前确定好的数与上一个一样,需要直接continue
当找符合条件搭配时,即sum == 0
,需要对相同的nums[l]和nums[r]进行判重出来
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(), nums.end());
for(int i = 0; i < nums.size(); i ++ ) {
if(i && nums[i] == nums[i - 1]) continue;
for(int j = i + 1, k = nums.size() - 1; j < k; j ++ ) {
if(j > i + 1 && nums[j] == nums[j - 1]) continue;
while(j < k - 1 && nums[i] + nums[j] + nums[k - 1] >= 0) k -- ;
if(nums[i] = nums[j] + nums[k] == 0) {
res.push_back({nums[i], nums[j], nums[k]});
}
}
}
return res;
}
};
LeetCode 16. 最接近的三数之和
排序 + 双指针
- 枚举每个数,表示该数的
nums[i]
已确定, 通过双指针l = i + 1
和r = n - 1
往中间靠拢,直到找到nums[i] + nums[l] + nums[r] == sum
所有情况中最接近target的sum,更新res - 在找符合条件搭配的过程中,假设
sum = nums[i] + nums[l] + nums[r]
若sum > target
,则r往左走,使sum变小
若sum < target
,则l往右走,使sum变大
若sum == target
,则表示找到了与nums[i]
搭配的组合nums[l]
和nums[r]
,直接返回 - 判重处理
确定好nums[i]
时,l 需要从i + 1开始
当nums[i] == nums[i - 1]
,表示当前确定好的数与上一个一样,需要直接continue
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
pair<int, int> res(INT_MAX, INT_MAX);
for(int i = 0; i < nums.size(); i ++ )
for(int j = i + 1, k = nums.size() - 1; j < k; j ++ ) {
while(k - 1 > j && nums[i] + nums[j] + nums[k - 1] >= target) k -- ;
int s = nums[i] + nums[j] + nums[k];
res = min(res, make_pair(abs(s - target), s));
if(k - 1 > j) {
s = nums[i] + nums[j] + nums[k - 1];
res = min(res, make_pair(target - s, s));
}
}
return res.second;
}
};
LeetCode 17. 电话号码的字母组合
- 先把数字和字符存进两个数组中相互映射
- 通过深度优先搜索进行遍历
- 当达到对应长度时将当前字符串存进数组中
class Solution {
public:
vector<string> ans;
string strs[10] = {
"", "", "abc", "def",
"ghi", "jkl", "mno",
"pqrs", "tuv", "wxyz",
};
vector<string> letterCombinations(string digits) {
if(digits.empty()) return ans;
dfs(digits, 0, "");
return ans;
}
void dfs(string &digits, int u, string path) {
if(u == digits.size()) ans.push_back(path);
else
{
for(auto c : strs[digits[u] - '0'])
dfs(digits, u + 1, path + c);
}
}
};
LeetCode 18. 四数之和
排序 + 双指针
1、与三数之和操作类似,枚举每两个数,表示该数nums[i]
和nums[j]
已被确定,在排序后的情况下,通过双指针l,r分别从左边l = i + 1和右边n - 1往中间靠拢,找到nums[i] + nums[j] + nums[l] + nums[r] == target
的所有符合条件的搭配
2、在找符合条件搭配的过程中,假设sum = nums[i] + nums[j] + nums[l] + nums[r]
若sum > target
,则r往左走,使sum变小
若sum < target
,则l往右走,使sum变大
若sum == target
,则表示找到了与nums[i]搭配的组合nums[l]和nums[r],存到ans中
3、判重处理
确定好nums[i]时,l 需要从i + 1开始
当nums[i] == nums[i - 1]
,表示当前确定好的数与上一个一样,需要直接continue
当nums[j] == nums[j - 1]
,表示当前确定好的数与上一个一样,需要直接continue
当找符合条件搭配时,即sum == 0,需要对相同的nums[l]和nums[r]进行判重出来
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
vector<vector<int>> res;
for (int i = 0; i < nums.size(); i ++ ) {
if (i && nums[i] == nums[i - 1]) continue;
for (int j = i + 1; j < nums.size(); j ++ ) {
if (j > i + 1 && nums[j] == nums[j - 1]) continue;
for (int k = j + 1, u = nums.size() - 1; k < u; k ++ ) {
if (k > j + 1 && nums[k] == nums[k - 1]) continue;
while (u - 1 > k && nums[i] + nums[j] + nums[k] + nums[u - 1] >= target) u -- ;
if (nums[i] + nums[j] - target == -nums[k] - nums[u]) {
res.push_back({nums[i], nums[j], nums[k], nums[u]});
}
}
}
}
return res;
}
};
LeetCode 19. 删除链表的倒数第N个节点
先遍历一遍链表记录链表总长度,在第二次遍历的时候将倒数第N个节点删除
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int k) {
auto dummy = new ListNode(-1);
dummy -> next = head;
int n = 0;
for(auto p = dummy; p; p = p -> next) n ++ ;
auto p = dummy;
for(int i = 0; i < n - k - 1; i ++ ) p = p -> next;
p -> next = p -> next -> next;
return dummy -> next;
}
};
LeetCode 20. 有效的括号
栈的简单应用
class Solution {
public:
bool isValid(string s) {
stack<char> stk;
for (auto c : s) {
if (c == '(' || c == '[' || c == '{') stk.push(c);
else {
if (stk.size() && abs(stk.top() - c) <= 2) stk.pop();
else return false;
}
}
return stk.empty();
}
};
class Solution {
public:
bool isValid(string s) {
int len = s.length();
if(len % 2) return false;
stack<int> st;
for(int i = 0; i < len; i ++ )
{
if(s[i] == '(' || s[i] == '[' || s[i] == '{')
st.push(s[i]);
else if(!st.empty())
{
if(s[i] == ')' && st.top() == '(')
st.pop();
else if(s[i] == ']' && st.top() == '[')
st.pop();
else if(s[i] == '}' && st.top() == '{')
st.pop();
else return false;
}else return false;
}
if(st.empty()) return true;
return false;
}
};