LeetCode Top 100 题解
1.三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
判断nums中三元素之和为0,除过三者都为0的情况之外,还包括正负数,所以先先选定一个数,然后再去找另外两个数,这两数之和为选定的数的相反数即可,所以将数组排序,然后用双指针以线性时间复杂度来进行遍历结果。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int> > res;
if (nums.size() < 3)
return res;
sort(nums.begin(), nums.end());
if((nums[0] == nums[nums.size() - 1]) && nums[0] == 0)
{
res.push_back({0, 0, 0});
return res;
}
const int target = 0;//目标值
auto last = nums.end();
for (auto a = nums.begin(); a < prev(last, 2); ++a)//遍历到倒数第三个即可
{
auto b = next(a);
auto c = prev(last);
while (b < c)
{
if (*a + *b + *c < target)
{
++b;//趋向于大数
}
else if (*a + *b + *c > target)
{
--c;//趋向于小数
}
else
{
res.push_back({*a, *b, *c});
++b;
--c;
}
}
}
sort(res.begin(), res.end());
res.erase(unique(res.begin(), res.end()), res.end());//去重
return res;
}
};
还可以进行剪枝优化,即当遍历到正数的时候就break,因为若选定的第一个数是正数,对于已经排好序的数组来说,之后的数字都是正数,其和不为0;在处理重复的问题中,从第二个数开始,如果和前面的数字相等就跳过。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(),nums.end());
if (nums.empty() || nums.back() < 0 || nums.front() > 0)
return {};
for (int k = 0; k < (int)nums.size() - 2; ++k)
{
if (nums[k] > 0)//剪枝
break;
if (k > 0 && nums[k] == nums[k - 1])//去重
continue;
int targrt = 0 - nums[k], i = k + 1, j = (int)nums.size() - 1;
while (i < j)
{
if (nums[i] + nums[j] == targrt)
{
res.push_back({ nums[k],nums[i],nums[j]});
while (i < j && nums[i] == nums[i + 1])//去重
++i;
while (i < j && nums[j] == nums[j - 1])//去重
--j;
++i;
--j;
}
else if (nums[i] + nums[j] < targrt)
{
++i;
}
else
--j;
}
}
return res;
}
};
- 来源:力扣(LeetCode) 链接:三数之和
2.电话号码的字母组合
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例:
输入:“23”
输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
利用递归Recursion来解此题,建立字典keyLetters,保存每个数字代表的字符串,利用index变量来记录当前生成的字符串的字符数,若index等于digits的长度,就将其加入strs中,然后返回。通过digits中的数组访问字符串,遍历取出字符加入当前的组合中即可。
string keysLetters[10] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
class Solution {
public:
void ConLetters(const string& digits, size_t index, const string& str, vector<string>& strs)
{
if(index == digits.size())
{
strs.push_back(str);
return;
}
//获取数字的字母串
string letters = keysLetters[digits[index] - '0'];
for(size_t i = 0; i < letters.size(); i++)
{
ConLetters(digits, index + 1, str + letters[i], strs);
}
}
vector<string> letterCombinations(string digits) {
vector<string> strs;
if(digits.empty())
{
return strs;
}
size_t index = 0;
string str;
ConLetters(digits, index, str, strs);
return strs;
}
};
利用迭代Iterative也可以解此题,遍历digit中所有数字时,建立临时字符串数组tmp,通过数字找到keyLetters中的字符串,然后遍历取出字符串中的所有字符,再遍历当前结果res中的每一个字符串,将字符加到其后,保存到临时字符串数组中,取出的字符串letters遍历结束后,将tmp赋值给res即可。
string keysLetters[10] = { "", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" };
class Solution {
public:
vector<string> letterCombinations(string digits) {
if (digits.empty())
{
return {};
}
vector<string> strs{""};
for (int i = 0; i < digits.size(); ++i)
{
vector<string> tmp;
string letters = keysLetters[digits[i] - '0'];
for (int j = 0; j < letters.size();++j)
{
for (string str : strs)
{
tmp.push_back(str + letters[j]);
}
}
strs = tmp;
}
return strs;
}
};
- 来源:力扣(LeetCode) 链接:电话号码的字母组合
3.删除链表的倒数第N个节点
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
限定n是有效的,所以n不会超过链表长度。使用两个指针pre和cur,先让cur向前走n步,若cur为空,则n为链表长度,则需要移除的为首结点,直接返回head->next,若不为空,则让pre和cur同时走,直到cur为最后一个元素,然后删除pre指向的结点的下一个结点即可。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
if (!head->next)
return NULL;
ListNode *pre = head, *cur = head;
for (int i = 0; i < n; ++i)
{
cur = cur->next;
}
if (!cur)
return head->next;
while (cur->next) {
cur = cur->next;
pre = pre->next;
}
pre->next = pre->next->next;
return head;
}
};
- 来源:力扣(LeetCode) 链接:删除链表的倒数第N个节点