LeetCode 热题 HOT 100
Posted 行码阁119
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 热题 HOT 100相关的知识,希望对你有一定的参考价值。
申明:以下所有内容均来自力扣
此博客就是总结了部分作者觉得好的题,难得题,需要品味的题,也是需要背诵的题。
此题没有明确说明,就是作者自己写的代码。
大家看了题没思路的话,自己点开,看题解。
本博客主要是方便复习和查看
第三天
3.1 寻找两个正序数组的中位数
4. 寻找两个正序数组的中位数https://leetcode-cn.com/problems/median-of-two-sorted-arrays/
给定两个大小分别为 m和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
示例 1:
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
利用两个数组逐渐递增的性质,l指向nums1, l2指向nums2,判断两者的大小,一次写入数组record,当找到中间元素,跳出 。
class Solution
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2)
vector<int> record(nums1.size() + nums2.size(), 0);
int n = nums1.size();
int m = nums2.size();
int t = (n + m) / 2;
int t1 = (n + m) % 2;
int l = 0;
int r = 0;
int j = 0;
while(l + r <= t)
if(l < n && r < m && nums1[l] >= nums2[r])
record[j++] = nums2[r];
r++;
else if(l < n && r < m && nums1[l] < nums2[r])
record[j++] = nums1[l];
l++;
else if(l >= n && r < m )
record[j++] = nums2[r];
r++;
else if(l < n && r >= m )
record[j++] = nums1[l];
l++;
else break;
if(t1 == 1)
return record[l + r - 1];
return double(record[r + l - 2] + record[r + l - 1]) / 2 ;
;
class Solution
public:
int getKthElement(const vector<int>& nums1, const vector<int>& nums2, int k)
/* 主要思路:要找到第 k (k>1) 小的元素,那么就取 pivot1 = nums1[k/2-1] 和 pivot2 = nums2[k/2-1] 进行比较
* 这里的 "/" 表示整除
* nums1 中小于等于 pivot1 的元素有 nums1[0 .. k/2-2] 共计 k/2-1 个
* nums2 中小于等于 pivot2 的元素有 nums2[0 .. k/2-2] 共计 k/2-1 个
* 取 pivot = min(pivot1, pivot2),两个数组中小于等于 pivot 的元素共计不会超过 (k/2-1) + (k/2-1) <= k-2 个
* 这样 pivot 本身最大也只能是第 k-1 小的元素
* 如果 pivot = pivot1,那么 nums1[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums1 数组
* 如果 pivot = pivot2,那么 nums2[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums2 数组
* 由于我们 "删除" 了一些元素(这些元素都比第 k 小的元素要小),因此需要修改 k 的值,减去删除的数的个数
*/
int m = nums1.size();
int n = nums2.size();
int index1 = 0, index2 = 0;
while (true)
// 边界情况
if (index1 == m)
return nums2[index2 + k - 1];
if (index2 == n)
return nums1[index1 + k - 1];
if (k == 1)
return min(nums1[index1], nums2[index2]);
// 正常情况
int newIndex1 = min(index1 + k / 2 - 1, m - 1);
int newIndex2 = min(index2 + k / 2 - 1, n - 1);
int pivot1 = nums1[newIndex1];
int pivot2 = nums2[newIndex2];
if (pivot1 <= pivot2)
k -= newIndex1 - index1 + 1;
index1 = newIndex1 + 1;
else
k -= newIndex2 - index2 + 1;
index2 = newIndex2 + 1;
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2)
int totalLength = nums1.size() + nums2.size();
if (totalLength % 2 == 1)
return getKthElement(nums1, nums2, (totalLength + 1) / 2);
else
return (getKthElement(nums1, nums2, totalLength / 2) + getKthElement(nums1, nums2, totalLength / 2 + 1)) / 2.0;
;
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/xun-zhao-liang-ge-you-xu-shu-zu-de-zhong-wei-s-114/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
3.2 正则化表达
10. 正则表达式匹配https://leetcode-cn.com/problems/regular-expression-matching/
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。
'.' 匹配任意单个字符
'*' 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
难 题没读懂
示例 1:
输入:s = "aa", p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。
示例 2:
输入:s = "aa", p = "a*"
输出:true
解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。
示例 3:
输入:s = "ab", p = ".*"
输出:true
解释:".*" 表示可匹配零个或多个('*')任意字符('.')。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/regular-expression-matching
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
这里是官方代码,解释请去官方
class Solution
public:
bool isMatch(string s, string p)
int m = s.size();
int n = p.size();
auto matches = [&](int i, int j)
if (i == 0)
return false;
if (p[j - 1] == '.')
return true;
return s[i - 1] == p[j - 1];
;
vector<vector<int>> f(m + 1, vector<int>(n + 1));
f[0][0] = true;
for (int i = 0; i <= m; ++i)
for (int j = 1; j <= n; ++j)
if (p[j - 1] == '*')
f[i][j] |= f[i][j - 2];
if (matches(i, j - 1))
f[i][j] |= f[i - 1][j];
else
if (matches(i, j))
f[i][j] |= f[i - 1][j - 1];
return f[m][n];
;
3.3 合并K个升序链表
23. 合并K个升序链表https://leetcode-cn.com/problems/merge-k-sorted-lists/
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 1:
输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
示例 2:
输入:lists = []
输出:[]
示例 3:
输入:lists = [[]]
输出:[]
class Solution
public:
class mycompare
public:
bool operator()(const ListNode* A, const ListNode *B)
return A->val > B->val;
;
ListNode* mergeKLists(vector<ListNode*>& lists)
//创建一个小顶堆
priority_queue<ListNode*, vector<ListNode*>, mycompare> que;
//将数据压入优先队列中
for(int i = 0; i < lists.size(); i++)
auto t = lists[i];
while(t != NULL)
que.push(t);
t = t->next;
//申明一个虚拟头结点
//这里一定要注意链表的结尾要赋予空
ListNode* head = new ListNode(0);
ListNode* cur = head;
while(!que.empty())
cur->next = que.top();
cur = cur->next;
cur->next = NULL;
que.pop();
return head->next;
;
3.4 最小栈
155. 最小栈https://leetcode-cn.com/problems/min-stack/
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
实现 MinStack 类:
MinStack() 初始化堆栈对象。
void push(int val) 将元素val推入堆栈。
void pop() 删除堆栈顶部的元素。
int top() 获取堆栈顶部的元素。
int getMin() 获取堆栈中的最小元素。
输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]
输出:
[null,null,null,null,-3,null,0,-2]
解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
class MinStack
public:
stack<int> q;
stack<int> p;
MinStack()
p.push(INT_MAX);
void push(int val)
q.push(val);
if(val < p.top())
p.push(val);
else
p.push(p.top());
void pop()
q.pop();
p.pop();
int top()
return q.top();
int getMin()
return p.top();
;
class MinStack
public:
stack<int> q;
stack<int> p;
MinStack()
p.push(INT_MAX);
void push(int val)
q.push(val);
if(val <= p.top())
p.push(val);
void pop()
int t = q.top();
if(t == p.top())
p.pop();
q.pop();
int top()
return q.top();
int getMin()
return p.top();
;
3.5 回文链表
234. 回文链表https://leetcode-cn.com/problems/palindrome-linked-list/
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
示例 1:
输入:head = [1,2,2,1]
输出:true
示例 2:
输入:head = [1,2]
输出:false
进阶:你能否用 O(n)
时间复杂度和 O(1)
空间复杂度解决此题?
class Solution
public:
bool isPalindrome(ListNode* head)
int n = 0;
ListNode* cur = head;
while(cur)
n++;
cur = cur->next;
cur = head;
ListNode* hummy = new ListNode(0);
int temp = n / 2;
while(temp > 0)
cur = cur->next;
temp--;
ListNode* pre = NULL;
while(cur)
ListNode* t = cur->next;
cur->next = pre;
pre = cur;
cur = t;
cur = head;
ListNode* op = pre;
bool t = true;
while(cur && pre)
if(cur->val != pre->val)
t = false;
break;
cur = cur->next;
pre = pre->next;
return t;
;
3.6 找到所有数组中消失的数字
448. 找到所有数组中消失的数字https://leetcode-cn.com/problems/find-all-numbers-disappeared-in-an-array/
给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。
示例 1:
输入:nums = [4,3,2,7,8,2,3,1]
输出:[5,6]
示例 2:
输入:nums = [1,1]
输出:[2]
进阶:你能在不使用额外空间且时间复杂度为 O(n)
的情况下解决这个问题吗? 你可以假定返回的数组不算在额外空间内。
class Solution
public:
vector<int> findDisappearedNumbers(vector<int>& nums)
vector<int> result;
int n = nums.size();
for(int num : nums)
int x = (num - 1) % n;
nums[x] = nums[x] + n;
for(int i = 0; i < nums.size(); i++)
if(nums[i] <= n)
result.push_back(i + 1);
return result;
;
3.7 二叉树的直径
543. 二叉树的直径https://leetcode-cn.com/problems/diameter-of-binary-tree/
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
示例 :
给定二叉树
1
/ \\
2 3
/ \\
4 5
返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。
class Solution
public:
int ans = 0;
int recur(TreeNode* root)
if(root == NULL)
return 0;
int l = recur(root->left);
int r = recur(root->right);
ans = max(ans, l + r);
return max(l, r) + 1;
int diameterOfBinaryTree(TreeNode* root)
recur(root);
return ans;
;
3.8 下一个排列
31. 下一个排列https://leetcode-cn.com/problems/next-permutation/
整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。
整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。
例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。
给你一个整数数组 nums ,找出 nums 的下一个排列。
必须 原地 修改,只允许使用额外常数空间。
示例 1:
输入:nums = [1,2,3]
输出:[1,3,2]
示例 2:
输入:nums = [3,2,1]
输出:[1,2,3]
示例 3:
输入:nums = [1,1,5]
输出:[1,5,1]
难,参考官方代码
class Solution
public:
void nextPermutation(vector<int>& nums)
int i = nums.size() - 2;
while(i >=0 && nums[i] >= nums[i + 1])
i--;
if(i >= 0)
int j = nums.size() - 1;
for(; j > i; j--)
if(nums[j] > nums[i])
swap(nums[j], nums[i]);
break;
reverse(nums.begin() + i + 1, nums.end());
;
3.9 旋转图像
48. 旋转图像https://leetcode-cn.com/problems/rotate-image/
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
class Solution
public:
void rotate(vector<vector<int>>& matrix)
int n = matrix.size();
for(int i = 0; i < matrix.size() / 2; i++)
for(int j = 0; j < (matrix[0].size() + 1) / 2; j++)
int temp = matrix[i][j];
matrix[i][j] = matrix[n - j - 1][i];
matrix[n - j - 1][i] = matrix[n - i - 1][n - j - 1];
matrix[n - i - 1][n - j - 1] = matrix[j][n - i - 1];
matrix[j][n - i - 1] = temp;
;
class Solution
public:
void rotate(vector<vector<int>>& matrix)
vector<vector<int>> temp = matrix;
for(int i = 0; i < matrix.size() ; i++)
for(int j = 0; j < matrix[0].size(); j++)
matrix[i][j] = temp[matrix.size() - 1 - j][i];
3.10 字母异位词分组
49. 字母异位词分组https://leetcode-cn.com/problems/group-anagrams/
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母通常恰好只用一次。
示例 1:
输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]
示例 2:
输入: strs = [""]
输出: [[""]]
示例 3:
输入: strs = ["a"]
输出: [["a"]]
暴力解法 超时
class Solution
public:
bool comapreStr(string s1, string s2)
if(s1.size() != s2.size()) return false;
int a[26] = 0;
for(int i = 0; i < s1.size(); i++)
a[s1[i] - 'a']++;
for(int j = 0; j < s2.size(); j++)
if(a[s2[j] - 'a'] == 0) return false;
a[s2[j] - 'a']--;
for(int i = 0; i < 0; i++)
if(a[i] != 0) return false;
return true;
vector<vector<string>> groupAnagrams(vector<string>& strs)
vector<vector<string>> result;
vector<int> visited(strs.size(), 0);
for(int i = 0; i < strs.size(); i++)
if(visited[i] == 0)
visited[i] = 1;
vector<string> str;
str.push_back(strs[i]);
for(int j = 0; j < strs.size(); j++)
if(visited[j] == 0 && comapreStr(strs[i], strs[j]))
visited[j] = 1;
str.push_back(strs[j]);
if(str.size() >= 1)
result.push_back(str);
return result;
;
class Solution
public:
bool comapreStr(string s1, string s2)
if(s1.size() != s2.size()) return false;
int a[26] = 0;
for(int i = 0; i < s1.size(); i++)
a[s1[i] - 'a']++;
for(int j = 0; j < s2.size(); j++)
if(a[s2[j] - 'a'] == 0) return false;
a[s2[j] - 'a']--;
for(int i = 0; i < 0; i++)
if(a[i] != 0) return false;
return true;
vector<vector<string>> groupAnagrams(vector<string>& strs)
vector<vector<string>> result;
for(int i = 0; i < strs.size(); i++)
vector<string> str;
if(strs[i] != "0")
str.push_back(strs[i]);
for(int j = i + 1; j < strs.size(); j++)
if(strs[j] != "0" && comapreStr(strs[i], strs[j]))
str.push_back(strs[j]);
strs[j] = "0";
result.push_back(str);
return result;
;
官方代码 利用哈希表 对原数组进行排序,作为哈希表的键,排序的时间复杂度O(nlogn),遍历元素为n, 所以时间复杂度为O(n^2logn),上面的代码是O(n^3)
class Solution
public:
unordered_map<string, vector<string>> map;
void getGroupAnagrams(vector<string>& strs)
for(string str : strs)
string key = str;
sort(key.begin(), key.end());
map[key].push_back(str);
vector<vector<string>> groupAnagrams(vector<string>& strs)
vector<vector<string>> ans;
getGroupAnagrams(strs);
for(unordered_map<string, vector<string>>::iterator it = map.begin(); it != map.end(); it++)
ans.push_back(it->second);
return ans;
;
class Solution
public:
vector<vector<string>> groupAnagrams(vector<string>& strs)
unordered_map<string, vector<string>> mp;
for(int i = 0; i < strs.size(); i++)
string temp = strs[i];
sort(temp.begin(), temp.end());
mp[temp].push_back(strs[i]);
vector<vector<string>> result;
for(unordered_map<string, vector<string>>::iterator it = mp.begin(); it != mp.end(); it++)
result.push_back(it->second);
return result;
;
3.11 合并区间
56. 合并区间https://leetcode-cn.com/problems/merge-intervals/
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
区间题很容易弄混,大家都思考几遍
示例 1:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。
class Solution
public:
static bool cmp(vector<int>& a, vector<int>& b)
if(a[0] == b[0])
return a[1] < b[1];
return a[0] < b[0];
vector<vector<int>> merge(vector<vector<int>>& intervals)
vector<vector<int>> result;
sort(intervals.begin(), intervals.end(), cmp);
for(int i = 0; i < intervals.size(); i++)
int l = intervals[i][0];
int r = intervals[i][1];
while(i < (intervals.size() - 1) && intervals[i + 1][0] <= r )
r = max(r, intervals[i + 1][1]);
i++;
if(result.size() > 0 && result[result.size() - 1][1] >= l) result[result.size() - 1][1] = max(r, intervals[i][1]);
else result.push_back(l,max(r, intervals[i][1]));
return result;
;
3.12 颜色分类
75. 颜色分类https://leetcode-cn.com/problems/sort-colors/
给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
必须在不使用库的sort函数的情况下解决这个问题。
同样的思路写出来的代码不一样 哎 能力还是不行
class Solution
public:
void sortColors(vector<int>& nums)
int l = 0;
int r = nums.size() - 1;
while(l < r)
while(l <= r && nums[r] != 0)
r--;
while(l <= r && nums[l] == 0)
l++;
if(l < r)
swap(nums[l], nums[r]);
r = nums.size() - 1;
while(l < r)
while(l <= r && nums[r] != 1)
r--;
while(l <= r && nums[l] == 1)
l++;
if(l < r)
swap(nums[l], nums[r]);
;
官方代码:
class Solution
public:
void sortColors(vector<int>& nums)
int n = nums.size();
int ptr = 0;
for (int i = 0; i < n; ++i)
if (nums[i] == 0)
swap(nums[i], nums[ptr]);
++ptr;
for (int i = ptr; i < n; ++i)
if (nums[i] == 1)
swap(nums[i], nums[ptr]);
++ptr;
;
class Solution
public:
void sortColors(vector<int>& nums)
int n = nums.size();
int p0 = 0, p1 = 0;
for (int i = 0; i < n; ++i)
if (nums[i] == 1)
swap(nums[i], nums[p1]);
++p1;
else if (nums[i] == 0)
swap(nums[i], nums[p0]);
if (p0 < p1)
swap(nums[i], nums[p1]);
++p0;
++p1;
;
3.13 最长连续序列
128. 最长连续序列https://leetcode-cn.com/problems/longest-consecutive-sequence/
给定一个未排序的整数数组 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
作者实现代码先排序在哈希表 在动态规划 时间复杂度:O(nlogn)
class Solution
public:
int longestConsecutive(vector<int>& nums)
if(nums.size() == 0) return 0;
vector<int> dp(nums.size(), 1);
sort(nums.begin(), nums.end());
dp[0] = 1;
int mmax = 1;
for(int i = 1; i < nums.size(); i++)
if(nums[i] == nums[i - 1] + 1)
dp[i] = dp[i - 1] + 1;
else if(nums[i] == nums[i - 1])
dp[i] = dp[i - 1];
mmax = max(dp[i], mmax);
return mmax;
;
官方代码 利用哈希表 将重复元素和判断数组是否为空都省略了 思路真好
class Solution
public:
int longestConsecutive(vector<int>& nums)
unordered_set<int> record;
//真好,把相同重复的元素也排除在外了
for(int num : nums)
record.insert(num);
int longnum = 0;
for(int num : record)
if(!record.count(num - 1))
int curnum = num + 1;
int curlong = 1;
while(record.count(curnum))
curlong++;
curnum += 1;
longnum = max(longnum, curlong);
return longnum;
;
3.14 二叉树展开为链表
114. 二叉树展开为链表https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list/
给你二叉树的根结点 root ,请你将它展开为一个单链表:
展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
展开后的单链表应该与二叉树 先序遍历 顺序相同。
输入:root = [1,2,5,3,4,null,6]
输出:[1,null,2,null,3,null,4,null,5,null,6]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [0]
输出:[0]
class Solution
public:
void flatten(TreeNode* root)
stack<TreeNode*> st;
if(root == NULL) return;
st.push(root);
vector<TreeNode*> l;
while(!st.empty())
auto t = st.top();
st.pop();
l.push_back(t);
if(t->right != NULL)
st.push(t->right);
if(t->left != NULL)
st.push(t->left);
for(int i = 1; i < l.size(); i++)
TreeNode* pre =l[i];
TreeNode* cur = l[i - 1];
cur->left = NULL;
cur->right = pre;
;
第4天
4.1 337. 打家劫舍 III
337. 打家劫舍 IIIhttps://leetcode-cn.com/problems/house-robber-iii/
小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。
除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。
给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。
class Solution
public:
unordered_map<TreeNode *, int> f, g;
void dfs(TreeNode* root)
if(root == NULL) return;
dfs(root->left);
dfs(root->right);
f[root] = root->val + g[root->left] + g[root->right];
g[root] = max(f[root->left], g[root->left]) + max(f[root->right], g[root->right]);
return ;
int rob(TreeNode* root)
if(root == NULL) return 0;
dfs(root);
return max(f[root], g[root]);
;
4.2 309. 最佳买卖股票时机含冷冻期
309. 最佳买卖股票时机含冷冻期https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/
给定一个整数数组prices,其中第 prices[i] 表示第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: prices = [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
示例 2:
输入: prices = [1]
输出: 0
class Solution
public:
int maxProfit(vector<int>& prices)
vector<vector<int>> dp(prices.size(), vector(4, 0));
dp[0][0] = -prices[0];
dp[0][1] = 0;
dp[0][2] = 0;
dp[0][3] = 0;
for(int i = 1; i < prices.size(); i++)
dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][2], dp[i - 1][3]) - prices[i]);
dp[i][1] = dp[i - 1][0] + prices[i];
dp[i][2] = dp[i - 1][1];
dp[i][3] = max(dp[i - 1][2], dp[i - 1][3]);
int n = prices.size();
return max(dp[n - 1][1], max(dp[n - 1][3], dp[n - 1][2]));
;
class Solution
public:
int maxProfit(vector<int>& prices)
int n = prices.size();
vector<vector<int>> dp(n, vector(3,0));
dp[0][0] = -prices[0];
dp[0][1] = 0;
dp[0][2] = 0;
for(int i = 1; i < n; i++)
dp[i][0] = max(dp[i - 1][0], dp[i - 1][2] - prices[i]);
dp[i][1] = dp[i - 1][0] + prices[i];
dp[i][2] = max(dp[i - 1][2], dp[i - 1][1]);
return max(dp[n - 1][1], dp[n - 1][2]);
;
4.3 148. 排序链表
148. 排序链表https://leetcode-cn.com/problems/sort-list/
给你链表的头结点 head
,请将其按 升序 排列并返回 排序后的链表 。
时间复杂度O(n),时间复杂度O(n)
输入:head = [4,2,1,3]
输出:[1,2,3,4]
class Solution
public:
class cmp
public:
bool operator()(const pair<ListNode*, int>& a, const pair<ListNode*, int>& b)
return a.second > b.second;
;
ListNode* sortList(ListNode* head)
if(head == NULL) return head;
priority_queue<pair<ListNode*, int>, vector<pair<ListNode*, int>>, cmp> que;
ListNode *cur = head;
while(cur)
que.push(cur,cur->val);
cur = cur->next;
ListNode *myhead = new ListNode(0);
cur = myhead;
while(!que.empty())
auto t = que.top();
que.pop();
cur->next = t.first;
cur = cur->next;
cur->next = NULL;
return myhead->next;
;
官方使用的归并排序 对于归并排序不了解 等了解了再来写这道题的代码。
归并排序需要最后合并两个有序链表,可以先做一下这道题
4.4 21. 合并两个有序链表
21. 合并两个有序链表https://leetcode-cn.com/problems/merge-two-sorted-lists/
class Solution
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2)
ListNode* cur1 = list1;
ListNode* cur2 = list2;
ListNode* hummy = new ListNode(0);
ListNode* cur = hummy;
while(cur1 || cur2)
if(!cur1 && cur2)
cur->next = cur2;
break;
else if(!cur2 && cur1)
cur->next = cur1;
break;
else if(cur1->val > cur2->val)
cur->next = cur2;
cur = cur->next;
cur2 = cur2->next;
else
cur->next = cur1;
cur = cur->next;
cur1 = cur1->next;
return hummy->next;
;
官方的复杂度为:O(nlgn)时间复杂度为O(1)
直接在链表的基础上进行操作
有兴趣也可以看看这道题,对链表进行排序
4.5 147. 对链表进行插入排序
147. 对链表进行插入排序 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/insertion-sort-list/
对于147的答案:
class Solution
public:
ListNode* insertionSortList(ListNode* head)
if(!head) return head;
ListNode* hummy = new ListNode(0);
hummy->next = head;
ListNode* lastsort = head;
ListNode* cur = head->next;
while(cur)
if(lastsort->val <= cur->val)
lastsort = lastsort->next;
else
ListNode* pre = hummy;
while(pre->next->val < cur->val )
pre = pre->next;
lastsort->next = cur->next;
ListNode* temp = pre->next;
pre->next = cur;
cur->next = temp;
cur = lastsort->next;
return hummy->next;
;
对于改题,使用插入排序:
class Solution
public:
ListNode* sortList(ListNode* head)
ListNode* hummy = new ListNode(0);
hummy->next = head;
ListNode* cur = head;
ListNode* pre = NULL;
while(cur)
if(pre == NULL)
pre = cur;
cur = cur->next;
else
if(pre->val > cur->val)
ListNode* mhead = new ListNode(0);
mhead = hummy;
while(mhead->next->val < cur->val)
mhead = mhead->next;
ListNode* temp = cur->next;
ListNode* temp1 = mhead->next;
mhead->next = cur;
pre->next = temp;
cur->next = temp1;
cur = temp;
else
pre = cur;
cur = cur->next;
return hummy->next;
;
这是作者写的归并排序:
class Solution
public:
ListNode* mergeSort(ListNode* head)
if(!head || !head->next)
return head;
ListNode* slow = head;
ListNode* faster = head;
while(faster && faster->next && faster->next->next)
slow = slow->next;
faster = faster->next->next;
cout << slow->val << endl;
ListNode* temp = slow->next;
slow->next = NULL;
ListNode* head1 = mergeSort(head);
ListNode* head2 = mergeSort(temp);
ListNode* mhead2 = new ListNode(0);
ListNode* next = mhead2;
while(head1 || head2)
if(!head1 && head2)
next->next = head2;
break;
else if(!head2 && head1)
next->next = head1;
break;
else if(head1->val < head2->val)
next->next = head1;
head1 = head1->next;
next = next->next;
else if(head1->val >= head2->val)
next->next = head2;
head2 = head2->next;
next = next->next;
return mhead2->next;
ListNode* sortList(ListNode* head)
return mergeSort(head);
;
class Solution
public:
void mergeTwoList(ListNode* l1, ListNode* l2, ListNode* cur)
if(l1 && !l2)
cur->next = l1;
return;
if(!l1 && l2)
cur->next = l2;
return;
if(l1->val > l2->val)
cur->next = l2;
cur = cur->next;
mergeTwoList(l1, l2->next, cur);
else
cur->next = l1;
cur = cur->next;
mergeTwoList(l1->next, l2, cur);
ListNode* mergeSort(ListNode* head)
if(!head || !head->next)
return head;
ListNode* slow = head;
ListNode* faster = head;
while(faster && faster->next && faster->next->next)
slow = slow->next;
faster = faster->next->next;
ListNode* temp = slow->next;
slow->next = NULL;
ListNode* head1 = mergeSort(head);
ListNode* head2 = mergeSort(temp);
ListNode* mhead = new ListNode(0);
ListNode* cur = mhead;
mergeTwoList(head1, head2, cur);
return mhead->next;
ListNode* sortList(ListNode* head)
return mergeSort(head);
;
官方空间复杂度为O(1):
class Solution
public ListNode sortList(ListNode head)
if (head == null)
return head;
int length = 0;
ListNode node = head;
while (node != null)
length++;
node = node.next;
ListNode dummyHead = new ListNode(0, head);
for (int subLength = 1; subLength < length; subLength <<= 1)
ListNode prev = dummyHead, curr = dummyHead.next;
while (curr != null)
ListNode head1 = curr;
for (int i = 1; i < subLength && curr.next != null; i++)
curr = curr.next;
ListNode head2 = curr.next;
curr.next = null;
curr = head2;
for (int i = 1; i < subLength && curr != null && curr.next != null; i++)
curr = curr.next;
ListNode next = null;
if (curr != null)
next = curr.next;
curr.next = null;
ListNode merged = merge(head1, head2);
prev.next = merged;
while (prev.next != null)
prev = prev.next;
curr = next;
return dummyHead.next;
public ListNode merge(ListNode head1, ListNode head2)
ListNode dummyHead = new ListNode(0);
ListNode temp = dummyHead, temp1 = head1, temp2 = head2;
while (temp1 != null && temp2 != null)
if (temp1.val <= temp2.val)
temp.next = temp1;
temp1 = temp1.next;
else
temp.next = temp2;
temp2 = temp2.next;
temp = temp.next;
if (temp1 != null)
temp.next = temp1;
else if (temp2 != null)
temp.next = temp2;
return dummyHead.next;
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/sort-list/solution/pai-xu-lian-biao-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
4.6 152. 乘积最大子数组
152. 乘积最大子数组https://leetcode-cn.com/problems/maximum-product-subarray/
给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
测试用例的答案是一个 32-位 整数。
子数组 是数组的连续子序列。
示例 1:
输入: nums = [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:
输入: nums = [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
class Solution
public:
int maxProduct(vector<int>& nums)
vector<int> dpmax(nums.size(), 1);
vector<int> dpmin(nums.size(), 1);
dpmax[0] = nums[0];
dpmin[0] = nums[0];
int mmax = nums[0];
for(int i = 1; i < nums.size(); i++)
dpmax[i] = max(max(nums[i], dpmax[i - 1] * nums[i]), dpmin[i - 1] * nums[i]);
dpmin[i] = min(min(nums[i], dpmax[i - 1] * nums[i]), dpmin[i - 1] * nums[i]);
mmax = max(mmax, dpmax[i]);
return mmax;
;
第5天 (拓扑排序)
5.1 207. 课程表
207. 课程表https://leetcode-cn.com/problems/course-schedule/
你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。
例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。
请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。
示例 1:
输入:numCourses = 2, prerequisites = [[1,0]]
输出:true
解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。
示例 2:
输入:numCourses = 2, prerequisites = [[1,0],[0,1]]
输出:false
解释:总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。
这道题 我首先思想是对其就是优先队列排队,内容和第四天的排序链表那道题类似,然后找区间是否有交区,如果有交区,那么就不行。只是这道题不行, 比如说[0,1],[0,2], 或者[1,0],[2,1],[0,2]。然后又想到了哈希表。哈哈 看答案才知道是拓扑排序 和上面题 归并排序一样 不是很懂 所以需要区学习 这道题先放到 等学完了 再来实现代码。
5.2 215. 数组中的第K个最大元素
215. 数组中的第K个最大元素https://leetcode-cn.com/problems/kth-largest-element-in-an-array/
给定整数数组 nums
和整数 k
,请返回数组中第 k
个最大的元素。
请注意,你需要找的是数组排序后的第 k
个最大的元素,而不是第 k
个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
这道图 最简单的方法就是对其就行排序,然后直接知道第k大的元素
时间复杂度:O(nlongn)空间复杂度O(1)
还可以用优先队列,时间复杂度O(n),空间复杂度为O(n)空间换时间
class Solution
public:
int findKthLargest(vector<int>& nums, int k)
priority_queue<int, vector<int>, less<int>> que;
for(int num:nums)
que.push(num);
for(int j = k - 1; j > 0; j--)
que.pop();
return que.top();
;
但是官方中等题肯定不是考你这个。
在思考哈
这道题要找到第、k大的数,那么肯定需要遍历整个数组,时间复杂度至少为O(n),那么思考的方向是怎么才能把空间复杂度降下去,如果要把空间复杂度降下去,那么就只能在原数组进行操作。
怎么对其进行操作了?排序?
好嘛 实在想不到更加好的算法了 ,那么就排序吧
这里选择归并排序 试试
class Solution
public:
void maxHeapify(vector<int>& nums, vector<int>& temp, int l, int r)
if(l >= r) return;
int mid = l + (r - l) / 2;
maxHeapify(nums, temp, l, mid);
maxHeapify(nums, temp, mid + 1, r);
if(nums[mid] < nums[mid + 1]) return;
mtemp(nums, temp, l, r);
void mtemp(vector<int>& nums, vector<int>& temp, int l, int r)
int mid = l + (r - l) / 2;
for(int i = l; i <= r; i++)
temp[i] = nums[i];
int i = l;
int j = mid + 1;
for(int k = l; k <= r; k++)
if(i == mid + 1)
nums[k] = temp[j];
j++;
else if(j == r + 1)
nums[k] = temp[i];
i++;
else if(temp[i] > temp[j])
nums[k] = temp[j];
j++;
else
nums[k] = temp[i];
i++;
int findKthLargest(vector<int>& nums, int k)
vector<int> temp(nums);
maxHeapify(nums, temp, 0, nums.size() - 1);
int j = nums.size() - 1;
for(; j > nums.size() - k; j--);
return nums[j];
;
也能过 但是时间复杂度为O(nlongn),空间复杂度为O(n);
这里推荐一个对于归并排序的经典使用:
剑指 Offer 51. 数组中的逆序对LeetCode 热题 HOT 100
#yyds干货盘点# LeetCode 热题 HOT 100:子集