LeetCode Hot 100

leetcode hot 100

####1. 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例:

输入:

nums = [2,7,11,15], target = 9

输出:

[0,1]

解释:因为nums[0] + nuts[1] == 9

思路:

方法一:暴力

方法二:用哈希表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int>mp;
vector<int>res(2,-1);
for(int i=0;i<nums.size();i++){
//判断是否有相加等于target的数
if(mp.count(target-nums[i])>0){
res[0]=mp[target-nums[i]];
res[1]=i;
break;
}
mp[nums[i]]=i;
}
return res;
}
};

2. 两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例:

输入:l1 = [2,4,3], l2 = [5,6,4]

输出:[7,0,8]

解释:342 + 465 = 807

思路:

模拟即可,需要注意进位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <iostream>
#include <vector>
using namespace std;

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* res = new ListNode();
//进位
int carry = 0;
//定义一个可移动指针
ListNode* cur = res;
//当l1或者l2不为空时
while(l1 != nullptr || l2 != nullptr){
//如果l1不等于null,就取它的值,等于就赋值0,保持两个链表具有相同的位数
int x = l1 != nullptr ? l1->val : 0;
//如果l2不等于null,就取它的值,等于就赋值0,保持两个链表具有相同的位数
int y = l2 != nullptr ? l2->val : 0;

//计算两个数的和,注意进位
int sum = x + y + carry;
//计算进位
carry = sum/10;
sum = sum % 10;

//将结果添加到新节点中
cur->next = new ListNode(sum);
cur = cur->next;

//后移l1,l2
if(l1!=nullptr){
l1 = l1->next;
}
if(l2!=nullptr){
l2 = l2->next;
}
}
//如果最后两个数相加有进位,赋予链表新节点
if(carry){
cur->next = new ListNode(carry);
}
//返回头节点
return res->next;
}
};

3. 无重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例:

输入:s="abcabcbb"

输出:3

输入:s = "bbbbb"

输出:1

输入:s = "pwwkew"

输出:3

思路:

标签:滑动窗口

暴力解法时间复杂度较高,会达到O(n^2),故而采取滑动窗口的方法降低时间复杂度

定义一个 map 数据结构存储 (k, v),其中 key 值为字符,value 值为字符位置 +1,加 1 表示从字符位置后一个才开始不重复

我们定义不重复子串的开始位置为 start,结束位置为 end

随着 end 不断遍历向后,会遇到与 [start, end] 区间内字符相同的情况,此时将字符作为 key 值,获取其 value 值,并更新 start,此时 [start, end] 区间内不存在重复字符

无论是否更新 start,都会更新其 map 数据结构和结果 ans = end - start + 1。

时间复杂度:O(n)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int n = s.size(),ans=0;
//mp用于记录下一个数字从哪开始
map<char,int> mp;
for(int start=0,end=0;end<n;end++){
char tmp = s[end];
//已经出现过
if(mp.count(tmp)>0){
//移动start到新的窗口
start = max(mp[tmp],start);
}
ans = max(ans,end-start+1);
mp[tmp] = end+1;
}
return ans;
}
};

两数之和 II - 输入有序数组

给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。

以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。

你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

你所设计的解决方案必须只使用常量级的额外空间。

示例:

输入:numbers = [2,7,11,15], target = 9 输出:[1,2] 解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

思路:

采用双指针,l=0,r=numners.size()-1,sum = numbers[l]+numbers[r]

我们可以得出如果sum > target,那么我们可以排除这一列,因为往后和越大,我们只需要r--

如果sum<target,我们可以排除这一行,l++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int l=0,r=numbers.size()-1;
while(l<r){
int sum = numbers[l]+numbers[r];
//排除这一行
if(sum < target) l++;
//排除这一列
else if(sum > target) r--;
else return {l+1,r+1};
}
return {-1,-1};
}
};

####20. 有效的括号

给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。

示例:

输入:s = "()" 输出:true

思路:

方法一:使用哈希表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
public:
bool isValid(string s) {
int n = s.size();
if (n % 2 == 1) {
return false;
}

unordered_map<char, char> pairs = {
{')', '('},
{']', '['},
{'}', '{'}
};
stack<char> stk;
for (char ch: s) {
if (pairs.count(ch)) {
if (stk.empty() || stk.top() != pairs[ch]) {
return false;
}
stk.pop();
}
else {
stk.push(ch);
}
}
return stk.empty();
}
};

方法二:不使用哈希表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
bool isValid(string s) {
if(s.size() == 0) return true;
//奇数
if(s.size()&1) return false;
stack<char> st;
for(char c:s){
if(c == '(' || c=='[' || c=='{') st.push(c);
if(c == ')'){
if(!st.empty() && st.top()=='(') st.pop();
else return false;
}
if(c==']'){
if(!st.empty() && st.top()=='[') st.pop();
else return false;
}
if(c=='}'){
if(!st.empty() && st.top()=='{') st.pop();
else return false;
}
}
if(st.empty()) return true;
return false;
}
};

48. 旋转图像

给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

示例:

img

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]] 输出:[[7,4,1],[8,5,2],[9,6,3]]

思路:

顺时针旋转90度

算法流程:

1,先对角线反转

2,再中间对称反转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
void rotate(vector<vector<int> >& matrix) {
int n = matrix.size();
//先沿对角线镜像对称二维矩阵
for(int i = 0; i < n; i++){
for(int j = i; j < n; j++){
swap(matrix[i][j],matrix[j][i]);
}
}
//然后中间对称反转
for(int i = 0; i < n; i++){
reverse(matrix[i]);
}
}
void reverse(vector<int>& row){
int i = 0, j = row.size() - 1;

while(j > i){
swap(row[i++],row[j--]);
}
}
};

54. 螺旋矩阵

给你一个 mn 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

示例:

spiral1

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]] 输出:[1,2,3,6,9,8,7,4,5]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class Solution {
public:
vector<int> spiralOrder(vector<vector<int> >& matrix) {
//初始化
vector<int> res;
int m = matrix.size(),n = matrix[0].size();
if(m == 0 || n == 0) return {};
//定义边界
int upper_bound = 0;
int lower_bound = m - 1;
int left_bound = 0;
int right_bound = n - 1;

while(res.size() <= m*n ){
//从左往右,行不变,列增大
for(int i = left_bound; i <= right_bound; i++){
res.push_back(matrix[upper_bound][i]);
}
//上边界下移
upper_bound++;
if(upper_bound > lower_bound) break;

//从上往下,列不变,行增大
for(int j = upper_bound; j <= lower_bound; j++){
res.push_back(matrix[j][right_bound]);
}
//右边界左移
right_bound--;
if(right_bound < left_bound) break;

//从右往左,行不变,列减小
for(int i = right_bound; i >= left_bound; i--){
res.push_back(matrix[lower_bound][i]);
}
//下边界上移
lower_bound--;
if(lower_bound < upper_bound) break;

//从上往下,列不变,行减小
for(int j = lower_bound; j >= upper_bound; j--){
res.push_back(matrix[j][left_bound]);
}
//左边界右移
left_bound++;
if(left_bound > right_bound) break;
}
return res;
}
};

59. 螺旋矩阵 II

给你一个正整数 n ,生成一个包含 1n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

示例:

spiraln

输入:n = 3 输出:[[1,2,3],[8,9,4],[7,6,5]]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class Solution {
public:
vector<vector<int> > generateMatrix(int n) {
//初始化
vector<vector<int> > res(n,vector<int>(n));
int upper_bound = 0;
int lower_bound = n - 1;
int left_bound = 0;
int right_bound = n - 1;
int num = 1;
while(num <= n * n ){
//从左往右,行不变,列增大
for(int i = left_bound; i <= right_bound; i++){
res[upper_bound][i] = num++;
}
//上边界下移
upper_bound++;
if(upper_bound > lower_bound) break;

//从上往下,列不变,行增大
for(int j = upper_bound; j <= lower_bound; j++){
res[j][right_bound] = num++;
}
//右边界左移
right_bound--;
if(right_bound < left_bound) break;

//从右往左,行不变,列减小
for(int i = right_bound; i >= left_bound; i--){
res[lower_bound][i] = num++;
}
//下边界上移
lower_bound--;
if(lower_bound < upper_bound) break;

//从上往下,列不变,行减小
for(int j = lower_bound; j >= upper_bound; j--){
res[j][left_bound] = num++;
}
//左边界右移
left_bound++;
if(left_bound > right_bound) break;
}
return res;
}
};