leetcode刷题

  1. 704:二分查找

  1. 35:搜索插入位置

想象一个for循环,两个指针,一个从左边开始往右,一个从右边开始往左,当while中left<=right的时候就是for循环中两个指针指向了中间位置,就像上面在nums[mid] >= target的时候right = mid – 1;也就是说,如果要返回right那就要返回right + 1。如果是left那就可以直接返回,因为left已经往右边移动一个位置了

  1. 34:在排序数组中查找元素的第一个和最后一个位置

下面是用二分法做的,也可以用暴力法的思路,就算左右边界都用for循环遍历数组,找到第一个nums[i]==target的时候就算左边界,右边界可以从右边往左遍历

class Solution {

public:

    vector<int> searchRange(vector<int>& nums, int target) {

        vector<int> res{-1, -1};

        res[0] = left(nums, target);

        res[1] = right(nums, target);

        return res;

    }  

    int left(vector<int>& nums, int target){

        int left = 0;

        int right = nums.size() -1;

        int ans = -1;

        while(left<=right){

            int mid = left + (right - left) / 2;

            if(nums[mid]>=target){

                if(nums[mid] == target) ans = mid;

                right = mid - 1;

            }else{

                left = mid + 1;

            }

        }

        return ans;

    }

    int right(vector<int>& nums, int target){

        int left = 0;

        int right = nums.size() -1;

        int ans = -1;

        while(left<=right){

            int mid = left + (right - left) / 2;

            if(nums[mid]<=target){

                if(nums[mid] == target) ans = mid;

                left = mid + 1;

            }else{

                right = mid - 1;

            }

        }

        return ans;

    }

};

  1. 69题

这里为什么是返回left-1呢,是因为mid <= x / mid的时候left = mid + 1;所以退出循环的时候left * left 会大于target,所以返回left – 1;,也可以返回right

这里为什么是返回left-1呢,是因为mid <= x / mid的时候left = mid + 1;所以退出循环的时候left * left 会大于target,所以返回left – 1;,也可以返回right

  1. 367:有效的完全平方数

public:

    bool isPerfectSquare(int num) {

        if(num == 1) return true;

        int left = 1;

        int right = num;

        while(left<=right){

            int mid = left + (right - left) / 2;

            if(mid <= num / mid){

                left = mid + 1;

            }else{

                right = mid - 1;

            }

        }

        return (right * right) == num;

    }

};

就像上面找边界一样,循环中如果mid*mid > num,那么right = mid – 1;所以退出循环的时候right * right 是<= num的,所以返回return (right * right) == num;

  1. 27:移除元素

class Solution {

public:

    int removeElement(vector<int>& nums, int val) {

        int slow = 0;

        for(int fast = 0; fast < nums.size(); ++fast){

            if(nums[fast]!=val){

                nums[slow++] = nums[fast];

            }

        }

        return slow;        

    }

};

直接快慢指针秒了

  1. 26:删除有序数组中的重复项

class Solution {

public:

    int removeDuplicates(vector<int>& nums) {

        int slow = 0;

        nums[slow++] = nums[0];

        for(int fast = 1; fast < nums.size(); fast++){

            if(nums[slow - 1] != nums[fast]){

                nums[slow++] = nums[fast];

            }

        }

        return slow;

    }

};

  1. 283:移动零

class Solution {

public:

    void moveZeroes(vector<int>& nums) {

        int count = 0;

        int n = nums.size();

        //count就是不为0的数量

        for(int i = 0; i < n; i++){

            if(nums[i]!=0){

                nums[count++] = nums[i];

            }

        }

        for(int i = count; i < n; i++){

            nums[count++] = 0;

        }

    }

};

  1. 844:比较含退格的字符串

class Solution {

public:

    bool backspaceCompare(string s, string t) {

        return outString(s) == outString(t);

    }

    string outString(const string& s){

        string res = "";

        for(int i = 0; i < s.size(); i++)

        {

            if(s[i] != '#'){

                res.push_back(s[i]);

            }else if(!res.empty()){

                res.pop_back();

            }

        }

        return res;

    }  

};

  1. 977:有序数组的平方

class Solution {

public:

    vector<int> sortedSquares(vector<int>& nums) {

        int size = nums.size();

        vector<int> res;

        res.resize(size);

       

        int left = 0;

        int right = size - 1;

        size--;

        while(left<=right){

            if(nums[left] * nums[left] >= nums[right] * nums[right]){

                res[size--] = nums[left] * nums[left];

                left++;

            }else{

                res[size--] = nums[right] * nums[right];

                right--;

            }

        }

        return res;

    }

};

  1. 209:长度最小的子数组

class Solution {

public:

    int minSubArrayLen(int target, vector<int>& nums) {

        int sum = 0;

        int count = 0;

        int ans = INT_MAX;

        for(int i = 0, j = 0; j < nums.size(); j++){

            sum += nums[j];

            while(sum >= target){

                count = j - i + 1;

                ans = count < ans ? count : ans;

                sum -= nums[i];

                i++;

            }

        }

        return ans != INT_MAX ? ans : 0;

        //暴力 无法完全通过测试用例18/21

        // int res = INT_MAX;

        // int length = 0;

        // for(int i = 0; i< nums.size(); i++){

        //     int sum = 0;

        //     for(int j = i; j < nums.size(); j++){            

        //         sum += nums[j];

        //         length = j - i + 1;

        //         if(sum >= target) {

        //             res = min(length,res);

        //             break;                

        //         }

        //     }

        // }

        // if(res == INT_MAX)  return 0;

        // return res;

    }

};

要注意提供的第三个测试用例,因为可能就数组所有元素加起来都不大于target,所以在最后要判断ans != INT_MAX ? ans : 0;

  1. 904:水果成篮

class Solution {

public:

    int totalFruit(vector<int>& fruits) {

        unordered_map<int, int> m_map;

        int ans = 0;

        int count = 0;

        for(int i=0, j=0; j < fruits.size(); j++){

            m_map[fruits[j]]++;

            while(m_map.size() > 2){

                int tmp = fruits[i];

                if(--m_map[tmp] == 0) m_map.erase(tmp);

                i++;              

            }

            count = j - i + 1;

            ans = count < ans ? ans : count;

        }

        return ans;

    }

};

思路:

  1. 螺旋矩阵2  这个题要注意必须给res进行初始化!

class Solution {

public:

    vector<vector<int>> generateMatrix(int n) {

        vector<vector<int>> res(n, vector<int>(n, 0));

        int up = 0, down = n - 1, left = 0, right = n -1;

        int count = 1;

        while(true){

            for(int i = left; i <= right; i++){

                res[up][i] = count++;

            }

            up++;

            if(up > down) break;

            for(int i = up; i <= down; i++){

                res[i][right]= count++;

            }

            right--;

            if(right < left)break;

            for(int i =right; i>=left; i--){

                res[down][i] =count++;

            }

            down--;

            if(down < up)break;

            for(int i = down; i >= up; i--){

                res[i][left]=count++;

            }

            left++;

            if(left > right)break;

        }

        return res;

    }

};

  1. 54:螺旋矩阵  注意行和列是怎么求出来的

class Solution {

public:

    vector<int> spiralOrder(vector<vector<int>>& matrix) {

        int m = matrix.size();

        int n = matrix[0].size();

        int up = 0, down = m-1, left = 0, right=n-1;

        vector<int> res;

        while(true){

            for(int i = left; i <= right; i++)  res.push_back(matrix[up][i]);

            up++;

            if(up > down)break;

            for(int i = up; i <=down; i++)  res.push_back(matrix[i][right]);

            right--;

            if(right < left)break;

            for(int i = right; i>=left; i--)    res.push_back(matrix[down][i]);

            down--;

            if(down < up)break;

            for(int i = down; i>=up; i--)   res.push_back(matrix[i][left]);

            left++;

            if(left > right)break;

        }

        return res;

    }

};

  1. 203:移除链表元素

class Solution {

public:

    ListNode* removeElements(ListNode* head, int val) {

        if(head == nullptr) return head;

        ListNode* dummyHead = new ListNode(0);

        dummyHead->next = head;

        ListNode* cur = dummyHead;

        while(cur->next != nullptr){

            if(cur->next->val == val){

                ListNode* tmp = cur->next;

                cur->next = cur->next->next;

                delete tmp;

            }else{

                cur = cur->next;

            }

        }

        return dummyHead->next;

    }

};

  1. 设计链表

class MyLinkedList {

    struct ListedNode {

        ListedNode(int i) : val(i), next(nullptr) {}

        int val;

        ListedNode* next;

    };

public:

    //下标是从0开始的

    MyLinkedList() : size_(0), dummyHead(new ListedNode(0)){}

    int get(int index){

        if(index > size_ -1  || index < 0)   return -1;

        ListedNode* cur = dummyHead->next;

     

        while(index--){

            cur = cur->next;

        }

        return cur->val;

    }

    void addAtHead(int val){

        ListedNode* newNode = new ListedNode(val);

        newNode->next = dummyHead->next;

        dummyHead->next = newNode;

        size_++;

    }

    void addAtTail(int val){

        ListedNode* newNode = new ListedNode(val);

        ListedNode* cur = dummyHead;

        int count = size_;

        while(count--){

            cur = cur->next;

        }

        cur->next = newNode;

        size_++;

    }

    void addAtIndex(int index, int val){

        if(index > size_ ) return;

        ListedNode* newNode = new ListedNode(val);

        ListedNode* cur = dummyHead;

        while(index--){

            cur = cur->next;

        }

        newNode->next = cur->next;

        cur->next = newNode;

        size_++;

    }

    void deleteAtIndex(int index){

        if(index > size_ - 1)   return;

        ListedNode* cur = dummyHead;

        while(index--){

            cur = cur->next;

        }

        ListedNode* tmp = cur->next;

        cur->next = cur->next->next;

        delete tmp;

        size_--;

    }

private:

    int size_;

    ListedNode* dummyHead;

};

注意

在这里最容易弄错的就是,下标是从0开始的,不是从1开始,我错在认为是1开始的下标,同时在addAtIndex的时候要注意判断条件是if(index > size_ ) return;而不是if(index > size_ - 1) return;这是因为有一个插入末尾的情况。

  1. 206 翻转链表

class Solution {

public:

    ListNode* reverseList(ListNode* head) {

        ListNode* pre = nullptr;

        ListNode* cur = head;

        ListNode* tmp;

        while(cur){

            tmp = cur->next;

            cur->next = pre;

            pre = cur;

            cur = tmp;

        }

        return pre;

    }

};

易错点是tmp要在循环内进行初始化而不是声明的时候

  1. 24:两两交换链表节点

class Solution {

public:

    ListNode* swapPairs(ListNode* head) {

        ListNode* dummyHead = new ListNode(0);

        dummyHead->next = head;

        ListNode* cur = dummyHead;

        while(cur->next && cur->next->next){

            ListNode* tmp = cur->next;

            ListNode* tmp1 = cur->next->next->next;

            cur->next = cur->next->next;

            cur->next->next = tmp;

            cur->next->next->next = tmp1;

            cur = cur->next->next;

        }

        return dummyHead->next;

    }

};

要注意的是:循环的条件和tmp、tmp1存的地址

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

class Solution {

public:

    ListNode* removeNthFromEnd(ListNode* head, int n) {

        ListNode* dummyHead = new ListNode(0);

        dummyHead->next = head;

        ListNode* cur = dummyHead;

        int count = 0;

        while(cur->next){

            count++;

            cur = cur->next;

        }

        int m = count - n;

        cur = dummyHead;

        while(m--){

            cur = cur->next;

        }

        ListNode* tmp = cur->next;

        cur->next = cur->next->next;

        delete tmp;

        return dummyHead->next;

    }

};

  1. 链表相交

class Solution {

public:

    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {

        unordered_set<ListNode*> m_set;

        ListNode* curA = headA;

        while(curA){

            m_set.insert(curA);

            curA = curA->next;

        }

        ListNode* curB = headB;

        while(curB){

            if(m_set.find(curB)!=m_set.end())   return curB;

            curB = curB->next;

        }

        return nullptr;

    }

};

  1. 142:链表相交2

class Solution {

public:

    ListNode *detectCycle(ListNode *head) {

        unordered_set<ListNode*> m_set;

        ListNode* cur = head;

        while(cur){

            if(m_set.find(cur) != m_set.end()) return cur;

            m_set.insert(cur);

            cur = cur->next;

        }

        return nullptr;

    }

};

注意别忘了让cur=cur->next;

  1. 136:只出现一次的数字

class Solution {

public:

    int singleNumber(vector<int>& nums) {

        int res = 0;

        for(int n : nums){

            res ^= n;

        }

        return res;

    }

};

这里用的异或操作,a ^ 0 = a; a ^ a = 0;  a ^ b = c; c ^ b = a;

所以res ^ n会留下只出现一次的数字,因为其他都是两次,所以a ^ a = 0;

  1. 只出现一次的数字2

class Solution {

public:

    int singleNumber(vector<int> &nums) {

        int res = 0;

        for(int i = 0; i < 32; i++){

            int count = 0;

            for(int n : nums){

                count += n >> i & 1;

            }

            if(count % 3) res = res | 1 << i;

        }

        return res;

    }

};

把每个元素转换成二进制,由于同一个数字要么有3个要么就是一个,所以转成二进制后每一位上的1%3要么为0要么为1,可以用左移和右移来记录

for(int n : nums){

count += n >> i & 1;

} 以上是算每个数字在第i位上的1的数量,n>>i是把对应第i位的数字移动到最低位,然后 & 1,1是最低位的,1 & 1为1,1&0为0,按照这个策略计算数量。 if(count % 3) res = res | 1 << i; 这里是让1 << i,也就是让1 左移回到原来的位置,然后和res进行或操作

  1. 有效的字母异位词

class Solution {

public:

    bool isAnagram(string s, string t) {

        int sSize = s.size();

        int tSize = t.size();

        if(sSize != tSize)  return false;

        unordered_map<char, int> m_map;

        for(char ch = 'a'; ch <= 'z'; ch++){

            m_map[ch]=0;

        }

        for(int i = 0; i < sSize; i++){

            m_map[s[i]]++;

        }

        for(int i = 0; i < tSize; i++){

            m_map[t[i]]--;

        }

        for(auto it : m_map){

            if(it.second != 0)  return false;

        }

        return true;

    }

};

思路:用m_map获取a z 的键值对,然后对s进行++,对t进行--,在进行对应处理

  1. 383:赎金信

class Solution {

public:

    bool canConstruct(string ransomNote, string magazine) {

        int rSize = ransomNote.size();

        int mSize = magazine.size();

        if(rSize > mSize) return false;

        unordered_map<char, int> m_map;

        for(char ch = 'a'; ch <= 'z'; ch++){

            m_map[ch] = 0;

        }

        for(int i = 0; i < rSize; i++){

            m_map[ransomNote[i]]++;

        }

        for(int i = 0; i< mSize; i++){

            m_map[magazine[i]]--;

        }

        for(auto it : m_map){

            if(it.second > 0) return false;

        }

        return true;

    }

};

别搞错返回条件了,一开始if(rSize > mSize) return false;写成if(rSize < mSize) return false;

  1. 15:三数之和

class Solution {

public:

    vector<vector<int>> threeSum(vector<int>& nums) {

        //先确定一个,然后用左右指针确定后面两个

        sort(nums.begin(), nums.end());

        vector<vector<int>> res;

        for(int i = 0; i < nums.size(); i++){

            if(i > 0 && nums[i] == nums[i-1]) continue;

            int tmp = 0 - nums[i];

            for(int left = i + 1, right = nums.size() - 1; left < right;){

                if(tmp == nums[left] + nums[right]){

                    res.push_back({nums[i], nums[left], nums[right]});

                    while(left < right && nums[left] == nums[left+1])left++;

                    left++;

                    while(left < right && nums[right] == nums[right-1])right--;

                    right--;

                }else if(tmp < nums[left] + nums[right]){

                    right--;

                }else{

                    left++;

                }

            }

        }

        return res;

    }

};

  1. 1:两数之和

class Solution {

public:

    vector<int> twoSum(vector<int>& nums, int target) {

        unordered_map<int,int> m_map;

        for(int i = 0; i < nums.size(); i++){

            if(m_map.find(target - nums[i]) != m_map.end()){

                return {i, m_map[target-nums[i]]};

            }else{

                m_map.insert(pair<int,int>(nums[i],i));

            }

           

        }

        return {-1, -1};

    }

};

  1. 349:两个数组的交集

class Solution {

public:

    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {

        unordered_set<int> m_set(nums1.begin(), nums1.end());

        unordered_set<int> tmp(nums2.begin(), nums2.end());

        vector<int> res;

        for(int n : tmp){

            if(m_set.find(n)!=m_set.end()){

                res.push_back(n);

            }

        }

        return res;

    }

};

  1. 350:

class Solution {

public:

    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {

        int size1 = nums1.size();

        int size2 = nums2.size();

        vector<int> res;

        if(size1 < size2) return intersect(nums2, nums1);

        unordered_map<int ,int> m_map;

        for(int n : nums2)  m_map[n]++;

        for(int i = 0; i < nums1.size(); i++){

            if(m_map.find(nums1[i])!=m_map.end() && m_map[nums1[i]]>0){

                res.push_back(nums1[i]);

                m_map[nums1[i]]--;

            }

        }

        return res;

    }

};

找到size更小的那个容器,然后用m_map保存值和出现次数,之后去另一个数组找对应出现的值,同时要进行对应的--操作,注意对应值得数量要>0才行

  1. 202:快乐数

class Solution {

public:

    bool isHappy(int n) {

        unordered_set<int> m_set;

        while(true){

            int tmp = getSum(n);

            if(tmp == 1){

                return true;

            }else if(m_set.find(tmp)!=m_set.end()){

                return false;

            }else{

                m_set.insert(tmp);

                n=tmp;

            }

        }

        return false;

    }

    int getSum(int n){

        int sum = 0;

        while(n){

            int tmp = n % 10;

            sum += tmp * tmp;

            n/=10;

        }

        return sum;

    }

};

  1. 18:四数之和

class Solution {

public:

    vector<vector<int>> fourSum(vector<int>& nums, int target) {

        vector<vector<int>> res;

        sort(nums.begin(), nums.end());

        for(int i = 0; i < nums.size(); i++){

            if(i > 0 && nums[i] == nums[i-1])    continue;

            for(int j = i + 1; j < nums.size(); j++){

                if(j > i+1 && nums[j] == nums[j-1]) continue;

                int left = j + 1;

                int right = nums.size() - 1;

                long tmp = (long)target - nums[i] - nums[j];

                while(left<right){

                    if(tmp == nums[left] + nums[right]){

                        res.push_back({nums[i], nums[j], nums[left], nums[right]});

                        while(left < right && nums[left]==nums[left+1]) left++;

                        left++;

                        while(left < right && nums[right] == nums[right-1]) right--;

                        right--;

                    }else if(tmp < nums[left] + nums[right]){

                        right--;

                    }else{

                        left++;

                    }

                }

            }

        }

        return res;

    }

};

思路:先用sort去给数组进行排序,这点很重要,然后确定第一个和第二个数字,再确定后面的两个数字

  1. 454:四数相加2

class Solution {

public:

    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {

        //先把两个数组中所有数字的和放到unordered_map里,key为和,value为同一个数字出现的次数

        //然后在剩下两个数组中找有多少和m_map中的键相加为0的值,然后count加上key的次数

        unordered_map<int,int> m_map;

        int count = 0;

        for(int n : nums1){

            for(int k : nums2){

                m_map[n+k]++;

            }

        }

        for(int n : nums3){

            for(int k : nums4){

                if(m_map.find(0 - n - k) != m_map.end()){

                    count += m_map[0 - n - k];

                }

            }

        }

        return count;

    }

};

  1. 344:翻转字符串

class Solution {

public:

    void reverseString(vector<char>& s) {

        for(int slow = 0, fast = s.size()-1; slow < fast; slow++, fast--){

            s[slow] = s[slow] ^ s[fast];

            s[fast] = s[slow] ^ s[fast];

            s[slow] = s[slow] ^ s[fast];

        }

    }

};

可以使用双指针,也可以使用异或操作

  1. 翻转字符串2

class Solution {

public:

    string reverseStr(string s, int k) {

        int size = s.size();

       

        for(int i = 0; i < size; i += 2 * k){

            if(size - i >= 2 * k){

                reverse(s.begin() + i, s.begin() + i+k);

            }else if(size - i >= k){

                reverse(s.begin()+i, s.begin() + i+k);

            }else{

                reverse(s.begin() + i, s.begin() + size);

            }

        }

        return s;

    }

};

第二种解法:

class Solution {

public:

    string reverseStr(string s, int k) {

        int length = s.size();

        for(int i = 0; i < length; i += 2*k){

            reverse(s.begin()+i, s.begin() + min(i+k, length));

        }

        return s;

    }

};

  1. 151:反转字符串中的单词

第一种解法:

class Solution {

public:

    string reverseWords(string s) {

        stack<string> m_str;

        string res = "";

        for(int i=0; i < s.size(); i++){

            if(s[i] != ' '){

                res += s[i];

            }else if(res != ""){

                m_str.push(res);

                res = "";

            }

        }

        if(res != "")

            m_str.push(res);

        string m_res = "";

        while(m_str.size() != 0){

            m_res += m_str.top();

            m_str.pop();

            m_res.push_back(' ');

        }

        m_res.pop_back();

        return m_res;

       

    }

};

第二种解法:

class Solution {

public:

    string reverseWords(string s) {

        vector<string> res;

        string ss;

        string tmp = "";

        //把单词一个一个装到tmp,然后放到res

        for(int i = 0; i < s.size(); i++){

            if(s[i]!= ' '){

                tmp += s[i];

            }else if(tmp != ""){

                res.push_back(tmp);

                tmp = "";//要将tmp置空

            }

        }

        if(tmp != "")   res.push_back(tmp);//要注意最后一个单词后面没有空格,所以循环后单独加到res

        for(int i = res.size()-1; i >=0; i--){//注意是 i>=0,如果是i>0就会少第一个单词

            ss += res[i];

            //加空格

            if(i != 0){

                ss += ' ';

            }

       

        }

        return ss;

    }

};

  1. 28:找出字符串第一个匹配项的下标

class Solution {

public:

    int strStr(string haystack, string needle) {

        int hSize = haystack.size();

        int nSize = needle.size();

        if(hSize < nSize)   return -1;

        for(int i = 0; i <= hSize - nSize; i++){

            string tmp = "";

            for(int j = i; j < i + nSize; j++){

                tmp += haystack[j];

            }

            if(tmp == needle)return i;

        }

        return -1;

    }

};

里主要出错的就是边界问题,I 和 j容易弄错边

  1. 459:重复的子字符串

    bool repeatedSubstringPattern(string s) {

        return (s + s).find(s, 1) != s.size();

    }

};

思路:如果是重复字符串,那么(s + s)也是重复字符串,所以find(s, 1)得到的下标就不会为s的开始,也就是s.size()

  1. 20:有效的括号

class Solution {

public:

    bool isValid(string s) {

        stack<char> m_stack;

        for(int i = 0; i < s.size(); i++){

            if(s[i] == '(') m_stack.push(')');

            else if(s[i] == '[') m_stack.push(']');

            else if(s[i] == '{') m_stack.push('}');

            else if(m_stack.empty() || s[i] != m_stack.top())   return false;

            else{

                m_stack.pop();

            }

        }

        return m_stack.empty();

    }

};

注意返回的是m_stack.empty()

  1. 1047:删除字符串中的所有相邻重复项

class Solution {

public:

    string removeDuplicates(string s) {

        stack<char> m_stack;

        string res ="";

        for(int i = 0; i < s.size(); i++){

            if(m_stack.empty()){

                m_stack.push(s[i]);

            }else if(!m_stack.empty() && m_stack.top() == s[i]){

                m_stack.pop();

            }else{

                m_stack.push(s[i]);

            }

        }

        while(m_stack.size() != 0){

            res.push_back(m_stack.top());

            m_stack.pop();

        }

        reverse(res.begin(), res.end());

        return res;

    }

};

主要用栈来解决

  1. 150:逆波兰表达式求值

class Solution {

public:

    int evalRPN(vector<string>& tokens) {

        stack<int> ss;

        for(int i = 0; i < tokens.size(); i++){

            int left=0,right=0, sum=0;

            if(tokens[i] == "+"){

                right = ss.top();

                ss.pop();

                left = ss.top();

                ss.pop();

                sum = left + right;

                ss.push(sum);

            }else if(tokens[i] == "-"){

                right = ss.top();

                ss.pop();

                left = ss.top();

                ss.pop();

                sum = left - right;

                ss.push(sum);

            }else if(tokens[i] == "*"){

                right = ss.top();

                ss.pop();

                left = ss.top();

                ss.pop();

                sum = left * right;

                ss.push(sum);

               

            }else if(tokens[i] == "/"){

                right = ss.top();

                ss.pop();

                left = ss.top();

                ss.pop();

                sum = left / right;

                ss.push(sum);

               

            }else{

                ss.push(stoi(tokens[i]));

            }

        }

        return ss.top();

    }

};

  1. 146:LRU缓存

class LRUCache {

public:

    struct Node {

        int key;

        int val;

        Node* pre;

        Node* next;

        Node() : key(0), val(0), pre(nullptr), next(nullptr) {}

        Node(int k, int v) : key(k), val(v), pre(nullptr), next(nullptr) {}

    };

    int capacity;

    std::unordered_map<int, Node*> m_map;

    Node* head;

    Node* tail;

    LRUCache(int capacity) {

        this->capacity = capacity;

        head = new Node();

        tail = new Node();

        head->next = tail;

        tail->pre = head;

    }

    int get(int key) {

        if (m_map.find(key) != m_map.end()) {

            Node* node = m_map[key];

            moveToTail(node);

            return node->val;

        }

        return -1;

    }

    void put(int key, int value) {

        if (m_map.find(key) != m_map.end()) {

            Node* node = m_map[key];

            node->val = value;

            moveToTail(node);

        } else {

            if (m_map.size() >= capacity) {

                removeHead();

            }

            Node* node = new Node(key, value);

            m_map[key] = node;

            addToTail(node);

        }

    }

    void moveToTail(Node* node) {

        // Remove node from current position

        node->pre->next = node->next;

        node->next->pre = node->pre;

        // Insert node at the tail

        node->next = tail;

        node->pre = tail->pre;

        tail->pre->next = node;

        tail->pre = node;

    }

    void removeHead() {

        Node* node = head->next;

        head->next = node->next;

        node->next->pre = head;

        m_map.erase(node->key);

        delete node;

    }

    void addToTail(Node* node) {

        node->next = tail;

        node->pre = tail->pre;

        tail->pre->next = node;

        tail->pre = node;

    }

};

  1. 347:前K个高频元素

class Solution {

public:

    class small{

        public:

        bool operator()(const pair<int,int>& l, const pair<int,int>& r){

            return l.second > r.second;//优先级低的在堆顶,优先出队列

        }

    };

    vector<int> topKFrequent(vector<int>& nums, int k) {

        unordered_map<int,int> m_map;

        for(int n : nums){

            m_map[n]++;

        }

        priority_queue<pair<int,int>, vector<pair<int,int>>, small> m_que;

        for(auto it = m_map.begin(); it != m_map.end(); ++it){

            m_que.push(pair<int,int>(it->first, it->second));

            if(m_que.size() > k){

                m_que.pop();

            }

        }

        vector<int> res;

        for(int i = 0; i < k; i++){

            res.push_back(m_que.top().first);

            m_que.pop();

        }

        return res;

    }

};

要注意小顶堆的设置,也就是仿函数

  1. 144:二叉树的前序遍历

class Solution {

    void treeTraversal(TreeNode* root, vector<int>& res){

        if(root == nullptr) return;

        //

        res.push_back(root->val);

        //

        treeTraversal(root->left, res);

        //

        treeTraversal(root->right, res);

    }

public:

    vector<int> preorderTraversal(TreeNode* root) {

        vector<int> res;

        //treeTraversal(root, res);//递归法

        //迭代法  前序遍历是中左右,所以一开始根节点放进去之后处理要让右节点先入栈,这样才能保证中左右吗,不然就是中右左了

        stack<TreeNode*> m_stack;

        if(root == nullptr) return res;

        m_stack.push(root);

        while(m_stack.size()!=0){

            TreeNode* tmp = m_stack.top();

            res.push_back(tmp->val);

            m_stack.pop();

            if(tmp->right != nullptr)   m_stack.push(tmp->right);

            if(tmp->left != nullptr)    m_stack.push(tmp->left);

        }

        return res;

    }

};

  1. 145:二叉树的后序遍历

class Solution {

    void treeTraversal(TreeNode* root, vector<int>& res){

        if(root == nullptr) return;     

        //

        treeTraversal(root->left, res);

        //

        treeTraversal(root->right, res);

        //

        res.push_back(root->val);

    }

public:

    vector<int> postorderTraversal(TreeNode* root) {

        vector<int> res;

        //treeTraversal(root, res);//递归法

        //以下是迭代法 前序是中左右,后序是左右中,所以可以先中右左,存到res后,逆序排列res,就是左右中

        if(root == NULL) return res;

        stack<TreeNode*> m_stack;

        m_stack.push(root);

        while(!m_stack.empty()){

            TreeNode* node = m_stack.top();

            m_stack.pop();

            res.push_back(node->val);

            //中右左,所以先放左再放右

            if(node->left)  m_stack.push(node->left);

            if(node->right) m_stack.push(node->right);

        }

        //最后要翻转数组,不然就是中右左

        reverse(res.begin(), res.end());

        return res;

    }

};

  1. 94:二叉树的中序遍历

class Solution {

public:

    void treeTraversal(TreeNode* root, vector<int>& res){

        if(root == nullptr) return;

        //

        treeTraversal(root->left, res);

        //

        res.push_back(root->val);      

        //

        treeTraversal(root->right, res);

    }

    vector<int> inorderTraversal(TreeNode* root) {

        vector<int> res;

        //treeTraversal(root, res);//递归法

        //迭代法,中序是 左中右

        stack<TreeNode*> m_stack;

        TreeNode* cur = root;

        while(cur != NULL || !m_stack.empty()){

            if(cur != NULL){

                m_stack.push(cur);

                cur = cur->left;//

            }else{

                cur = m_stack.top();

                m_stack.pop();

                res.push_back(cur->val);//

                cur = cur->right;

            }

        }

        return res;

    }

};

  1. 192:将字符串转成整数

class Solution {

public:

    int myAtoi(string str) {

        int size = str.size();

        int i = 0;

        while(str[i]==' ') i++;

        int flag = 1;

        if(str[i] == '+'){

            i++;

        }else if(str[i] == '-'){

            flag = -1;

            i++;

        }

        long sum = 0;

        for( ; i < size; i++){

            if(str[i] < '0' || str[i] > '9'){

                return sum;

            }

            sum = sum * 10 + flag * (str[i] - '0');

            if(sum >= INT_MAX && flag == 1) return INT_MAX;

            if(sum < INT_MIN && flag == -1) return INT_MIN;

        }

        return sum;

    }

};

  1. 102:二叉树的层序遍历

class Solution {

public:

    vector<vector<int>> levelOrder(TreeNode* root) {

        vector<vector<int>> res;

        if(root == nullptr) return res;

        queue<TreeNode*> m_que;

        m_que.push(root);

        while(!m_que.empty()){

            vector<int> m_res;

            int size = m_que.size();

            for(int i = 0; i < size; i++){

                TreeNode* tmp = m_que.front();

                m_que.pop();

                m_res.push_back(tmp->val);

                if(tmp->left != nullptr)    m_que.push(tmp->left);

                if(tmp->right != nullptr)   m_que.push(tmp->right);

            }

            res.push_back(m_res);

        }

        return res;

    }

};

注意,递归去进行前、中、后序遍历,递归可以做的栈也可以做,所以也可以使用栈去进行迭代遍历,进行前、中、后序遍历

  1. 107:二叉树的层序遍历2

class Solution {

public:

    vector<vector<int>> levelOrderBottom(TreeNode* root) {

        vector<vector<int>> res;

        queue<TreeNode*> m_que;

        if(root == nullptr) return res;

        m_que.push(root);

        while(m_que.size()!=0){

            vector<int> m_res;

            int size = m_que.size();

            for(int i = 0; i < size; i++){

                TreeNode* tmp = m_que.front();

                m_que.pop();

                m_res.push_back(tmp->val);

                if(tmp->left != nullptr)    m_que.push(tmp->left);

                if(tmp->right != nullptr)   m_que.push(tmp->right);

            }

            res.push_back(m_res);

        }

        reverse(res.begin(), res.end());

        return res;

    }

};

思路就是,层序遍历后逆序一下

  1. 199:二叉树的右视图

class Solution {

public:

    vector<int> rightSideView(TreeNode* root) {

        vector<int> res;

        if(root == nullptr) return res;

        queue<TreeNode*> m_que;

        m_que.push(root);

        while(m_que.size() != 0){

            int size = m_que.size();

            for(int i = 0; i < size; i++){

                TreeNode* tmp = m_que.front();

                m_que.pop();

                if(i == size - 1){

                    res.push_back(tmp->val);

                }

                if(tmp->left != nullptr) m_que.push(tmp->left);

                if(tmp->right != nullptr)   m_que.push(tmp->right);

            }          

        }

        return res;

    }

};

  1. 637:二叉树的层平均值

class Solution {

public:

    vector<double> averageOfLevels(TreeNode* root) {

        vector<double> res;

        if(root == nullptr) return res;

        queue<TreeNode*> m_que;

        m_que.push(root);

        while(m_que.size() != 0){

            int size = m_que.size();

            double sum = 0;

            for(int i = 0; i < size; i++){

                TreeNode* tmp = m_que.front();

                m_que.pop();

                sum += tmp->val;

                if(tmp->left != nullptr)    m_que.push(tmp->left);

                if(tmp->right != nullptr)   m_que.push(tmp->right);

            }

            res.push_back(sum / size);

        }

        return res;

    }

};

注意:要记得pop()

  1. 429N叉树的层序遍历

class Solution {

public:

    vector<vector<int>> levelOrder(Node* root) {

        vector<vector<int>> res;

        if(root == nullptr) return res;

        queue<Node*> m_que;

        m_que.push(root);

        while(m_que.size() != 0){

            int size = m_que.size();

            vector<int> m_res;

            for(int i = 0; i < size; i++){

                Node* tmp = m_que.front();

                m_que.pop();

                m_res.push_back(tmp->val);

                for(Node* n : tmp->children){

                    m_que.push(n);                  

                }

            }

            res.push_back(m_res);

        }

        return res;

    }

};

注意:这里和二叉树层序遍历的思路类似,只是需要在加入节点的时候把Node里面的children都放到队列,可以用for直接遍历

  1. 515:在每个树中找最大值

class Solution {

public:

    vector<int> largestValues(TreeNode* root) {

        vector<int> res;

        if(root == nullptr) return res;

        queue<TreeNode*> m_que;

        m_que.push(root);

        while(m_que.size()!=0){

            int size = m_que.size();

            int max = INT_MIN;

            for(int i = 0; i < size; i++){

                TreeNode* tmp = m_que.front();

                m_que.pop();

                max = max > tmp->val ? max : tmp->val;

                if(tmp->left != nullptr)    m_que.push(tmp->left);

                if(tmp->right != nullptr)   m_que.push(tmp->right);

            }

            res.push_back(max);

        }

        return res;

    }

};

  1. 116:填充每个节点的下一个右侧节点指针

class Solution {

public:

    Node* connect(Node* root) {

        if(root == nullptr)  return root;

        Node* pre = nullptr;

        Node* cur = nullptr;

        queue<Node*> m_que;

        m_que.push(root);

        while(m_que.size() != 0){

            int size = m_que.size();

            for(int i = 0; i < size; i++){

                if(i == 0){

                    pre = m_que.front();

                    m_que.pop();

                }else{

                    cur = m_que.front();

                    m_que.pop();

                    pre->next = cur;

                    pre = cur;

                }

                if(pre->left != nullptr) m_que.push(pre->left);

                if(pre->right != nullptr) m_que.push(pre->right);

            }

            pre->next = nullptr;

        }

        return root;

    }

};

注意:这里要用到层序遍历和快慢指针的思想,每一层都用快慢指针来设置next的指向

  1. 117:填充每个节点的下一个右侧节点指针2

class Solution {

public:

    Node* connect(Node* root) {

        if(root == nullptr) return root;

        Node* pre = nullptr;

        Node* cur = nullptr;

        queue<Node*> m_que;

        m_que.push(root);

        while(!m_que.empty()){

            int size = m_que.size();

            for(int i = 0; i < size; i++){

                if(i == 0){

                    pre = m_que.front();

                    m_que.pop();

                }else{

                    cur = m_que.front();

                    m_que.pop();

                    pre->next = cur;

                    pre = cur;

                }

                if(pre->left != nullptr) m_que.push(pre->left);

                if(pre->right != nullptr) m_que.push(pre->right);

            }

            pre->next = nullptr;

        }

        return root;

    }

};

注意这题和上面那题思路一样,都是层序遍历加快慢指针,上面那题是完美二叉树,这题是普通的二叉树,不过都是一样的代码。

  1. 104:二叉树的最大深度

class Solution {

public:

    int maxDepth(TreeNode* root) {

        if(root == nullptr) return 0;

        int count = 0;

        queue<TreeNode*> m_que;

        m_que.push(root);

        while(m_que.size() != 0){

            int size = m_que.size();

            count++;

            for(int i = 0; i < size; i++){

                TreeNode* tmp = m_que.front();

                m_que.pop();

                if(tmp->left != nullptr) m_que.push(tmp->left);

                if(tmp->right != nullptr) m_que.push(tmp->right);

            }

        }

        return count;

    }

};

  1. 111:二叉树的最小深度

class Solution {

public:

    int minDepth(TreeNode* root) {

        if(root == nullptr)return 0;

        int count =0;

        queue<TreeNode*> m_que;

        m_que.push(root);

        while(m_que.size()!=0){

            count++;

            int size = m_que.size();

            for(int i = 0; i <size;i++){

                TreeNode* cur = m_que.front();

                m_que.pop();

                if(cur->left==nullptr && cur->right == nullptr) return count;

                if(cur->left!=nullptr)m_que.push(cur->left);

                if(cur->right!=nullptr)m_que.push(cur->right);

            }

        }

        return count;

    }

};

注意:有一个节点的左右节点都是空那就是没子树了

  1. 226:反转二叉树

class Solution {

public:

    void reverseTree(TreeNode* cur){

        if(cur == nullptr)return;

        swap(cur->left, cur->right);

        reverseTree(cur->left);

        reverseTree(cur->right);

    }

    TreeNode* invertTree(TreeNode* root) {

        if(root == nullptr)return root;

        //reverseTree(root);//递归法

        queue<TreeNode*> m_que;

        m_que.push(root);

        while(m_que.size() != 0){

            int size= m_que.size();

            for(int i = 0; i < size; i++){

                TreeNode* tmp = m_que.front();

                m_que.pop();

                swap(tmp->left, tmp->right);

                if(tmp->left != nullptr) m_que.push(tmp->left);

                if(tmp->right != nullptr) m_que.push(tmp->right);

            }

        }

        return root;

    }

};

注意:这里有两种方法:递归和层序,主要思想就是交换每个节点的左右指针的值

  1. 完全二叉树的节点个数

class Solution {

public:

    int countNodes(TreeNode* root) {

        int count = 0;

        if(root == nullptr) return count;

        queue<TreeNode*> m_que;

        m_que.push(root);

        while(m_que.size()!=0){

            int size = m_que.size();

            for(int i = 0; i < size; i++){

                TreeNode* tmp = m_que.front();

                m_que.pop();

                count++;

                if(tmp->left != nullptr) m_que.push(tmp->left);

                if(tmp->right != nullptr) m_que.push(tmp->right);

            }

        }

        return count;

    }

};

思路:层序遍历,不管你是二叉树还是完全二叉树,没遍历一个节点就count++

  1. 110平衡二叉树

class Solution {

public:

    int getCount(TreeNode* node){

        int count = 0;

        if(node == nullptr) return 0;

        queue<TreeNode*> m_Lque;

        m_Lque.push(node);

        while(m_Lque.size()!=0){

            int size = m_Lque.size();          

            count++;

            for(int i = 0; i < size; i++){

                TreeNode* cur = m_Lque.front();

                m_Lque.pop();

                if(cur->left != nullptr) m_Lque.push(cur->left);

                if(cur->right != nullptr) m_Lque.push(cur->right);

            }          

        }

        return count;

    }

    bool isBalanced(TreeNode* root) {

        int lCount = 0;

        int rCount = 0;

        if(root == nullptr) return true;

        //计算左子树深度

        lCount = getCount(root->left);

        //计算右子树深度

        rCount = getCount(root->right);

        return abs(lCount - rCount) <= 1 && isBalanced(root->left) && isBalanced(root->right);

    }

};

注意看返回条件,这可不是只判断abs(lCount - rCount) <= 1。因为平衡二叉树的定义是每个节点的左右子树的高度差不大于1,所以如果只是abs(lCount - rCount) <= 1的话就只看了根节点,这是错的,只能通过百分之九十的测试用例。正确的是return abs(lCount - rCount) <= 1 && isBalanced(root->left) && isBalanced(root->right);

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值