目录
LeetCode 1. 两数之和
算法 1:暴力枚举
很水的暴力做法,时间复杂度,直接上代码吧(ーー゛)
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
for(int i = 0; i < nums.size() - 1; i ++) // 直接二重循环不解释
{
for(int j = i + 1; j < nums.size(); j ++)
if(nums[i] + nums[j] == target)
return {i, j};
}
return {};
}
};
算法 2:排序+双指针
推荐做法* 时间复杂度,上代码♪(^∇^*),具体步骤和思路见注释
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> cpy;
for(int i = 0; i < nums.size(); i ++) //作一备份,便于sort打乱顺序后的查找
cpy.push_back(nums[i]);
sort(nums.begin(), nums.end()); // 排序
int a1, a2; //代表答案的数字(不是下标)
bool flag = 0;
for(int i = 0, j = nums.size() - 1; i < j; ) // 定义头指针i,尾指针j
{
if(nums[i] + nums[j] == target)
{
a1 = nums[i], a2 = nums[j];
flag = 1;
break;
}
if(nums[i] + nums[j] > target) j --;
else if(nums[i] + nums[j] < target) i ++;
}
if(!flag) return {};
int r1, r2; //代表答案(下标)
for(int i = 0; i < cpy.size(); i ++) // 找到对应的下标
{
if(cpy[i] == a1)
{
r1 = i;
break;
}
}
for(int i = cpy.size() - 1; i >= 0; i --)
{
if(cpy[i] == a2)
{
r2 = i;
break;
}
}
return {r1, r2};
}
};
算法 3:哈希表
推荐做法* 时间复杂度
这里用到了哈希表unordered_map<T t, U u>,上代码︿( ̄︶ ̄)︿
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> heap; //建立一个哈希表
for(int i = 0; i < nums.size(); i ++)
{
int r = target - nums[i]; // 如果两个数中的一个数是nums[i],另一个就是target - nums[i],设为r
if(heap.count(r)) // 哈希表里查询到了r
return {heap[r], i}; // 返回答案
heap[nums[i]] = i; // 没找到就把当前元素放进哈希表
}
return {};
}
};
第一题完~~
LeetCode 2. 两数相加
算法 模拟(类似高精度运算)
模拟竖式即可,时间复杂度,上代码 (ーー゛)
/**
* 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* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode *head = new ListNode(-1); // 做有关链表的题目,有个常用技巧:添加一个虚拟头结点:ListNode *head = new ListNode(-1);,可以简化边界情况的判断
ListNode *cur = head;
int t = 0;
while(l1 || l2 || t)
{
if(l1) t += l1->val, l1 = l1->next;
if(l2) t += l2->val, l2 = l2->next;
cur->next = new ListNode(t % 10); // 将t的个位数插入新的虚拟链表(通过构造函数初始化)
cur = cur->next;
t /= 10;
}
return head->next; //跳过虚拟的头结点
}
};
第二题完~~
LeetCode 3. 无重复字符的最长子串
算法:典型双指针算法
可以用一个哈希表来维护字段,时间复杂度,上代码~
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int res = 0; // 最大值(即答案)
unordered_map<char, int> heap; // 定义哈希表维护两指针(如下)之间的字符串
for(int i = 0, j = 0; i < s.length(); i ++) // 双指针i, j分别为头指针,尾指针,每次仅移动头指针
{
heap[s[i]] ++; // 哈希表中放入指针i所指的字符
while(heap[s[i]] > 1) heap[s[j ++]] --; //指针j往后移动一格,哈希表中去掉指针j所指的字符
res = max(res, i - j + 1);
}
return res;
}
};
第三题完~~
LeetCode 4. 寻找两个正序数组的中位数
这题有些难度,这里放两个做法(第一个是水的( ̄ε(# ̄))
算法1:排序
ummm纯暴力做法,直接合并排序,时间复杂度,上代码
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
vector<int> merged;
int s1 = nums1.size(), s2 = nums2.size();
int s = s1 + s2;
for(int i = 0; i < s1; i ++)
merged.push_back(nums1[i]);
for(int i = 0; i < s2; i ++)
merged.push_back(nums2[i]);
sort(merged.begin(), merged.end());
if(s % 2) return merged[s / 2];
else return 1.0 * (merged[s / 2] + merged[s / 2 - 1]) / 2; //这里注意数据类型的转换
}
};
算法 2:递归
乍一看看不出递归算法可行o( ̄ヘ ̄o#),不妨先将原问题简化为:
在两个有序数组中,找出第k小的数
原问题即找出第小的数(暂时不分奇偶讨论)
若 ,从 nums1 和 nums2 中各取前 个元素:
如果 ,则说明 中取的元素过多, 中取的元素过少;因此 中的前 个元素一定都小于等于第 小的数,所以我们可以不考虑这些数,将问题简化为在剩下的数中找第 小的数。
如果 ,同理可说明 中的前 个元素一定都小于等于第 小数,
类似可将问题的规模减少一半。
再考虑边界情况,如果 ,则我们从 中取 个元素,从 中取 个元素(由于 ,因此 不可能同时小于 ):
如果 ,则 中的前 个元素一定都小于等于第 小的数,我们可以将问题归约成在剩下的数中找第 小数。
如果 ,则 中的所有元素一定都小于等于第 小数,
因此第 小的数是 。
对于每种情况,都能把原问题简化成几个子问题,当 为1或某数组为空时,可退出递归。符合递归的条件,代码如下:
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int s1 = nums1.size(), s2 = nums2.size();
int s = s1 + s2; // s为总长度
if(s % 2 == 0)
{
int left = find(nums1, 0, nums2, 0, s / 2); // find即为递归函数
int right = find(nums1, 0, nums2, 0, s / 2 + 1);
return (left + right) / 2.0;
}
else
return find(nums1, 0, nums2, 0, s / 2 + 1);
}
int find(vector<int> &nums1, int i, vector<int> &nums2, int j, int k) //i, j表示两数组从第i, j位开始计算, k表示找第k小的元素
{
if(nums1.size() - i > nums2.size() - j) return find(nums2, j, nums1, i, k); //确保第二个数组的长度大于第一个数组
if(nums1.size() == i) return nums2[j + k - 1]; //若第一个数组为空,直接从第二个数组里找
if(k == 1) return min(nums1[i], nums2[j]); // k是1,则返回两数组的头一个元素(无需讨论第一个数组是否为空,上面已经讨论过了)
int si = min((int)nums1.size(), i + k / 2), sj = j + k / 2; // 按照分类讨论的标准模拟
if(nums1[si - 1] > nums2[sj - 1])
return find(nums1, i, nums2, sj, k - k / 2); //si位置上的元素大,则nums2从sj处开始计算,nums1不变,递归寻找第 (k - k / 2) 个元素
else
return find(nums1, si, nums2, j, k - (si - i)); //同理,相反(写si - i 是为了避免讨论si 等于s1.size()的情况)
}
};
此做法时间复杂度为
第四题完~~
LeetCode 5. 最长回文子串
算法:暴力搜索
水题,直接上代码 ︿( ̄︶ ̄)︿
class Solution {
public:
string longestPalindrome(string s) {
string res;
for(int i = 0; i < s.length(); i ++)
{
int l = i - 1, r = i + 1; // 对应回文串长度为奇数情况
while(l >= 0 && r < s.length() && s[l] == s[r]) l --, r ++; // 根据回文串的特性,向两边扩展
if(res.length() < r - l - 1) res = s.substr(l + 1, r - l - 1); // 这里注意边界
l = i, r = i + 1; // 对应回文串长度为奇数情况
while(l >= 0 && r < s.length() && s[l] == s[r]) l --, r ++; // 同上
if(res.length() < r - l - 1) res = s.substr(l + 1, r - l - 1);
}
return res;
}
};
时间复杂度为,但实际无法达到
第五题完~~
更多题解在主页哦~~(๑•̀ㅂ•́)و✧
如果觉得不错,可以⭐Star 和 Fork (u‿ฺu✿ฺ)