1. 两数之和
简单
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]
两数之和
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int>hash_map;
for(int i=0;i<nums.size();i++)
{
auto it =hash_map.find(target-nums[i]);
if(it !=hash_map.end())
{
return {it->second,i};
}
hash_map[nums[i]]=i;
}
return{};
}
};
|
解法
使用unordered_map对数组进行遍历,查看另一半是否在unordered_map中,不在就加入,存在就返回
49. 字母异位词分组
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的所有字母得到的一个新单词。
示例 1:
输入: strs = [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”]
输出: [[“bat”],[“nat”,“tan”],[“ate”,“eat”,“tea”]]
示例 2:
输入: strs = [""]
输出: [[""]]
示例 3:
输入: strs = [“a”]
输出: [[“a”]]
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string, vector<string>> mp;
for(string& str:strs){
string key =str;
sort(key.begin(),key.end());
mp[key].emplace_back(str);
}
vector<vector<string>> ans;
for(auto it = mp.begin();it!=mp.end();++it){
ans.emplace_back(it->second);
}
return ans;
}
};
|
解法
接着使用unordered_map 前边是排序后的字符串,后边是为排序的字符串,然后打印出来
128. 最长连续序列
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
请你设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例 1:
输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
示例 2:
输入:nums = [0,3,7,2,5,8,4,6,0,1]
输出:9
示例 3:
输入:nums = [1,0,1,2]
输出:3
代码
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
|
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
unordered_set<int> set;
for(const int& num :nums){
set.insert(num);
}
int l=0;
for(const int &num:set){
if(!set.count(num-1)){
int temp=num;
int now =1;
while(set.count(temp+1)){
now+=1;
temp+=1;
}
l=max(l,now);
}
}
return l;
}
};
|
解法
先使用unordered_set去重,然后遍历set,只有处于第一位(n-1不存在)进入队列长度的计量。时间复杂度是O(n)
283. 移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
示例 2:
输入: nums = [0]
输出: [0]
代码
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 moveZeroes(vector<int>& nums) {
int a=0,b=0;
for(int i=0;i<nums.size();i++)
{
if(nums[b]!=0)
{
nums[a]=nums[b];
a++;
b++;
}
else
{
b++;
}
}
for(;a < nums.size();a++)
{
nums[a]=0;
}
}
};
|
解法
双指针,一前一后,同时记录0的数量在最后给他补上(代码里好像没b什么事)
11. 盛最多水的容器
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
示例 1:
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例 2:
输入:height = [1,1]
输出:1
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
class Solution {
public:
int maxArea(vector<int>& height) {
int l =0,r=height.size()-1;
int ans=0;
while(l<r){
int area=min(height[l],height[r])*(r-l);
ans=max(ans,area);
if(height[l]<=height[r]){
l++;
}
else{
r--;
}
}
return ans;
}
};
|
解法
使用双指针,从两边接近中间,偏小的一边前进,同时记录之间最大的面积
证明:因为高板前进必然会导致结果的减小,使用只能前进短板,同时排除一部分结果
x
x x
x x o
x o o x
x o x x x
o o x x x x
160. 相交链表
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
图示两个链表在节点 c1 开始相交:
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at ‘8’
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,6,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
— 请注意相交节点的值不为 1,因为在链表 A 和链表 B 之中值为 1 的节点 (A 中第二个节点和 B 中第三个节点) 是不同的节点。换句话说,它们在内存中指向两个不同的位置,而链表 A 和链表 B 中值为 8 的节点 (A 中第三个节点,B 中第四个节点) 在内存中指向相同的位置。
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB)
{
if(headA==nullptr||headB==nullptr)
{
return nullptr;
}
ListNode *pa=headA, *pb=headB;
while(pa!=pb)
{
pa = pa == nullptr ? headB : pa->next;
pb = pb == nullptr ? headA : pb->next;
}
return pa;
};
};
|
解法
使用两个指针,分别类似倒8字遍历两条链,直到相交或者都为空(无相交)
证明:a+c+b==b+c+a
206. 反转链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2]
输出:[2,1]
示例 3:
输入:head = []
输出:[]
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* nex=head;
ListNode* now=nullptr;
ListNode* temp;
while(nex!=nullptr)
{
temp=nex->next;
nex->next=now;
now=nex;
nex=temp;
}
return now;
}
};
|
解法
使用三个指针,两个负责反向,一个负责指向下一个位置
234. 回文链表
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
示例 1:
输入:head = [1,2,2,1]
输出:true
示例 2:
输入:head = [1,2]
输出:false
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
class Solution {
public:
bool isPalindrome(ListNode* head) {
int x[50110];
int num=0;
while(head!=null)
{
x[num]=head->val;
head=head->next;
num++;
}
for(int i=0,j=num-1;i<j;i++,j--)
{
if(x[i]!=x[j])
{
return false;
}
}
return true;
}
};
|
解法
用数组将链表读取,然后双指针一左一右对进判断,时间复杂度O(n)
141. 环形链表
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class Solution {
public:
bool hasCycle(ListNode *head) {
unordered_set<ListNode*> hash;
while(head!=nullptr)
{
if(hash.count(head))
{
return true;
}
hash.insert(head);
head=head->next;
}
return false;
}
};
|
解法
使用unordered_set,对每个加入的节点搜索,看看有没有一样的(使用数组一样的,只是时间复杂度会高
21. 合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = []
输出:[]
示例 3:
输入:l1 = [], l2 = [0]
输出:[0]
代码
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
55
56
57
58
59
60
61
|
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
struct ListNode* head;
struct ListNode* p;
if(list1==NULL&&list2==NULL)
{
return NULL;
}
if(list1!=NULL&&list2==NULL)
{
return list1;
}
if(list2!=NULL&&list1==NULL)
{
return list2;
}
if(list1->val>=list2->val)
{
head=list2;
p=list2;
list2=list2->next;
}
else
{
head=list1;
p=list1;
list1=list1->next;
}
while((list1!=NULL)||(list2!=NULL))
{
if(list1==NULL&&list2!=NULL)
{
p->next=list2;
list2=list2->next;
p=p->next;
break;
}
if(list2==NULL&&list1!=NULL)
{
p->next=list1;
list1=list1->next;
p=p->next;
break;
}
if(list1->val>=list2->val)
{
p->next=list2;
list2=list2->next;
p=p->next;
}
else
{
p->next=list1;
list1=list1->next;
p=p->next;
}
}
return head;
}
|
解法
极度丑陋的代码,主要部分是维护三个指针,两个分别指着a,b,一个指着目标。但是需要考虑空,就需要超级多的if,else语句
94. 二叉树的中序遍历
给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。
示例 1:
输入:root = [1,null,2,3]
输出:[1,3,2]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [1]
输出:[1]
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class Solution {
public:
void inorder(TreeNode* root, vector<int>& res)
{
if (root==nullptr) {
return;
}
inorder(root->left,res);
res.push_back(root->val);
inorder(root->right,res);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
inorder(root,res);
return res;
}
};
|
解法
传入一个栈,用res.push_back(root->val);压入
104. 二叉树的最大深度
给定一个二叉树 root ,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:3
示例 2:
输入:root = [1,null,2]
输出: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:
int deep (TreeNode* root,int d)
{
if(root==nullptr)
{
return d;
}
int l=deep(root->left,d+1);
int r=deep(root->right,d+1);
if(l>=r)
{
return l;
}
else{
return r;
}
}
int maxDepth(TreeNode* root) {
int i=deep(root,0);
return i;
}
};
|
解法
二叉树大部分用的都是递归,取左+取右,比较
226. 翻转二叉树
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
示例 1:
输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]
示例 2:
输入:root = [2,1,3]
输出:[2,3,1]
示例 3:
输入:root = []
输出:[]
代码
1
2
3
4
5
6
7
8
9
10
11
12
|
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if(root==nullptr) return nullptr;
TreeNode *temp=root->left;
invertTree(root->left);
invertTree(root->right);
root->left=root->right;
root->right=temp;
return root;
}
};
|
解法
二叉树大部分用的都是递归,左子树先换,右子树再换,最后在根节点换
101. 对称二叉树
给你一个二叉树的根节点 root , 检查它是否轴对称。
示例 1:
输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:
输入:root = [1,2,2,null,3,null,3]
输出:false
代码
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 fx(TreeNode* left,TreeNode* right){
if(left==nullptr&&right==nullptr){
return true;
}
if(left==nullptr&&right!=nullptr){
return false;
}
if(left!=nullptr&&right==nullptr){
return false;
}
if(left->val==right->val){
int a=fx(left->left,right->right);
int b=fx(left->right,right->left);
if(a==true&&b==true){
return true;
}
else{
return false;
}
}
return false;
}
bool isSymmetric(TreeNode* root) {
return fx(root->left,root->right);
}
};
|
解法
二叉树大部分用的都是递归,传入左右两个节点,对称的来比较