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:子集

leetcode热题Hot100——LRU缓存

#yyds干货盘点# LeetCode 热题 HOT 100:全排列

leetcode热题Hot100——LRU缓存

#yyds干货盘点# LeetCode 热题 HOT 100:最长有效括号