刷题总结——数据结构相关

LeetCode—链表

T160. 相交链表

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if(headA == NULL || headB == NULL)  return NULL;
        ListNode* pa = headA;
        ListNode* pb = headB;
        while(pa != pb){
            (pa == NULL) ? (pa = headB) : (pa = pa->next);
            (pb == NULL) ? (pb = headA) : (pb = pb->next);
        }
        return pa;
    }
};

T206. 反转链表
迭代:

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* p = head;
        ListNode* cur = NULL;
        ListNode* pre = NULL;
        while(p != NULL){
            cur = p;
            p = p->next;
            cur->next = pre;
            pre = cur;
        }
        return cur;
    }
};

递归:
递归解法的思路是,不断的进入递归函数,直到head指向倒数第二个节点,因为head指向空或者是最后一个结点都直接返回了,newHead则指向对head的下一个结点调用递归函数返回的头结点,此时newHead指向最后一个结点,然后head的下一个结点的next指向head本身,这个相当于把head结点移动到末尾的操作,因为是回溯的操作,所以head的下一个结点总是在上一轮被移动到末尾了,但head之后的next还没有断开,所以可以顺势将head移动到末尾,再把next断开,最后返回newHead即可。

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if (!head || !head->next) return head;
        ListNode *newHead = reverseList(head->next);
        head->next->next = head;
        head->next = NULL;
        return newHead;
    }
};

T21. 合并两个有序链表

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode dummy(0);
        ListNode* head = &dummy;
        while(l1 != NULL && l2 != NULL){
            if(l1->val < l2->val){
                head->next = new ListNode(l1->val);
                head = head->next;
                l1 = l1->next;
            }
            else{
                head->next = new ListNode(l2->val);
                head = head->next;
                l2 = l2->next;
            }
        }
            while(l1 != NULL){
                head->next = new ListNode(l1->val);
                head = head->next;
                l1 = l1->next;
            }
            while(l2 != NULL){
                head->next = new ListNode(l2->val);
                head = head->next;
                l2 = l2->next;
            }
            return dummy.next;
        
    }
};

T83. 删除排序链表中的重复元素

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        ListNode* p = head;
        while(p != NULL && p->next != NULL){
            if(p->val == p->next->val){
                p->next = p->next->next;
            }
            else{
                p = p->next;
            }
        }
        return head;
    }
};

T19. 删除链表的倒数第N个节点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode dummy(0);
        ListNode* tail = &dummy;
        tail->next = head;
        ListNode* slow = tail;
        ListNode* fast = tail;
        while(n--){
            fast = fast->next;
        }
        while(fast->next != NULL){
            fast = fast->next;
            slow = slow->next;
        }
        slow->next = slow->next->next;
        return dummy.next;
    }
};

T24. 两两交换链表中的节点

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode dummy(0);
        ListNode* tail = &dummy;
        tail->next = head;
        ListNode* p1 = tail;
        while(p1->next != NULL && p1->next->next != NULL){
            ListNode* p2 = p1->next;
            ListNode* p3 = p2->next;
            p1->next = p3;
            p2->next = p3->next;
            p3->next = p2;
            p1 = p2;
        }
        return dummy.next;
    }
};

T445. 两数相加 II

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        stack<int> s1;
        stack<int> s2;
        while(l1 != NULL){
            s1.push(l1->val);
            l1 = l1->next;
        }
        while(l2 != NULL){
            s2.push(l2->val);
            l2 = l2->next;
        }
        ListNode* p = new ListNode(0);
        int num = 0;
        while(!s1.empty() || !s2.empty()){
            if(!s1.empty()){
                num += s1.top();
                s1.pop();
            }
            if(!s2.empty()){
                num += s2.top();
                s2.pop();
            }
            p->val = num % 10;
            ListNode* q = new ListNode(num / 10);
            q->next = p;
            p = q;
            num /= 10;
        }
        return p->val == 0 ? p->next : p;
    }
};

T234. 回文链表

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if(head == NULL || head->next == NULL)  return true;
        ListNode* slow = head;
        ListNode* fast = head;
        while(fast->next != NULL && fast->next->next != NULL){
            slow = slow->next;
            fast = fast->next->next;
        }
        ListNode* p1 = slow->next;
        while(p1->next != NULL){
            ListNode* p2 = p1->next;
            p1->next = p2->next;
            p2->next = slow->next;
            slow->next = p2;
        }
        ListNode* pre = head;
        while(slow->next != NULL){
            slow = slow->next;
            if(pre->val != slow->val)  return false;
            pre = pre->next;
        }
        return true;
    }
};

T725. 分隔链表

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    vector<ListNode*> splitListToParts(ListNode* root, int k) {
        vector<ListNode*> res(k);
        int len = 0;
        for(ListNode* t = root; t != NULL; t = t->next)
            len++;
        int a = len / k;
        int b = len % k;
        for(int i = 0; i < k && root != NULL; ++i){
            res[i] = root;
            for(int j = 1; j < a + (i < b); ++j){
                root = root->next;
            }
            ListNode* t = root->next;
            root->next = NULL;
            root = t;
        }
        return res;
    }
};

T328. 奇偶链表

/**
 * 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* oddEvenList(ListNode* head) {
        ListNode dummy1(0);
        ListNode* tail1 = &dummy1;
        ListNode dummy2(0);
        ListNode* tail2 = &dummy2;
        int flag = 1;
        while(head != NULL){
            if(flag == 1){
                tail1->next = new ListNode(head->val);
                tail1 = tail1->next;
                head = head->next;
                flag = 0;
            }
            else if(flag == 0){
                tail2->next = new ListNode(head->val);
                tail2 = tail2->next;
                head = head->next;
                flag = 1;
            }
        }
        tail2->next = NULL;
        tail1->next = dummy2.next;
        return dummy1.next;
    }
};

LeetCode—栈和队列

T232. 用栈实现队列

class MyQueue {
public:
    stack<int> s1, s2;
    /** Initialize your data structure here. */
    MyQueue() {
        while(!s1.empty())  s1.pop();
        while(!s2.empty())  s2.pop();
    }
    
    /** Push element x to the back of queue. */
    void push(int x) {
        s1.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        while(s1.size() > 1){
            s2.push(s1.top());
            s1.pop();
        }
        int x = s1.top();
        s1.pop();
        while(!s2.empty()){
            s1.push(s2.top());
            s2.pop();
        }
        return x;

    }
    
    /** Get the front element. */
    int peek() {
        while(s1.size() > 1){
            s2.push(s1.top());
            s1.pop();
        }
        int x =s1.top();
        while(!s2.empty()){
            s1.push(s2.top());
            s2.pop();
        }
        return x;
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        if(s1.empty()) return true;
        else return false;
    }
};

T225. 用队列实现栈

class MyStack {
public:
    queue<int> q1, q2;
    /** Initialize your data structure here. */
    MyStack() {
        while(!q1.empty())  q1.pop();
        while(!q2.empty())  q2.pop();
    }
    
    /** Push element x onto stack. */
    void push(int x) {
        q1.push(x);
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        while(q1.size() > 1){
            q2.push(q1.front());
            q1.pop();
        }
        int x = q1.front();
        q1.pop();
        while(!q2.empty()){
            q1.push(q2.front());
            q2.pop();
        }
        return x;
    }
    
    /** Get the top element. */
    int top() {
        while(q1.size() > 1){
            q2.push(q1.front());
            q1.pop();
        }
        int x = q1.front();
        q1.pop();
        q2.push(x);
        while(!q2.empty()){
            q1.push(q2.front());
            q2.pop();
        }
        return x;
    }
    
    /** Returns whether the stack is empty. */
    bool empty() {
        if(q1.empty()) return true;
        else return false;
    }
};

T155. 最小栈
使用两个栈来实现,一个栈来按顺序存储 push 进来的数据,另一个用来存出现过的最小值。

class MinStack {
public:
    stack<int> st1, st2;
    /** initialize your data structure here. */
    MinStack() {

        
    }
    
    void push(int x) {
        st1.push(x);
        if(st2.empty() || x<= st2.top())  st2.push(x);        
    }
    
    void pop() {
        if(st1.top() == st2.top())  st2.pop();
        st1.pop();
    }
    
    int top() {
        return st1.top();
        
    }
    
    int getMin() {
        return st2.top();

    }
};

T20. 有效的括号
这道题让我们验证输入的字符串是否为括号字符串,包括大括号,中括号和小括号。这里需要用一个栈,开始遍历输入字符串,如果当前字符为左半边括号时,则将其压入栈中,如果遇到右半边括号时,若此时栈为空,则直接返回 false,如不为空,则取出栈顶元素,若为对应的左半边括号,则继续循环,反之返回 false。

class Solution {
public:
    bool isValid(string s) {
        stack<char> s1;
        for(char c : s){
            switch (c){
                case '(':
                case '[':
                case '{': s1.push(c);break;
                case '}': 
                if(s1.empty() || s1.top() != '{') return false; 
                else s1.pop(); break;
                case ']': 
                if(s1.empty() || s1.top() != '[') return false; 
                else s1.pop(); break;
                case ')': 
                if(s1.empty() || s1.top() != '(') return false; 
                else s1.pop(); break;
            }
        }
        return s1.empty();
        
    }
};

T739. 每日温度
这道题给了我们一个数组,让我们找下一个比当前数字大的数字的距离,我们研究一下题目中给的例子,发现数组是无序的,所以没法用二分法快速定位下一个大的数字,那么最先考虑的方法就是暴力搜索了,写起来没有什么难度,但是OJ并不答应。实际上这道题应该使用递减栈Descending Stack来做,栈里只有递减元素,思路是这样的,我们遍历数组,如果栈不空,且当前数字大于栈顶元素,那么如果直接入栈的话就不是递减栈了,所以我们取出栈顶元素,那么由于当前数字大于栈顶元素的数字,而且一定是第一个大于栈顶元素的数,那么我们直接求出下标差就是二者的距离了,然后继续看新的栈顶元素,直到当前数字小于等于栈顶元素停止,然后将数字入栈,这样就可以一直保持递减栈,且每个数字和第一个大于它的数的距离也可以算出来了。

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& T) {
        int n = T.size();
        vector<int> res(n, 0);
        stack<int> st;
        for(int i=0; i<n; ++i){
            while(!st.empty() && T[st.top()] < T[i]){
                auto t = st.top();
                st.pop();
                res[t] = i-t;
            }
            st.push(i);
        }
        return res;

    }
};

T503. 下一个更大元素 II
我们可以使用栈,遍历两倍的数组,坐标i对n取余,取出数字,如果此时栈不为空,且栈顶元素小于当前数字,说明当前数字就是栈顶元素的右边第一个较大数,那么建立二者的映射,并且去除当前栈顶元素,最后如果i小于n,则把i压入栈。因为res的长度必须是n,超过n的部分我们只是为了给之前栈中的数字找较大值,所以不能压入栈。

class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        vector<int> res(nums.size(), -1);
        stack<int> st;
        for(int i=0; i<2*nums.size(); ++i){
            while(!st.empty() && nums[st.top()] < nums[i%nums.size()]){
                res[st.top()] = nums[i%nums.size()];
                st.pop();
            }
            if(i<nums.size())
            st.push(i);
        }
        return res;

    }
};

T503. 下一个更大元素 II

class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        vector<int> res(nums.size(), -1);
        stack<int> st;
        for(int i=0; i<2*nums.size(); ++i){
            while(!st.empty() && nums[st.top()] < nums[i%nums.size()]){
                res[st.top()] = nums[i%nums.size()];
                st.pop();
            }
            if(i<nums.size())
            st.push(i);
        }
        return res;

    }
};

LeetCode—哈希表

T1. 两数之和
这道题给了我们一个数组,还有一个目标数target,让找到两个数字,使其和为 target,乍一看就感觉可以用暴力搜索,但是猜到 OJ 肯定不会允许用暴力搜索这么简单的方法,于是去试了一下,果然是 Time Limit Exceeded,这个算法的时间复杂度是 O(n^2)。那么只能想个 O(n) 的算法来实现,由于暴力搜索的方法是遍历所有的两个数字的组合,然后算其和,这样虽然节省了空间,但是时间复杂度高。一般来说,为了提高时间的复杂度,需要用空间来换,这算是一个 trade off 吧,但这里只想用线性的时间复杂度来解决问题,就是说只能遍历一个数字,那么另一个数字呢,可以事先将其存储起来,使用一个 HashMap,来建立数字和其坐标位置之间的映射,由于 HashMap 是常数级的查找效率,这样在遍历数组的时候,用 target 减去遍历到的数字,就是另一个需要的数字了,直接在 HashMap 中查找其是否存在即可,注意要判断查找到的数字不是第一个数字,比如 target 是4,遍历到了一个2,那么另外一个2不能是之前那个2,整个实现步骤为:先遍历一遍数组,建立 HashMap 映射,然后再遍历一遍,开始查找,找到则记录 index。代码如下:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> hash;
        vector<int> res;
        for (int i = 0; i < nums.size(); ++i) {
            hash[nums[i]] = i;
        }
        for (int i = 0; i < nums.size(); ++i) {
            int t = target - nums[i];
            //hash.count(t)判断t是否在hash表中
            if (hash.count(t) && hash[t] != i) {
                res.push_back(i);
                res.push_back(hash[t]);
                break;
            }
        }
        return res; 
    }
};

T217. 存在重复元素
使用一个哈希表,遍历整个数组,如果哈希表里存在,返回true,如果不存在,则将其放入哈希表中。

class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
        unordered_map<int, int> m;
        for (int i = 0; i < nums.size(); ++i) {
            if (m.find(nums[i]) != m.end()) //写成if(m.count(nums[i]))也可以
                return true;
            ++m[nums[i]];
        }
        return false;
    }
};
class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
        unordered_map<int, int> m;
        for (int i = 0; i < nums.size(); ++i) {
            if (m[nums[i]] == 1) //写成if(m.count(nums[i]))也可以
                return true;
            m[nums[i]] = 1;
        }
        return false;
    }
};

T594. 最长和谐子序列

class Solution {
public:
    int findLHS(vector<int>& nums) {
        unordered_map<int, int> m;
        int res=0;
        for(int num:nums) ++m[num];
        for(auto a:m){
            if(m.count(a.first+1)){
                res=max(res, m[a.first]+m[a.first+1]);
            }
        }
        return res;

    }
};

T128. 最长连续序列

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        unordered_map<int, int> m;
        for(int num : nums){
            if(m.count(num))  continue;//重复的数不用考虑

            auto left = m.find(num-1);
            auto right = m.find(num+1);
            int l = (left!=m.end()) ? left->second : 0;//->second里面存放的是边界长度
            int r = right!=m.end() ? right->second : 0;
            if(l>0 && r>0)
                m[num] = m[num-l] = m[num+r] =l+r+1;
            else if(l>0)
                m[num] =m[num-l] =l+1;
            else if(r>0)
                m[num] = m[num+r] = r+1;
            else
                m[num] = 1;
        }
        int ans = 0;
        for(const auto& kv : m)
            ans = max(ans, kv.second);
        return ans;

    }
};

LeetCode—字符串

编程之美3.1——字符串循环移位包含
在这里插入图片描述

编程之美2.17——字符串循环移位
在这里插入图片描述
程序员代码面试指南——字符串中单词的翻转
在这里插入图片描述
T242. 有效的字母异位词

class Solution {
public:
    bool isAnagram(string s, string t) {
        if (s.size() != t.size()) return false;
        int m[26] = {0};
        for (int i = 0; i < s.size(); ++i) ++m[s[i] - 'a'];
        for (int i = 0; i < t.size(); ++i) {
            if (--m[t[i] - 'a'] < 0) return false;
        }
        return true;
    }
};

T409. 最长回文串

class Solution {
public:
    int longestPalindrome(string s) {
        int res = 0;
        bool mid = false;
        unordered_map<char, int> m;
        for (char c : s) ++m[c];
        for (auto it = m.begin(); it != m.end(); ++it) {
            res += it->second;
            if (it->second % 2 == 1) {
                res -= 1;
                mid = true;
            } 
        }
        return mid ? res + 1 : res;
    }
};

T205. 同构字符串

class Solution {
public:
    bool isIsomorphic(string s, string t) {
        if(s.size() != t.size())  return false;
        int m1[256] = {0};
        int m2[256] = {0};
        for(int i = 0; i <= s.size(); ++i)
        {
            if(m1[s[i]] != m2[t[i]])  return false;
            m1[s[i]] = i + 1;
            m2[t[i]] = i + 1;
        }
        return true;

        
    }
};

T647. 回文子串

class Solution {
public:
    int countSubstrings(string s) {
        if(s.empty())  return 0;
        int res = 0;
        int n = s.size();
        for(int i = 0; i < n; ++i)
        {
            helper(s, i, i, res);
            helper(s, i, i+1, res);
        }
        return res;

    }

    void helper(string s, int i, int j, int& res){
        while(i >= 0 && j < s.size() && s[i] == s[j])
        {
            --i;
            ++j;
            ++res;
        }
    }
};

T9.回文数

class Solution {
public:
    bool isPalindrome(int x) {
        long rev;
        if (x < 0)  return false;
        string str_x = to_string(x);//转换成字符串
        std::reverse(str_x.begin(), str_x.end());//进行反转
        stringstream out(str_x);
        out >> rev;//结果写入rev
        return x==rev;//比较得出结果

        
    }
};
class Solution {
public:
    bool isPalindrome(int x) {
        if(x < 0) return false;
        int div = 1;
        while(x/div >= 10)  div *= 10;
        while(x){
            int left = x / div;
            int right = x % 10;
            if(left != right)  return false;
            x = (x % div) / 10;
            div /= 100;
        }
        return true;
    }
};

T696. 计数二进制子串

class Solution {
public:
    int countBinarySubstrings(string s) {
        int zeros = 0;
        int ones = 0;
        int res = 0;
        for(int i = 0; i <= s.size(); ++i)
        {
            if(i == 0)  (s[i] == '1') ? ++ones : ++zeros;
            else
            {
                if(s[i] == '1')
                {
                    ones = (s[i-1] == '1') ? ones+1 : 1;
                    if(zeros >= ones)  ++res;
                }
                else if(s[i] == '0')
                {
                    zeros = (s[i-1] == '0') ? zeros+1 : 1;
                    if(ones >= zeros)  ++res;
                }
            }
        }
        return res;

    }
};

LeetCode—数组与矩阵

T283. 移动零
这道题让我们将一个给定数组中所有的0都移到后面,把非零数前移,要求不能改变非零数的相对应的位置关系,而且不能拷贝额外的数组,那么只能用替换法in-place来做,需要用两个指针,一个不停的向后扫,找到非零位置,然后和前面那个指针交换位置即可,参见下面的代码:

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        for(int i = 0, j = 0; i < nums.size(); ++i){
            if(nums[i]){
                swap(nums[i], nums[j++]);
            } 
        }
    }
};

T566. 重塑矩阵
这道题让我们实现矩阵大小的重塑,也就是实现 Matlab 中的 reshape 函数。对于这种二维数组大小重新分配的问题的关键就是对应位置的坐标转换,最直接的办法就是先把原数组拉直,变成一条直线,然后再组成新的数组。所以这道题我们先判断给定数组是否能重塑成给定的大小,就是看两者的元素总数是否相同,直接行数乘以列数即可,然后我们新建一个目标大小的数组,并开始遍历,对于每个位置,我们先转为拉直后的一维坐标,然后在算出在原数组中的对应位置赋值过来即可。

class Solution {
public:
    vector<vector<int>> matrixReshape(vector<vector<int>>& nums, int r, int c) {
        int m = nums.size();
        int n = nums[0].size();
        if(m * n != r * c)  return nums;
        vector<vector<int>> res(r, vector<int>(c));
        for (int i = 0; i < r; ++i) {
            for (int j = 0; j < c; ++j) {
                int k = i * c + j;
                res[i][j] = nums[k / n][k % n];
            }
        }
        return res;
    }
};

T485. 最大连续1的个数

class Solution {
public:
    int findMaxConsecutiveOnes(vector<int>& nums) {
        int res = 0;
        int count = 0;
        for(int i = 0; i < nums.size(); ++i)
        {
            if(nums[i] == 1)
            {
                res++;
            }
            else if(nums[i] == 0)
            {
                res = 0;
            }
            count = max(count, res);
        }
        return count;

    }
};

T240. 搜索二维矩阵 II

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        if (matrix.empty() || matrix[0].empty()) return false;
        if (target < matrix[0][0] || target > matrix.back().back()) return false;
        int x = matrix.size() - 1, y = 0;
        while (true) {
            if (matrix[x][y] > target) --x;
            else if (matrix[x][y] < target) ++y;
            else return true;
            if (x < 0 || y >= matrix[0].size()) break;
        }
        return false;
        
    }
};

T378. 有序矩阵中第K小的元素

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        priority_queue<int> q;
        for (int i = 0; i < matrix.size(); ++i) {
            for (int j = 0; j < matrix[i].size(); ++j) {
                q.push(matrix[i][j]);
                if (q.size() > k) q.pop();
            }
        }
        return q.top();
    }
};

T645. 错误的集合

class Solution {
public:
    vector<int> findErrorNums(vector<int>& nums) {
        vector<int> res(2, 0), cnt(nums.size(), 0);
        for (int num : nums) ++cnt[num - 1];
        for (int i = 0; i < cnt.size(); ++i) {
            if (res[0] != 0 && res[1] != 0) return res;
            if (cnt[i] == 2) res[0] = i + 1;
            else if (cnt[i] == 0) res[1] = i + 1;
        }
        return res;

    }
};

T287. 寻找重复数
只能考虑用二分搜索法了,在区间 [1, n] 中搜索,首先求出中点 mid,然后遍历整个数组,统计所有小于等于 mid 的数的个数,如果个数小于等于 mid,则说明重复值在 [mid+1, n] 之间,反之,重复值应在 [1, mid-1] 之间,然后依次类推,直到搜索完成,此时的 low 就是我们要求的重复值。

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int left = 1, right = nums.size();
        while (left < right){
            int mid = left + (right - left) / 2, cnt = 0;
            for (int num : nums) {
                if (num <= mid) ++cnt;
            }
            if (cnt <= mid) left = mid + 1;
            else right = mid;
        }    
        return right;

    }
};

T667. 优美的排列 II

class Solution {
public:
    vector<int> constructArray(int n, int k) {
        vector<int> res;
        int i=1;
        int j=n;
        while(i<=j){
            if(k>1) res.push_back(k--%2 ? i++ : j--);
            else res.push_back(i++);
        }
        return res;

    }
};

T697. 数组的度
这道题给了我们一个数组,定义数组的度为某个或某些数字出现最多的次数,要我们找最短的子数组使其和原数组拥有相同的度。那么我们肯定需要统计每个数字出现的次数,就要用哈希表来建立每个数字和其出现次数之间的映射。由于我们要求包含原度的最小长度的子数组,那么最好的情况就是子数组的首位数字都是统计度的数字,即出现最多的数字。那么我们肯定要知道该数字的第一次出现的位置和最后一次出现的位置,由于我们开始不知道哪些数字会出现最多次,所以我们统计所有数字的首尾出现位置,那么我们再用一个哈希表,建立每个数字和其首尾出现的位置。我们用变量degree来表示数组的度。好,现在我们遍历原数组,累加当前数字出现的次数,当某个数字是第一次出现,那么我们用当前位置的来更新该数字出现的首尾位置,否则只更新尾位置。每遍历一个数,我们都更新一下degree。当遍历完成后,我们已经有了数组的度,还有每个数字首尾出现的位置,下面就来找出现次数为degree的数组,然后计算其首尾位置差加1就是candidate数组的长度,由于出现次数为degree的数字不一定只有一个,我们遍历所有的,找出其中最小的即可。

class Solution {
public:
    int findShortestSubArray(vector<int>& nums) {
        int n = nums.size();
        int res = INT_MAX;
        int degree = 0;
        unordered_map<int, int> m;
        unordered_map<int, pair<int, int>> pos;
        for(int i=0; i<n; ++i){
            if(++m[nums[i]] == 1){
                pos[nums[i]] = {i, i};
            }
            else{
                pos[nums[i]].second = i; 
            }
            degree = max(degree, m[nums[i]]);
        }
        for(auto a : m){
            if(degree == a.second){
                res = min(res, pos[a.first].second - pos[a.first].first+1);
            }
        }
        return res;

    }
};

T766. 托普利兹矩阵

class Solution {
public:
    bool isToeplitzMatrix(vector<vector<int>>& matrix) {
        for(int i = 0; i < matrix.size() - 1; ++i){
            for(int j = 0; j < matrix[0].size() - 1; ++j){
                if(matrix[i][j] != matrix[i+1][j+1])  return false;
            }          
        }
        return true;

    }
};

T565. 数组嵌套
这道题让我们找嵌套数组的最大个数,给的数组总共有n个数字,范围均在 [0, n-1] 之间,题目中也把嵌套数组的生成解释的很清楚了,其实就是值变成坐标,得到的数值再变坐标。那么实际上当循环出现的时候,嵌套数组的长度也不能再增加了,而出现的这个相同的数一定是嵌套数组的首元素,博主刚开始没有想清楚这一点,以为出现重复数字的地方可能是嵌套数组中间的某个位置,于是用个 set 将生成的嵌套数组存入,然后每次查找新生成的数组是否已经存在。而且还以原数组中每个数字当作嵌套数组的起始数字都算一遍,结果当然是 TLE 了。其实对于遍历过的数字,我们不用再将其当作开头来计算了,而是只对于未遍历过的数字当作嵌套数组的开头数字,不过在进行嵌套运算的时候,并不考虑中间的数字是否已经访问过,而是只要找到和起始位置相同的数字位置,然后更新结果 res,参见代码如下:

class Solution {
public:
    int arrayNesting(vector<int>& nums) {
        int n=nums.size();
        int res=INT_MIN;
        vector<bool> visited(n,false);
        for(int i=0; i<n; ++i){
            if(visited[nums[i]])  continue;
            res = max(res, helper(nums, i, visited));
        }
        return res;

    }
    int helper(vector<int>& nums, int start, vector<bool>& visited){
        int i=start;
        int cnt=0;
        while(cnt==0 || i!=start){
            visited[i] = true;
            i=nums[i];
            ++cnt;
        }
        return cnt;
    }
};

T769. 最多能完成排序块
我们遍历原数组,用cur表示能到达的最远点,然后我们遍历当前位置到cur之间的所有点,遍历的同时如果遇到更大的数字就更新cur,当cur大于等于末尾数字的时候,此时不能再拆分新块儿了,返回结果res加1。否则的话说明到达了最远点,更新第一个for循环的变量i,并且结果res自增1。

class Solution {
public:
    int maxChunksToSorted(vector<int>& arr) {
        int res = 0;
        int n = arr.size();
        for(int i=0; i<n; ++i){
            int cur =arr[i];
            int j=i+1;
            for(; j<=cur; ++j){
                cur = max(cur, arr[j]);
                if(cur >= arr.back()) return res+1;            
                }
            i=j-1;
            ++res;
        }
        return res;

    }
};

LeetCode—图

二分图

T785. 判断二分图
这道题让我们验证给定的图是否是二分图,所谓二分图,就是可以将图中的所有顶点分成两个不相交的集合,使得同一个集合的顶点不相连。为了验证是否有这样的两个不相交的集合存在,我们采用一种很机智的染色法,大体上的思路是要将相连的两个顶点染成不同的颜色,一旦在染的过程中发现有相连的两个顶点已经被染成相同的颜色,说明不是二分图。这里我们使用两种颜色,分别用1和 -1 来表示,初始时每个顶点用0表示未染色,然后遍历每一个顶点,如果该顶点未被访问过,则调用递归函数,如果返回 false,那么说明不是二分图,则直接返回 false。如果循环退出后没有返回 false,则返回 true。在递归函数中,如果当前顶点已经染色,如果该顶点的颜色和将要染的颜色相同,则返回 true,否则返回 false。如果没被染色,则将当前顶点染色,然后再遍历与该顶点相连的所有的顶点,调用递归函数,如果返回 false 了,则当前递归函数的返回 false,循环结束返回 true,参见代码如下:

class Solution {
public:
    bool isBipartite(vector<vector<int>>& graph) {
        vector<int> colors(graph.size());
        for (int i = 0; i < graph.size(); ++i) {
            if (colors[i] == 0 && !valid(graph, 1, i, colors)) {
                return false;
            }
        }
        return true;
    }
    bool valid(vector<vector<int>>& graph, int color, int cur, vector<int>& colors) {
        if (colors[cur] != 0) return colors[cur] == color;
        colors[cur] = color;
        for (int i : graph[cur]) {
            if (!valid(graph, -1 * color, i, colors)) {
                return false;
            }
        }
        return true;
    }
};

拓扑排序

T207. 课程表
定义二维数组 graph 来表示这个有向图,一维数组 in 来表示每个顶点的入度。开始先根据输入来建立这个有向图,并将入度数组也初始化好。然后定义一个 queue 变量,将所有入度为0的点放入队列中,然后开始遍历队列,从 graph 里遍历其连接的点,每到达一个新节点,将其入度减一,如果此时该点入度为0,则放入队列末尾。直到遍历完队列中所有的值,若此时还有节点的入度不为0,则说明环存在,返回 false,反之则返回 true。

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        vector<vector<int>> graph(numCourses, vector<int>());//存储有向图
        vector<int> in(numCourses);//存储每个节点的入度
        for (auto a : prerequisites) {
            graph[a[1]].push_back(a[0]);
            ++in[a[0]];
        }

        queue<int> q;
        // 将所有入度为 0 的节点放入队列中
        for (int i = 0; i < numCourses; ++i) {
            if (in[i] == 0) q.push(i);
        }
        while (!q.empty()) {
            // 从队首取出一个节点
            int u = q.front();
            q.pop();
            for (int v: graph[u]) {
                --in[v];
                // 如果相邻节点 v 的入度为 0,就可以选 v 对应的课程了
                if (in[v] == 0) {
                    q.push(v);
                }
            }
        }
        
        for (int i = 0; i < numCourses; ++i) {
            if (in[i] != 0) return false;
        }
        return true;

    }
};

T210. 课程表 II
这题是之前那道 Course Schedule 的扩展,那道题只让我们判断是否能完成所有课程,即检测有向图中是否有环,而这道题我们得找出要上的课程的顺序,即有向图的拓扑排序 Topological Sort,这样一来,难度就增加了,但是由于我们有之前那道的基础,而此题正是基于之前解法的基础上稍加修改,我们从 queue 中每取出一个数组就将其存在结果中,最终若有向图中有环,则结果中元素的个数不等于总课程数,那我们将结果清空即可。

class Solution {
private:
    // 存储答案
    vector<int> result;

public:
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
        vector<vector<int>> graph(numCourses, vector<int>());//存储有向图
        vector<int> in(numCourses);//存储每个节点的入度
        for (auto a : prerequisites) {
            graph[a[1]].push_back(a[0]);
            ++in[a[0]];
        }

        queue<int> q;
        // 将所有入度为 0 的节点放入队列中
        for (int i = 0; i < numCourses; ++i) {
            if (in[i] == 0) q.push(i);
        }

        while (!q.empty()) {
            // 从队首取出一个节点
            int u = q.front();
            q.pop();
            // 放入答案中
            result.push_back(u);
            for (int v: graph[u]) {
                --in[v];
                // 如果相邻节点 v 的入度为 0,就可以选 v 对应的课程了
                if (in[v] == 0) {
                    q.push(v);
                }
            }
        }

        if (result.size() != numCourses) {
            return {};
        }
        return result;
    }
};

T684. 冗余连接

LeetCode—位运算

T461. 汉明距离
这道题让我求两个数字之间的汉明距离,题目中解释的很清楚了,两个数字之间的汉明距离就是其二进制数对应位不同的个数,那么最直接了当的做法就是按位分别取出两个数对应位上的数并异或,我们知道异或的性质上相同的为0,不同的为1,我们只要把为1的情况累加起来就是汉明距离了。

class Solution {
public:
    int hammingDistance(int x, int y) {
        int res = 0;
        for (int i = 0; i < 32; ++i) {
            /*
                1 << i 是将1左移i位,即第i位为1,其余位为0
                例如1 << 2 则0001->0100
                n & (1 << i)是将左移i位的1与n进行按位与,即为保留n的第i位,其余位置零
                如果n第i位为0,则n & (1 << i)的值为0,否则不为0
                常用if(n & (1 << i)==0)用于判断n的第i位是否为0
            */
            if ((x & (1 << i)) ^ (y & (1 << i))) {
                ++res;
            }
        }
        return res;
    }
};

T136. 只出现一次的数字
题目中让我们不使用额外空间来做,本来是一道非常简单的题,但是由于加上了时间复杂度必须是 O(n),并且空间复杂度为 O(1),使得不能用排序方法,也不能使用 HashSet 数据结构。那么只能另辟蹊径,需要用位操作 Bit Operation 来解此题,0与0 ‘异或’ 是0,1与1 ‘异或’ 也是0,那么我们会得到0。根据这个特点,我们把数组中所有的数字都 ‘异或’ 起来,则每对相同的数字都会得0,然后最后剩下来的数字就是那个只有1次的数字。

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int res = 0;
        for(int i = 0; i < nums.size(); ++i){
            res = res ^ nums[i];
        }
        return res;

T268. 缺失数字
思路是既然0到n之间少了一个数,我们将这个少了一个数的数组合0到n之间完整的数组异或一下,那么相同的数字都变为0了,剩下的就是少了的那个数字了。

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        int res=0;
        for(int i=0; i<nums.size(); ++i){
            res ^= (i+1) ^nums[i];
        }
        return res;

    }
};

T260. 只出现一次的数字 III
这道题是之前那两道 Single Number 和 Single Number II 的再次延伸,说实话,这类位操作 Bit Manipulation 的题,如果之前没有遇到过类似的题目,楞想是很难相出来的,于是我只能上网搜大神们的解法,发现还真是巧妙啊。这道题其实是很巧妙的利用了 Single Number 的解法,因为那道解法是可以准确的找出只出现了一次的数字,但前提是其他数字必须出现两次才行。而这题有两个数字都只出现了一次,那么我们如果能想办法把原数组分为两个小数组,不相同的两个数字分别在两个小数组中,这样分别调用 Single Number 的解法就可以得到答案。那么如何实现呢,首先我们先把原数组全部异或起来,那么我们会得到一个数字,这个数字是两个不相同的数字异或的结果,我们取出其中任意一位为 ‘1’ 的位,为了方便起见,我们用 a &= -a 来取出最右端为 ‘1’ 的位,具体来说下这个是如何操作的吧。就拿题目中的例子来说,如果我们将其全部 ‘异或’ 起来,我们知道相同的两个数 ‘异或’ 的话为0,那么两个1,两个2,都抵消了,就剩3和5 ‘异或’ 起来,那么就是二进制的 11 和 101 ‘异或’ ,得到110。然后我们进行 a &= -a 操作。首先变负数吧,在二进制中负数采用补码的形式,而补码就是反码 +1,那么 110 的反码是 11…1001,那么加1后是 11…1010,然后和 110 相与,得到了 10,就是代码中的 diff 变量。得到了这个 diff,就可以将原数组分为两个数组了。为啥呢,我们想阿,如果两个相同的数字 ‘异或’ ,每位都会是0,而不同的数字 ‘异或’ ,一定会有对应位不同,一个0一个1,这样 ‘异或’ 是1。比如3和5的二进制 11 和 101,如果从低往高看,最开始产生不同的就是第二位,那么我们用第二位来和数组中每个数字相与,根据结果的不同,一定可以把3和5区分开来,而其他的数字由于是成对出现,所以区分开来也是成对的,最终都会 ‘异或’ 成0,不会3和5产生影响。分别将两个小组中的数字都异或起来,就可以得到最终结果了。

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        int sum = 0;
        for(int num : nums){
            sum ^= num;
        }

        int lowbit = sum & (-sum);
        vector<int> res{0, 0};
        for(int num : nums){
            if(num & lowbit) res[0] ^= num;
            else  res[1] ^= num;
        }
        return res;

    }
};

T190. 颠倒二进制位
我们只需要把要翻转的数从右向左一位位的取出来,如果取出来的是1,将结果 res 左移一位并且加上1;如果取出来的是0,将结果 res 左移一位,然后将n右移一位即可。

class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
        uint32_t res = 0;
        for(int i=0; i<32; ++i){
            if(n & 1 == 1){
                res = (res<<1) +1;
            }
            else{
                res = res << 1;
            }
            n = n >> 1;
        }
        return res;
        
    }
};

不用额外变量交换两个整数
在这里插入图片描述
T231. 2的幂

class Solution {
public:
    bool isPowerOfTwo(int n) {
        int cnt = 0;
        while(n > 0){
            cnt += (n&1);
            n >>= 1;
        }
        return cnt == 1;

    }
};

T342. 4的幂

class Solution {
public:
    bool isPowerOfFour(int num) {
        while(num && (num % 4 == 0)){
            num /= 4;
        }
        return num == 1;

    }
};

T693. 交替位二进制数

class Solution {
public:
    bool hasAlternatingBits(int n) {
        int bit = -1;
        while(n > 0){
            if(n & 1 == 1){
                if(bit == 1)  return false;
                bit = 1;
            }else{
                if(bit == 0) return false;
                bit = 0;
            }
            n >>= 1;
        }
        return true;

    }
};

T476. 数字的补数
这道题给了我们一个数,让我们求补数。通过分析题目汇总的例子,我们知道需要做的就是每个位翻转一下就行了,但是翻转的起始位置上从最高位的1开始的,前面的0是不能被翻转的,所以我们从高往低遍历,如果遇到第一个1了后,我们的flag就赋值为true,然后就可以进行翻转了,翻转的方法就是对应位异或一个1即可。

class Solution {
public:
    int findComplement(int num) {
        bool start = false;
        for(int i=31; i>=0; --i){
            if(num & (1 << i)) start = true;
            if(start)  num ^= (1<<i);
        }
        return num;

    }
};

T371. 两整数之和

class Solution {
public:
    int getSum(int a, int b) {
        if(b==0) return a;
        int sum = a ^ b;
        int carry = (a & b & 0x7fffffff) << 1;
        return getSum(sum, carry);

    }
};

T318. 最大单词长度乘积

class Solution {
public:
    int maxProduct(vector<string>& words) {
        int res = 0;
        vector<int> mask(words.size(), 0);
        for(int i=0; i<words.size(); ++i){
            for(char c : words[i]){
                mask[i] |= 1 << (c - 'a');
            }
            for(int j=0; j<i; ++j){
                if(!(mask[i] & mask[j])){
                    res = max(res, int(words[i].size() * words[j].size()));
                }
            }
        }
        return res;

    }
};

T338. 比特位计数

class Solution {
public:
    vector<int> countBits(int num) {
        vector<int> res{0};
        for(int i=1; i<=num; ++i){
            if(i % 2 == 0) res.push_back(res[i/2]);
            else res.push_back(res[i/2]+1);
        }
        return res;

    }
};

LeetCode—树

递归
一棵树要么是空树,要么有两个指针,每个指针指向一棵树。树是一种递归结构,很多树的问题可以使用递归来处理。
T104. 二叉树的最大深度

class Solution {
public:
    int maxDepth(TreeNode* root) {
        if(root == NULL) return 0;
        return 1 + max(maxDepth(root->left), maxDepth(root->right));
    }
};

T110. 平衡二叉树

class Solution {
public:
    bool isBalanced(TreeNode *root) {
        if (root == NULL) return true;
        if (abs(getDepth(root->left) - getDepth(root->right)) > 1) return false;
        return isBalanced(root->left) && isBalanced(root->right);    
    }
    int getDepth(TreeNode *root) {
        if (root == NULL) return 0;
        return 1 + max(getDepth(root->left), getDepth(root->right));
    }
};

T543. 二叉树的直径

class Solution {
public:
    int diameterOfBinaryTree(TreeNode* root) {
        int res = 0;
        depth(root, res);
        return res;
    }
    int depth(TreeNode* root, int &res){
        if(!root)  return 0;
        int L = depth(root->left, res);
        int R = depth(root->right, res);
        res = max(res, L+R);
        return max(L, R)+1;
    }
    
};

T226. 翻转二叉树

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(!root)  return NULL;
        TreeNode* tmp = root->left;
        root->left = invertTree(root->right);
        root->right = invertTree(tmp);
        return root;

    }
};

T617. 合并二叉树

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        if(!t1)  return t2;
        if(!t2)  return t1;
        TreeNode* t = new TreeNode(t1->val + t2->val);
        t->left = mergeTrees(t1->left, t2->left);
        t->right = mergeTrees(t1->right, t2->right);
        return t;
    }
};

T112. 路径总和

class Solution {
public:
    bool hasPathSum(TreeNode* root, int sum) {
        if(!root)  return false;
        if(!root->left && !root->right && root->val == sum)  return true;
        return hasPathSum(root->left, sum-root->val) || hasPathSum(root->right, sum-root->val);
    }
};

T437. 路径总和 III

class Solution {
public:
    int pathSum(TreeNode* root, int sum) {
        if(root == NULL)  return 0;
        return sumUp(root, 0, sum) + pathSum(root->left, sum) + pathSum(root->right, sum);

    }
    int sumUp(TreeNode* root, int pre, int& sum){
        if(root == NULL)  return 0;
        int cur = pre + root->val;
        return (cur == sum) + sumUp(root->left, cur, sum) + sumUp(root->right, cur, sum);

    }
};

T572. 另一个树的子树

class Solution {
public:
    bool isSubtree(TreeNode* s, TreeNode* t) {
        if(!s)  return false;
        if(isSame(s, t))  return true;
        return isSubtree(s->left, t) || isSubtree(s->right, t);
        
    }
    bool isSame(TreeNode* s, TreeNode* t){
        if(!s && !t)  return true;
        if(!s || !t)  return false;
        if(s->val != t->val)  return false;
        return isSame(s->left, t->left) && isSame(s->right, t->right);
    }
};

T101. 对称二叉树

class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        return check(root, root);
    }

    bool check(TreeNode *p, TreeNode *q) {
        if (!p && !q) return true;
        if (!p || !q) return false;
        return p->val == q->val && check(p->left, q->right) && check(p->right, q->left);
    }
};
class Solution {
public:
    bool check(TreeNode *u, TreeNode *v) {
        queue <TreeNode*> q;
        q.push(u); 
        q.push(v);
        while (!q.empty()) {
            u = q.front(); q.pop();
            v = q.front(); q.pop();
            if (!u && !v) continue;
            if ((!u || !v) || (u->val != v->val)) return false;

            q.push(u->left); 
            q.push(v->right);

            q.push(u->right); 
            q.push(v->left);
        }
        return true;
    }

    bool isSymmetric(TreeNode* root) {
        return check(root, root);
    }
};

T111. 二叉树的最小深度

class Solution {
public:
    int minDepth(TreeNode* root) {
        if (root == NULL) return 0;
        // 当一个左子树为空,右不为空,这时并不是最低点
        if (root->left == NULL && root->right != NULL) {
            return 1 + minDepth(root->right);
        }
        // 当一个右子树为空,左不为空,这时并不是最低点
        if (root->left != NULL && root->right == NULL) {
            return 1 + minDepth(root->left);
        }
        return 1 + min(minDepth(root->left), minDepth(root->right));
    }
};

T404. 左叶子之和

class Solution {
public:
    int sumOfLeftLeaves(TreeNode* root) {
        if(!root)  return 0;
        if(root->left && !root->left->left && !root->left->right)
        return root->left->val + sumOfLeftLeaves(root->right);
        return sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right);

    }
};

T687. 最长同值路径

class Solution {
public:
    int longestUnivaluePath(TreeNode* root) {
        int res = 0;
        UnivaluePath(root, res);
        return res;
    }
    int UnivaluePath(TreeNode* node, int& res) {
        if (!node) return 0;
        int l = UnivaluePath(node->left, res);
        int r = UnivaluePath(node->right, res);
        int pl = 0;
        int pr = 0;
        if(node->left && node->val == node->left->val) 
        pl = l + 1;
        if(node->right && node->val == node->right->val) 
        pr = r + 1;
        res = max(res, pl + pr);
        return max(pl, pr);
    }

};

T337. 打家劫舍 III

class Solution {
public:
    int rob(TreeNode* root) {
        vector<int> res = dfs(root);
        return max(res[0], res[1]);

    }
    vector<int> dfs(TreeNode* root){
        if(!root)  return vector<int> (2,0);
        vector<int> left = dfs(root->left);
        vector<int> right = dfs(root->right);
        vector<int> res(2,0);
        res[0] = max(left[0], left[1]) + max(right[0], right[1]);
        res[1] = left[0] + right[0] + root->val;
        return res;


    }
};

T671. 二叉树中第二小的节点

class Solution {
public:
    int findSecondMinimumValue(TreeNode* root) {
        return helper(root, root->val);
    }
    int helper(TreeNode* node, int first) {
        if (!node) return -1;
        if (node->val != first) return node->val;
        int left = helper(node->left, first), right = helper(node->right, first);
        return (left == -1 || right == -1) ? max(left, right) : min(left, right);
    
    }
};

层次遍历
使用 BFS 进行层次遍历。不需要使用两个队列来分别存储当前层的节点和下一层的节点,因为在开始遍历一层的节点时,当前队列中的节点数就是当前层的节点数,只要控制遍历这么多节点数,就能保证这次遍历的都是当前层的节点。
T637. 二叉树的层次平均值

class Solution {
public:
    vector<double> averageOfLevels(TreeNode* root) {
        if(!root)  return {};
        vector<double> res;
        queue<TreeNode*> q{{root}};
        while(!q.empty()){
            int n=q.size();
            double sum=0;
            for(int i=0; i<n; ++i){
                TreeNode* t = q.front();
                q.pop();
                sum += t->val;
                if(t->left)  q.push(t->left);
                if(t->right)  q.push(t->right);
            }
            res.push_back(sum/n);
        }
        return res;

    }
};

T513. 找树左下角的值

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        int res=0;
        queue<TreeNode*> q{{root}};
        while(!q.empty()){
            int n=q.size();
            for(int i=0; i<n; ++i){
                TreeNode* t = q.front();
                q.pop();
                if(i == 0) res = t->val;
                if(t->left)  q.push(t->left);
                if(t->right)  q.push(t->right);
            }
        }
        return res;


    }
};

前中后序遍历
在这里插入图片描述
T144. 二叉树的前序遍历

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        if(!root)  return {};
        vector<int> res;
        stack<TreeNode*> s{{root}};
        while(!s.empty()){
            TreeNode* t = s.top();
            s.pop();
            res.push_back(t->val);
            if(t->right)  s.push(t->right);
            if(t->left)  s.push(t->left);
        }
        return res;


    }
};

T145. 二叉树的后序遍历

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        if(!root)  return {};
        vector<int> res;
        stack<TreeNode*> s{{root}};
        TreeNode* head = root;
        while(!s.empty()){
            TreeNode* t = s.top();
            if((!t->left && !t->right) || t->left == head || t->right == head){
                res.push_back(t->val);
                s.pop();
                head = t;
            }
            else{
                if(t->right) s.push(t->right);
                if(t->left) s.push(t->left);
            }
        }
        return res;

    }
};

T94. 二叉树的中序遍历

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> s;
        TreeNode* p = root;
        while(p || !s.empty()){
            while(p){
                s.push(p);
                p=p->left;
            }
            p=s.top();
            s.pop();
            res.push_back(p->val);
            p=p->right;
        }
        return res;
        
    }
};

BST
二叉查找树(BST):根节点大于等于左子树所有节点,小于等于右子树所有节点。
T669. 修剪二叉搜索树

class Solution {
public:
    TreeNode* trimBST(TreeNode* root, int L, int R) {
        if(!root) return NULL;
        if(root->val < L)  return trimBST(root->right, L, R);
        if(root->val > R)  return trimBST(root->left, L, R);
        root->left = trimBST(root->left, L, R);
        root->right = trimBST(root->right, L, R);
        return root;

    }
};

T230. 二叉搜索树中第k小的元素

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int kthSmallest(TreeNode* root, int k) {
        int cnt = 0;
        stack<TreeNode*> s{{root}};
        TreeNode* p = root;
        while(p || !s.empty()){
            while(p){
                s.push(p);
                p=p->left; 
            }           
            p = s.top();
            s.pop();
            ++cnt;
            if(cnt == k)  return p->val;
            p = p->right;
        }
        return 0;
        
        
    }
};

T538. 把二叉搜索树转换为累加树

class Solution {
public:
    TreeNode* convertBST(TreeNode* root) {
        int sum=0;
        helper(root, sum);
        return root;

    }
    void helper(TreeNode*& node, int & sum){
        if(!node) return;
        helper(node->right, sum);
        node->val += sum;
        sum = node->val;
        helper(node->left, sum);
    }
};

T235. 二叉搜索树的最近公共祖先

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(!root) return NULL;
        if(root->val > max(p->val, q->val)){
            return lowestCommonAncestor(root->left, p, q);
        }
        else if(root->val < min(p->val, q->val)){
            return lowestCommonAncestor(root->right, p, q);
        }
        else return root;

        
    }
};

T236. 二叉树的最近公共祖先

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(!root || p==root || q==root)  return root;
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right= lowestCommonAncestor(root->right, p, q);
        if(left && right) return root;
        return left ? left : right;
        
    }
};

T108. 将有序数组转换为二叉搜索树

class Solution {
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        return helper(nums, 0, (int)nums.size() -1);

    }
    TreeNode* helper(vector<int>& nums, int left, int right){
        if(left > right) return NULL;
        int mid = left + (right-left) / 2;
        TreeNode* cur = new TreeNode(nums[mid]);
        cur->left = helper(nums, left, mid-1);
        cur->right = helper(nums, mid+1, right);
        return cur;
    }
};

T109. 有序链表转换为二叉搜索树

class Solution {
public:
    TreeNode* sortedListToBST(ListNode* head) {
        if(!head)  return NULL;
        if(!head->next)  return new TreeNode(head->val);
        ListNode* slow = head;
        ListNode* fast = head;
        ListNode* last = slow;
        while(fast->next && fast->next->next){
            last = slow;
            slow = slow->next;
            fast = fast->next->next;
        }
        fast = slow->next;
        last->next = NULL;
        TreeNode* cur = new TreeNode(slow->val);
        if(head != slow) cur->left = sortedListToBST(head);
        cur->right = sortedListToBST(fast);
        return cur;

        
    }
};

T653. 两数之和 IV - 输入 BST

class Solution {
public:
    bool findTarget(TreeNode* root, int k) {
        unordered_set<int> st;
        return helper(root, k, st);
    }
    bool helper(TreeNode* node, int k, unordered_set<int>& st){
        if(!node)  return false;
        if(st.count(k-node->val))  return true;
        st.insert(node->val);
        return helper(node->left, k, st) || helper(node->right, k, st);
    }
};

T530. 二叉搜索树的最小绝对差

class Solution {
public:
    int getMinimumDifference(TreeNode* root) {
        int res = INT_MAX;
        int pre = -1;
        inorder(root, pre, res);
        return res;

    }
    void inorder(TreeNode* root, int& pre, int& res){
        if(!root)  return;
        inorder(root->left, pre, res);
        if(pre != -1)  res = min(res, root->val - pre);
        pre = root->val;
        inorder(root->right, pre, res);
    }
};

T501. 二叉搜索树的众数

class Solution {
public:
    vector<int> findMode(TreeNode* root) {
        vector<int> res;
        int mx = 0;
        unordered_map<int, int> m;
        inorder(root, m, mx);
        for(auto a : m){
            if(a.second == mx){
                res.push_back(a.first);
            }
        }
        return res;

    }
    void inorder(TreeNode* node, unordered_map<int, int>& m, int& mx){
        if(!node)  return;
        inorder(node->left, m, mx);
        mx = max(mx, ++m[node->val]);
        inorder(node->right, m, mx);
    }

};
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值