力扣刷题续

79.实现strStr(KMP)

力扣刷题续_第1张图片

方法一 .常规方法

class Solution {
public:
    int strStr(string haystack, string needle) {
        if(haystack.empty() && needle.empty())  return 0;
        int m = haystack.length();
        int n = needle.length();
        for(int i=0;i+n<=m;++i)
        {
            bool flag = true;
            for(int j=0;j

方法二.KMP算法

【宫水三叶】简单题学 KMP 算法 - 实现 strStr() - 力扣(LeetCode) (leetcode-cn.com)

class Solution {
public:
    int strStr(string haystack, string needle) {
        int n = haystack.size();
        int m = needle.size();
        if(m == 0)  return 0;
        vector next(m);
        for(int i=1,j=0;i0 && needle[i] != needle[j])
            {
                j = next[j-1];
            }
            if(needle[i] == needle[j])
            {
                ++j;
            }
            next[i] = j;
        }
        for(int i =0,j=0;i0 && haystack[i] != needle[j])
            {
                j = next[j-1];
            }
            if(haystack[i] == needle[j])
            {
                ++j;
            }
            if(j == m)
            {
                return i-m+1;
            }
        }
        return -1;
    }
}

80.字符串转换整数(atoi)

力扣刷题续_第2张图片

class Solution {
public:
    int myAtoi(string s) {
        int n = s.length();
        if(n == 0)  return 0;

        int index = 0;
        while(index Integer.MAX_VALUE
            但是 *10 和 + digit 都有可能越界,所有都移动到右边去就可以了。*/
            if(ans > (INT_MAX-num)/10)
            {
                return flag?INT_MAX:INT_MIN;
            }
            ans = ans*10+num;
            index++;
        }
        return flag?ans:-ans;
    }
};

 81.三数之和(双指针)

力扣刷题续_第3张图片

class Solution {
public:
    vector> threeSum(vector& nums) 
    {
        int size = nums.size();
        if (size < 3)   return {};          // 特判
        vector >res;            // 保存结果(所有不重复的三元组)
        std::sort(nums.begin(), nums.end());// 排序(默认递增)
        for (int i = 0; i < size; i++)      // 固定第一个数,转化为求两数之和
        {
            if (nums[i] > 0)    return res; // 第一个数大于 0,后面都是递增正数,不可能相加为零了
            // 去重:如果此数已经选取过,跳过
            if (i > 0 && nums[i] == nums[i-1])  continue;
            // 双指针在nums[i]后面的区间中寻找和为0-nums[i]的另外两个数
            int left = i + 1;
            int right = size - 1;
            while (left < right)
            {
                if (nums[left] + nums[right] + nums[i] > 0)
                    right--;    // 两数之和太大,右指针左移
                else if (nums[left] + nums[right] + nums[i] < 0)
                    left++;     // 两数之和太小,左指针右移
                else
                {
                    // 找到一个和为零的三元组,添加到结果中,左右指针内缩,继续寻找
                    res.push_back({nums[i], nums[left], nums[right]});
                    left++;
                    right--;
                    // 去重:第二个数和第三个数也不重复选取
                    // 例如:[-4,1,1,1,2,3,3,3], i=0, left=1, right=5
                    while (left < right && nums[left] == nums[left-1])  left++;
                    while (left < right && nums[right] == nums[right+1])    right--;
                }
            }
        }
        return res;
    }
};

82.最接近的三数之和(双指针)

力扣刷题续_第4张图片

class Solution {
public:
    int threeSumClosest(vector& nums, int target) {
        int n = nums.size();
        sort(nums.begin(),nums.end());
        int pre = nums[0]+nums[1]+nums[2];
        for(int i = 0;i target)    --right;
                else if(cur < target)   ++left;
                else return target;
            }
        }
        return pre;
    }
};

 83.反转链表II

力扣刷题续_第5张图片

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        ListNode* newhead = new ListNode();
        newhead->next = head;
        ListNode* pre = newhead;
        for(int i=0;inext;
        }
        ListNode* cur = pre->next;
        ListNode* next;
        for(int i=0;inext;
            cur->next = next->next;
            next->next = pre->next;
            pre->next = next;
        }
        return newhead->next;
    }
};

84.和为K的子数组

力扣刷题续_第6张图片

力扣刷题续_第7张图片

class Solution {
public:
    int subarraySum(vector& nums, int k) {
        unordered_map m;
        m[0] = 1;
        int ans = 0;
        int sum = 0;
        for(auto &x:nums)
        {
            sum+=x;
            if(m.find(sum-k) != m.end())
            {
                ans+=m[sum-k];
            }
            m[sum]++;
        }
        return ans;
    }
};

 85.把二叉树转换为累加树

力扣刷题续_第8张图片

class Solution {
public:
    int sum = 0;

    TreeNode* convertBST(TreeNode* root) {
        if (root != nullptr) {
            convertBST(root->right);
            sum += root->val;
            root->val = sum;
            convertBST(root->left);
        }
        return root;
    }
};

86.两数之和

给你两个整数 a 和 b ,不使用 运算符 + 和 - ,计算并返回两整数之和。

class Solution {
public:
    int getSum(int a, int b) {
        while(b!=0)
        {
            unsigned int carry = (unsigned int)(a & b)<<1;//进位
            a^=b;
            b = carry;
        }
        return a;
    }
};

87.实现前缀树

力扣刷题续_第9张图片

力扣刷题续_第10张图片

class Trie {
private:
    vector children;
    bool isEnd;

    Trie* searchPrefix(string prefix) {
        Trie* node = this;
        for (char ch : prefix) {
            ch -= 'a';
            if (node->children[ch] == nullptr) {
                return nullptr;
            }
            node = node->children[ch];
        }
        return node;
    }

public:
    Trie() : children(26), isEnd(false) {}

    void insert(string word) {
        Trie* node = this;
        for (char ch : word) {
            ch -= 'a';
            if (node->children[ch] == nullptr) {
                node->children[ch] = new Trie();
            }
            node = node->children[ch];
        }
        node->isEnd = true;
    }

    bool search(string word) {
        Trie* node = this->searchPrefix(word);
        return node != nullptr && node->isEnd;
    }

    bool startsWith(string prefix) {
        return this->searchPrefix(prefix) != nullptr;
    }
};

 88.打家劫舍

力扣刷题续_第11张图片

class Solution {
public:
    int rob(vector& nums) {
        int n = nums.size();
        if(n == 0)  return 0;
        if(n == 1)  return nums[0];
        vector dp(n);
        dp[0] = nums[0];
        dp[1] = max(nums[0],nums[1]);
        for(int i = 2;i

 89.计数质数

力扣刷题续_第12张图片

class Solution {
public:
    int countPrimes(int n) {
        vector isPrime(n,true);
        int ans = 0;
        for (int i = 2; i < n; ++i) {
            if(isPrime[i])
            {
                ans++;
                for(int j=2;i*j

 90.最大正方形

力扣刷题续_第13张图片

力扣刷题续_第14张图片

力扣刷题续_第15张图片

class Solution {
public:
    int maximalSquare(vector>& matrix) {
        int m = matrix.size();
        int n = matrix[0].size();
        if(m == 0 || n == 0)    return 0;
        vector> dp(m,vector(n));
        int ans = 0;
        for(int i=0;i

91.统计全为1的正方形子矩阵

力扣刷题续_第16张图片

class Solution {
public:
    int countSquares(vector>& matrix) {
        int m = matrix.size();
        int n = matrix[0].size();
        vector> dp(m,vector(n));
        int ans = 0;
        for(int i=0;i

92.打家劫舍2

力扣刷题续_第17张图片

class Solution {
public:
    int rob(vector& nums) {
        if (nums.size() == 0) return 0;
        if (nums.size() == 1) return nums[0];
        int result1 = robRange(nums, 0, nums.size() - 2); // 情况二
        int result2 = robRange(nums, 1, nums.size() - 1); // 情况三
        return max(result1, result2);
    }
    // 198.打家劫舍的逻辑
    int robRange(vector& nums, int start, int end) {
        if (end == start) return nums[start];
        vector dp(nums.size());
        dp[start] = nums[start];
        dp[start + 1] = max(nums[start], nums[start + 1]);
        for (int i = start + 2; i <= end; i++) {
            dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
        }
        return dp[end];
    }
};

93.打家劫舍3

力扣刷题续_第18张图片

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

    vector dfs(TreeNode* root)
    {
        if(root == nullptr) return vector{0,0};
        vector left = dfs(root->left);
        vector right = dfs(root->right);

        int val1 = root->val + left[0] + right[0];
        int val2 = max(left[0],left[1]) + max(right[0],right[1]);
        return {val2,val1};
    }
};

94.删除无效的括号

力扣刷题续_第19张图片

力扣刷题续_第20张图片

class Solution {
public:
    vector removeInvalidParentheses(string s) {
        vector ans;
        unordered_set curset;
        curset.insert(s);
        while(true)
        {
            for(auto & str : curset)
            {
                if((isValid(str)))
                {
                    ans.push_back(str);
                }
            }
            if(!ans.empty())    return ans;
            unordered_set nextstr;
            for(auto &str:curset)
            {
                for(int i=0;i0 && str[i] == str[i-1])   continue;
                    if(str[i] == '(' || str[i] == ')')
                    {
                        nextstr.insert(str.substr(0,i)+str.substr(i+1,str.size()));
                    }
                }
            }
            curset = nextstr;
        }
    }

    bool isValid(string str)
    {
        int count =0 ;
        for(auto &x:str)
        {
            if(x == '(')    count++;
            else if(x == ')')
            {
                count--;
                if(count < 0)   return false;
            }
        }
        return count == 0;
    }
};

95.柱状图中最大的矩形

力扣刷题续_第21张图片

详情参考

class Solution {
public:
     int largestRectangleArea(vector& heights) {
        stack st;
        int result = 0;
        heights.insert(heights.begin(), 0);
        heights.push_back(0);
        // 第一个元素已经入栈,从下表1开始
        for (int i = 0; i < heights.size(); i++) {
                while (!st.empty()&&heights[i] < heights[st.top()]) { // 注意是while
                    int curheight = heights[st.top()];
                    st.pop();
                    int cur = curheight*(i-st.top()-1);
                    result = max(result, cur);
                }
                st.push(i);
            }
        return result;
    }
};

96.最大矩形

力扣刷题续_第22张图片

class Solution {
public:
    int maximalRectangle(vector>& matrix) {
        if(matrix.empty())  return 0;
        int m = matrix.size();
        int n = matrix[0].size();

        int ans = 0;
        vector heights(n+2);
        for(int i=0;i& heights) {
        stack st;
        int result = 0;
        // 第一个元素已经入栈,从下表1开始
        for (int i = 0; i < heights.size(); i++) {
                while (!st.empty()&&heights[i] < heights[st.top()]) { // 注意是while
                    int curheight = heights[st.top()];
                    st.pop();
                    int cur = curheight*(i-st.top()-1);
                    result = max(result, cur);
                }
                st.push(i);
            }
        return result;
    }
};

97.重新排序得到2的幂

力扣刷题续_第23张图片

class Solution {
public:
    bool reorderedPowerOf2(int n) {
        vector nums(10,0);
        while(n)
        {
            nums[n%10]++;
            n/=10;
        }

        for(int i=1;i<=1e9;i<<=1)//i*=2
        {
            vector temp(10,0);
            int k = i;
            while(k)
            {
                temp[k%10]++;
                k/=10;
            }
            if(nums == temp)   return true;
        }
        return false;
    }
};

98.课程表

力扣刷题续_第24张图片

 课程表 - 课程表 - 力扣(LeetCode) (leetcode-cn.com)

99.课程表2

力扣刷题续_第25张图片

class Solution {
private:
    vector> edges;
    vector indeg;
    vector ans;
public:
    vector findOrder(int numCourses, vector>& prerequisites) {
        edges.resize(numCourses);
        indeg.resize(numCourses);
        for(auto &x:prerequisites)
        {
            edges[x[1]].push_back(x[0]);
            indeg[x[0]]++;
        }
        queue q;
        for(int i=0;i

100.单词拆分

力扣刷题续_第26张图片

力扣刷题续_第27张图片

class Solution {
public:
    bool wordBreak(string s, vector& wordDict) {
        unordered_set st(wordDict.begin(),wordDict.end());
        int n = s.size();
        vector dp(n+1);
        dp[0] = true;
        for(int i=1;i<=n;++i)
        {
            for(int j=0;j

101.电话号码的字母组合

力扣刷题续_第28张图片

class Solution {
public:
    vector ans;
    string temp;
    vector Map = {
        "",
        "",
        "abc",
        "def",
        "ghi",
        "jkl",
        "mno",
        "pqrs",
        "tuv",
        "wxyz"
    };
    vector letterCombinations(string digits) {
        if(digits.empty())  return {};
        func(digits,0);
        return ans;
    }

    void func(string digits,int index)
    {
        if(index == digits.size())
        {
            ans.push_back(temp);
            return ;
        }
        int ch = digits[index]-'0';
        string s = Map[ch];
        for(auto& x:s)
        {
            temp.push_back(x);
            func(digits,index+1);
            temp.pop_back();
        }
    }
};

102.2的幂

class Solution {
public:
    bool isPowerOfTwo(int n) {
        return n>0 && (1<<30)%n == 0;//2的30次方对n取余
    }
};

103.用rand7()实现rand10()

class Solution {
public:
    int rand10() {
        int num = (rand7() -1)*7 + rand7();
        /*
        (1-1)*7 + 1 = 1
        (7-1)*7 + 7 = 42+7 = 49
        1~49
        */
        while(num > 40)//去除大于40的值,使1~40等概率出现
        {
            num = (rand7()-1)*7 +rand7();
        }
        return 1+num%10;//1+ (0~9)
    }
};

104.寻找两个正序数组的中位数

class Solution {
public:
    double findMedianSortedArrays(vector& nums1, vector& nums2) {
        int length = nums1.size()+nums2.size();
        if(length % 2 == 1)
        {
            return func(nums1,nums2,(length+1)/2);//此时要找的第K个数为(length+1)/2
        }
        else
        {
            return (func(nums1,nums2,length/2) + func(nums1,nums2,(length/2+1)))/2.0;
            //此事要找的第K个数为 length/2 + length/2+1
        }
    }

    int func(vector nums1,vector nums2,int k)
    {
        int len1 = nums1.size();
        int len2 = nums2.size();
        int i = 0;
        int j = 0;

        while(true)
        {
            if(i == len1)//如果第一个数组为空
            {
                return nums2[j+k-1];
            }
            if(j == len2)//如果第二个数组为空
            {
                return nums1[i+k-1];
            }
            if(k == 1)//如果要找的中位数即K为1,则返回当前遍历的nums1和nums2起始位置的较小值即可
            {
                return min(nums1[i],nums2[j]);
            }

            int half = k/2;
            int I = min(i+half,len1)-1;
            int J = min(j+half,len2)-1;
            if(nums1[I] <= nums2[J])
            {
                k-=(I-i+1);
                i = I+1;
            }
            else{
                k-=(J-j+1);
                j = J+1;
            }

        }
    }
};

105.天际线问题

力扣刷题续_第29张图片

力扣刷题续_第30张图片

class Solution {
public:
    vector> getSkyline(vector>& buildings) {
        vector> sortedBuildings;
        for(auto& x:buildings)
        {
            sortedBuildings.push_back(make_pair(x[0],-x[2]));
            sortedBuildings.push_back(make_pair(x[1],x[2]));
        }
        sort(sortedBuildings.begin(),sortedBuildings.end(),[](auto& left,auto& right)
        {
            if(left.first == right.first)
            {
                return left.second < right.second;
            }
            return left.first < right.first;
        });//按横坐标进行排序
        multiset> pq;
        pq.insert(0);
        vector> ans;
        for(auto& build:sortedBuildings)
        {
            int x = build.first;
            int y = build.second;
            int top = *(pq.begin());
            if(y<0)//高度小于0,说明此为左节点
            {
                y=-y;
                if(y>top)
                {
                    ans.push_back({x,y});
                }
                pq.insert(y);
            }
            else//右节点
            {
                pq.erase(pq.find(y));
                int temp = *(pq.begin());
                if(top > temp)
                {
                    ans.push_back({x,temp});
                }
            }
        }
        return ans;
    }
};

106.汉诺塔问题

力扣刷题续_第31张图片

力扣刷题续_第32张图片

力扣刷题续_第33张图片

class Solution {
public:
    void hanota(vector& A, vector& B, vector& C) {
        move(A.size(),A,B,C);//把A上的N个盘子通过B移到C  A->B->C
    }

    void move(int n,vector& A,vector& B,vector& C)
    {
        if(n == 1)
        {
            C.push_back(A.back());
            A.pop_back();
            return ;
        }

        move(n-1,A,C,B);//把A上面的n-1个盘子通过C移动到B  A->C->B
        C.push_back(A.back());
        A.pop_back();
        move(n-1,B,A,C);//把B上面的n-1个盘子通过A移动到C  B->A->C
    }
};

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

力扣刷题续_第34张图片

力扣刷题续_第35张图片

力扣刷题续_第36张图片力扣刷题续_第37张图片

力扣刷题续_第38张图片

class Solution {
public:
    bool check(vector>& matrix, int mid, int k, int n) {
        int i = n - 1;
        int j = 0;
        int num = 0;
        while (i >= 0 && j < n) {
            if (matrix[i][j] <= mid) {
                num += i + 1;
                j++;
            } else {
                i--;
            }
        }
        return num >= k;
    }

    int kthSmallest(vector>& matrix, int k) {
        int n = matrix.size();
        int left = matrix[0][0];
        int right = matrix[n - 1][n - 1];
        while (left < right) {
            int mid = left + ((right - left) >> 1);
            if (check(matrix, mid, k, n)) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        return left;
    }
};

108.峰与谷

力扣刷题续_第39张图片

class Solution {
public:
    void wiggleSort(vector& nums) {
        if(nums.empty())    return ;
        sort(nums.begin(),nums.end());
        for(int i = 0;i

 109.三角形最小路径和

力扣刷题续_第40张图片

力扣刷题续_第41张图片

class Solution {
public:
    int minimumTotal(vector>& triangle) {
        int n = triangle.size();
        vector> ans(n,vector(n));
        ans[0][0] = triangle[0][0];
        for(int i = 1;i

 110.最大整数子集

力扣刷题续_第42张图片

力扣刷题续_第43张图片 力扣刷题续_第44张图片

class Solution {
public:
    vector largestDivisibleSubset(vector& nums) {
        int n = nums.size();
        sort(nums.begin(),nums.end());
        vector dp(n,1);
        int maxsize = 1;
        int maxvalue = nums[0];
        for(int i=1;i maxsize)
            {
                maxsize = dp[i];
                maxvalue = nums[i];
            }
        }
        vector ans;
        if(maxsize == 1)
        {
            ans.push_back(nums[0]);
            return ans;
        }

        for(int i=n-1;i>=0 && maxsize > 0;--i)
        {
            if(dp[i] == maxsize && maxvalue % nums[i] == 0)
            {
                ans.push_back(nums[i]);
                maxvalue = nums[i];
                maxsize--;
            }
        }
        return ans;
    }
};

111.接雨水2

力扣刷题续_第45张图片

力扣刷题续_第46张图片

class Solution {
public:
    int trapRainWater(vector>& heightMap) {
        int row = heightMap.size();
        int col = heightMap[0].size();
        int maxheight = 0;

        //寻找三维矩阵中最高的高度
        for(int i=0;i> water(row,vector(col,maxheight));
        queue> q;
        for(int i=0;iheightMap[i][j])
                    {
                        water[i][j] = heightMap[i][j];
                        q.push({i,j});
                    }
                }
            }
        }
        //从四周向内部收缩
        while(!q.empty())
        {
            int x = q.front().first;
            int y = q.front().second;
            q.pop();
            if(x-1 >= 0)//上
            {
            //如果上边格子接了雨水以后的高度比当前格子接了雨水的高度还要高,那么高出来的这部分雨水必然会流走,
                if(water[x][y] < water[x-1][y] && water[x-1][y] > heightMap[x-1][y])
                {
                    water[x-1][y] = max(water[x][y],heightMap[x-1][y]);
                    q.push({x-1,y});
                }
            }

            if(x+1 < row)//下
            {
                if(water[x][y] < water[x+1][y] && water[x+1][y] > heightMap[x+1][y])
                {
                    water[x+1][y] = max(water[x][y],heightMap[x+1][y]);
                    q.push({x+1,y});
                }
            }

            if(y-1 >= 0)//左
            {
                if(water[x][y] < water[x][y-1] && water[x][y-1] > heightMap[x][y-1])
                {
                    water[x][y-1] = max(water[x][y],heightMap[x][y-1]);
                    q.push({x,y-1});
                }
            }

            if(y+1 < col)//右
            {
                if(water[x][y] < water[x][y+1] && water[x][y+1] > heightMap[x][y+1])
                {
                    water[x][y+1] = max(water[x][y],heightMap[x][y+1]);
                    q.push({x,y+1});
                }
            }
        }
        int ans = 0;
        for(int i=1;i

112.被围绕的区域

力扣刷题续_第47张图片

力扣刷题续_第48张图片

class Solution {
public:
        void dfs(vector>& board,int x,int y,int row,int col)
        {
            if(x<0 || x>=row || y<0 || y>=col || board[x][y] != 'O')    return;
            board[x][y] = 'P';//标记
            dfs(board,x+1,y,row,col);
            dfs(board,x-1,y,row,col);
            dfs(board,x,y+1,row,col);
            dfs(board,x,y-1,row,col);
        }

    void solve(vector>& board) {
        int row = board.size();
        if(row == 0)    return ;
        int col = board[0].size();

        for(int i=0;i

113.和为K的的子数组(前缀和)

力扣刷题续_第49张图片

class Solution {
public:
    int subarraySum(vector& nums, int k) {
        unordered_map m;
        int sum = 0;
        int ans = 0;
        m[0] = 1;
        for(int i=0;i

114.构成交替字符串需要的最小交换次数

力扣刷题续_第50张图片

class Solution {
public:
    int minSwaps(string s) {
//iOdd 1在奇数位上的总个数,iEven  1在偶数位上的总个数
        int iOdd = 0, iEven = 0, n = s.length();
        for(int i = 0; i < n; ++i){
            if(s[i] == '1'){
                if(i % 2 == 0) iEven++;
                else iOdd++;
            }
        }
        
        int n1 = iEven+iOdd;//1总共出现的次数
        int n0 = n-n1;//0总共出现的次数
        int ans = -1;
        if(n1 >= n0-1 && n1<= n0+1){
            if(n0==n1)ans = min(iEven, iOdd);
            else if(n1 == n0+1) ans = iOdd;
            else ans = iEven;
        }
        return ans;
    }
};

115.乘积为正数的最长子数组的长度

力扣刷题续_第51张图片

力扣刷题续_第52张图片力扣刷题续_第53张图片

class Solution {
public:
    int getMaxLen(vector& nums) {
        int m = nums.size();
        vector positive(m);
        vector negative(m);
        if(nums[0]>0)   positive[0] = 1;
        else if(nums[0]<0)  negative[0] = 1;
        int maxlen = positive[0];
        for(int i=1;i0)
            {
                positive[i] = positive[i-1]+1;
                negative[i] = (negative[i-1]>0?negative[i-1]+1:0);
            }
            else if(nums[i]<0)
            {
                positive[i] = (negative[i-1]>0?negative[i-1]+1:0);
                negative[i] = positive[i-1]+1;
            }
            else{
                positive[i] = 0;
                negative[i] = 0;
            }
            maxlen = max(maxlen,positive[i]);
        }
        return maxlen;
    }
};

116.最长定差子序列

力扣刷题续_第54张图片

力扣刷题续_第55张图片

class Solution {
public:
    int longestSubsequence(vector& arr, int difference) {
        if(arr.empty()) return 0;
        unordered_map m;
        int ans = INT_MIN;
        for(auto& x:arr)
        {
            m[x] = m[x-difference]+1;
            ans = max(ans,m[x]);
        }
        return ans;
    }
};

 117.按字典序排在最后的子串

力扣刷题续_第56张图片

力扣刷题续_第57张图片

class Solution {
public:
    string lastSubstring(string s) {
        if(s.empty())   return "";
        int left = 0;
        int  right = 1;
        int k = 0;//偏移,对于相同的字符,则更长的字典序更大,而我们通过移动偏移k来判断当前的两个字符是否相等。
        int len = s.size();
        while(right+k len2
            //所以先判断s[left] < s[right+k]
            //再判断s[left+k] < s[right+k]
            else if(s[left+k] < s[right+k])
            {
                left = right;
                right++;
                k=0;
            }
            else{
                right++;
                k=0;
            }
        }
        return s.substr(left);
    }
};

 118.向下的路径节点之和(前缀和)

力扣刷题续_第58张图片

力扣刷题续_第59张图片

class Solution {
public:
    unordered_map m;

    int dfs(TreeNode* root,int cur,int targetSum)
    {
        if(root == nullptr) return 0;
        int ret = 0;
        cur+=root->val;
        if(m.count(cur-targetSum))
        {
            ret+=m[cur-targetSum];
        }
        m[cur]++;
        ret+=dfs(root->left,cur,targetSum);
        ret+=dfs(root->right,cur,targetSum);
        m[cur]--;
        return ret;
    }
    int pathSum(TreeNode* root, int targetSum) {
        m[0] = 1;//前缀和为0的路径有1条
        return dfs(root,0,targetSum);
    }
};

119.求x的幂(位运算)

这类题通常是指,判断一个数是否为x的幂(x=1,2,3....),对于这类型题,有一个通用的模板。

例如,下面的代码是判断一个数是否为4的幂(其他的也一样)

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

120.汉明距离总和(位运算)

力扣刷题续_第60张图片

力扣刷题续_第61张图片

class Solution {
public:
    int totalHammingDistance(vector& nums) {
        int ans = 0;
        int n = nums.size();
        for(int i=0;i<32;++i)
        {
            int cur = 0;
            for(auto& x:nums)
            {
                cur+=(x>>i)&1;//(x>>i)&1计算的是当前的第i位是否为1
            }
            ans+=cur*(n-cur);//某位上有c个1,每个1对应n - c个0,总贡献就是c * (n - c)
        }   
        return ans;
    }
};

 121.丢失的数字

力扣刷题续_第62张图片

/*class Solution {
public:
    int missingNumber(vector& nums) {
        int n = nums.size();
        int sum = (n*(n+1))/2;//前n项求和公式,可能存在数据溢出问题
        int res = 0;
        for(auto x:nums)
        {
            res+=x;
        }
        return sum-res;
    }
};*/
class Solution {
public:
    int missingNumber(vector& nums) {
        int ans = nums.size();
        for(int i=0;i

 122.乘积小于K的子数组(双指针)

力扣刷题续_第63张图片

class Solution {
public:
    int numSubarrayProductLessThanK(vector& nums, int k) {
        if(nums.empty() || k == 0 || k == 1)    return 0;
        int res = 1;
        int ans = 0;
        int left = 0;
        for(int right = 0;right= k)
            {
                res/=nums[left++];
            }
            ans+=right-left+1;
        /*为什么这里是right-left+1
        比如现在有一个满足题意的子数组为{1,2,3,4},
        那么{4} {3,4} {2,3,4} {1,2,3,4}也一定是满足题意的
        所以其实就是这个子数组的元素个数,即长度
        */
        }
        return ans;
    }
};

123.展开二叉搜索树(dfs)

力扣刷题续_第64张图片

class Solution {
public:
    TreeNode* head = new TreeNode();
    TreeNode* pre = head;
    TreeNode* increasingBST(TreeNode* root) {
        func(root);
        return head->right;
    }

    void func(TreeNode*root)
    {
        if(root != nullptr)
        {
            func(root->left);
            pre->right = root;
            pre = root;
            root->left = nullptr;
            func(root->right);
        }
    }
};

 124.所有路径(深度优先遍历)

力扣刷题续_第65张图片

力扣刷题续_第66张图片

class Solution {
public:
    vector> ans;
    vector temp;
    vector> allPathsSourceTarget(vector>& graph) {
        if(graph.empty())   return {};
        temp.push_back(0);//因为每一条路径一定是从0开始的,所以我们先将0放入temp中
        dfs(graph,0);//开始深度优先遍历
        return ans;
    }

    void dfs(vector> graph,int cur)
    {
        if(cur == graph.size()-1)//说明此时已经遍历到一条路径的终点了
        {
            ans.push_back(temp);
            return;
        }
        for(auto&  y:graph[cur])
        {
            temp.push_back(y);//接着从以y为出发点的路径开始遍历
            dfs(graph,y);
            temp.pop_back();//以y为出发点的路径完成遍历
        }
    }
};//深度优先遍历

125.爱吃香蕉的猩猩(二分法)

力扣刷题续_第67张图片

class Solution {
public:
    int minEatingSpeed(vector& piles, int h) {
        int left = 1;
        int right = 1000000000;
        while(left<=right)
        {
            int mid = (right-left)/2+left;
            if(Can(piles,mid,h))//如果以mid的速度可以吃完,则试着让狒狒吃的更慢一点
            {
                right = mid-1;
            }
            else
            {
                left = mid+1;
            }
        }
        return left;
    }

    bool Can(vector& piles,int K,int h)
    {
        int sum = 0;//以K速度吃完这些香蕉,总共需要的时间
        for(auto& x:piles)
        {
            sum+=x/K;
            if(x%K)
            {
                sum+=1;
            }
        }
        return sum<=h;
    }
};

126.数组中第K大的数字(快排) 

力扣刷题续_第68张图片

class Solution {
public:
    int partition(vector& nums,int left,int right)
    {
        int temp = nums[left];//基准数->固定
        int low = left;
        while(left=temp)
            {
                --right;
            }
            
            while(left& nums, int k) {
        int target = nums.size()-k;
        int left = 0;
        int right = nums.size()-1;
        while(left& nums,int left,int right)
    {
        srand(time(0));
        int index = rand()%(right-left+1)+left;
        int temp = nums[index];//基准数->随机
        swap(nums[left],nums[index]);//先把基准数换到最左边
        while(left=temp)
            {
                --right;
            }
            nums[left] = nums[right];
            while(left& nums, int k) {
        int target = nums.size()-k;
        int left = 0;
        int right = nums.size()-1;
        while(left

 127.省份数量(并查集)

力扣刷题续_第69张图片

class Solution {
public:
    int Find(vector& parent,int index)//返回index的根结点
    {
        while(parent[index] != index)
        {
            index = parent[index];
        }
        return index;
    }

    void Union(vector& parent,int x,int y)
    {
        int X = Find(parent,x);
        int Y = Find(parent,y);
        if(X != Y)//如果两个节点的根结点不同,说明他们两个不在同一个集合里,则可以进行合并
        {
            parent[X] = Y;
        }
    }
    int findCircleNum(vector>& isConnected) {
        int n = isConnected.size();
        int m = isConnected[0].size();
        vector parent(n+1);
        for(int i=1;i<=n;++i)
        {
            parent[i] = i;
        }
        for(int i=0;i

128.冗余连接(并查集)

力扣刷题续_第70张图片

class Solution {
public:
    int Find(vector& parent,int index)
    {
        while(parent[index] != index)
        {
            index = parent[index];
        }
        return index;
    }

    void Union(vector& parent,int x,int y)
    {
        int X = Find(parent,x);
        int Y = Find(parent,y);
        if(X != Y)
        {
            parent[X] = Y;
        }
    }
    
    bool connected(vector& parent,int x,int y)//判断x和y是否已在同一集合中
    {
        return Find(parent,x) == Find(parent,y);
    }

    vector findRedundantConnection(vector>& edges) {
        int n = edges.size();
        int m = edges[0].size();
        vector parent(n+1);
        for(int i=1;i<=n;++i)
        {
            parent[i] = i;
        }
        for(auto& edge:edges)
        {
            int x = edge[0];
            int y = edge[1];
            if(!connected(parent,x,y))
            {
                Union(parent,x,y);
            }
            else
            {
                return {x,y};
            }
        }
        return {};
    }
};

129.矩阵中的距离 (BFS)

力扣刷题续_第71张图片

class Solution {
public:
    vector> updateMatrix(vector>& mat) {
        queue> q;
        for(int i=0;i=0 && ny>=0 && nx

 130.计算后缀表达式

力扣刷题续_第72张图片

class Solution {
public:
    int evalRPN(vector& tokens) {
        if(tokens.empty())  return 0;
        stack s;
        for(auto& x:tokens)
        {
            if(isdigit(x[0]) || x[0] == '-' && x.size()>1)//当前为数字,数字分为正负,如果是-的话,要判断当前字符长度,不然可能和符号-混淆
            {
                s.push(stoi(x));//如果是数字,则push到栈中
            }
            else//如果是符号,则将栈中的前两个元素拿出来,计算完后,将结果再插入栈中
            {
                int a = s.top();
                s.pop();
                int b = s.top();
                s.pop();
                if(x=="+")  s.push(a+b);
                else if(x == "-")   s.push(b-a);
                else if(x == "*")   s.push(a*b);
                else s.push(b/a);
            }
        }
        return s.top();
    }
};

 131.向下路径节点之和(深度优先遍历+前缀和)

力扣刷题续_第73张图片

力扣刷题续_第74张图片

力扣刷题续_第75张图片

class Solution {
public:
    unordered_map m;

    int dfs(TreeNode* root,int cur,int targetSum)
    {
        if(root == nullptr) return 0;
        int ret = 0;
        cur+=root->val;
        if(m.count(cur-targetSum))
        {
            ret+=m[cur-targetSum];
        }
        m[cur]++;
        ret+=dfs(root->left,cur,targetSum);
        ret+=dfs(root->right,cur,targetSum);
        m[cur]--;
        return ret;
    }
    int pathSum(TreeNode* root, int targetSum) {
        m[0] = 1;//前缀和为0的路径有1条
        return dfs(root,0,targetSum);
    }
};

132.按字典序排在最后的子串(双指针)

力扣刷题续_第76张图片

class Solution {
public:
    string lastSubstring(string s) {
        if(s.empty())   return "";
        int left = 0;
        int  right = 1;
        int k = 0;//偏移,对于相同的字符,则更长的字典序更大,而我们通过移动偏移k来判断当前的两个字符是否相等。
        int len = s.size();
        while(right+k len2
            //所以先判断s[left] < s[right+k]
            //再判断s[left+k] < s[right+k]
            else if(s[left+k] < s[right+k])
            {
                left = right;
                right++;
                k=0;
            }
            else{
                right++;
                k=0;
            }
        }
        return s.substr(left);
    }
};

 133.删除有序数组中的重复项(双指针)

class Solution {
public:
    int removeDuplicates(vector& nums) {
        int n = nums.size();
        if(n<=2)    return n;
        int slow = 2;
        int fast = 2;
        while(fast

134.所有子字符串美丽值之和

力扣刷题续_第77张图片

class Solution {
public:
    int beautySum(string s) {
        if(s.empty())   return 0;
        int sum = 0;
        int len = s.size();
        for(int i=0;i

135.乘积为正数的最长子数组长度(动态规划)

力扣刷题续_第78张图片

力扣刷题续_第79张图片

力扣刷题续_第80张图片

class Solution {
public:
    int getMaxLen(vector& nums) {
        int m = nums.size();
        vector positive(m);
        vector negative(m);
        if(nums[0]>0)   positive[0] = 1;
        else if(nums[0]<0)  negative[0] = 1;
        int maxlen = positive[0];
        for(int i=1;i0)
            {
                positive[i] = positive[i-1]+1;
                negative[i] = (negative[i-1]>0?negative[i-1]+1:0);
            }
            else if(nums[i]<0)
            {
                positive[i] = (negative[i-1]>0?negative[i-1]+1:0);
                negative[i] = positive[i-1]+1;
            }
            else{
                positive[i] = 0;
                negative[i] = 0;
            }
            maxlen = max(maxlen,positive[i]);
        }
        return maxlen;
    }
};

136.有效的完全平方数

class Solution {
public:
    bool isPerfectSquare(int num) {
        if(num == 0)    return false;
        int left = 1;
        int right = num;
        while(left<=right)
        {
            int mid = ((right-left)>>1)+left;
            if((long long)mid*mid>num)  right = mid-1;
            else    left = mid+1;
        }
        return right*right == num;
    }
};

 137.多次搜索

力扣刷题续_第81张图片

class Solution {
public:
    struct TrieNode
    {
        int index;
        vector child;
        TrieNode():child(26),index(-1){}
    };
    TrieNode* root = new TrieNode();

    void Delete(TrieNode* node)
    {
        if(node == nullptr) return ;
        for(int i=0;i<26;++i)
        {
            Delete(node->child[i]);
            node->child[i] = nullptr;
        }
        delete node;
    }

    void insert(string word,int s)
    {
        TrieNode* cur = root;
        for(auto& ch:word)
        {
            ch-='a';
            if(cur->child[ch] == nullptr)
            {
                cur->child[ch] = new TrieNode();
            }
            cur = cur->child[ch];
        }
        cur->index = s;
    }

    void search(string word,vector>& ans,int s)
    {
        TrieNode* cur = root;
        for(auto& ch:word)
        {
            ch-='a';
            if(cur->index != -1)
            {
                ans[cur->index].push_back(s);
            }
            if(cur->child[ch] == nullptr)  return;
            cur = cur->child[ch];
        }
        if(cur->index != -1) ans[cur->index].push_back(s);
    }
    vector> multiSearch(string big, vector& smalls) {
        int m = big.size();
        int n = smalls.size();
        vector> ans(n,vector{});
        for(int i=0;i

 138.复原IP地址 

力扣刷题续_第82张图片

class Solution {
private:
    vector ans;
    vector segments;

public:
    void dfs(const string& s, int segId, int segStart) {
        // 如果找到了 4 段 IP 地址并且遍历完了字符串,那么就是一种答案
        if (segId == 4) {
            if (segStart == s.size()) {
                string ipAddr;
                for (int i = 0; i < 4; ++i) {
                    ipAddr += to_string(segments[i]);
                    if (i != 3) {
                        ipAddr += ".";
                    }
                }
                ans.push_back(move(ipAddr));
            }
            return;
        }

        // 如果还没有找到 4 段 IP 地址就已经遍历完了字符串,那么提前回溯
        if (segStart == s.size()) {
            return;
        }

        // 由于不能有前导零,如果当前数字为 0,那么这一段 IP 地址只能为 0
        if (s[segStart] == '0') {
            segments[segId] = 0;
            dfs(s, segId + 1, segStart + 1);
        }

        // 一般情况,枚举每一种可能性并递归
        int addr = 0;
        for (int segEnd = segStart; segEnd < s.size(); ++segEnd) {
            addr = addr * 10 + (s[segEnd] - '0');
            if (addr > 0 && addr <= 0xFF) {
                segments[segId] = addr;
                dfs(s, segId + 1, segEnd + 1);
            } else {
                break;
            }
        }
    }

    vector restoreIpAddresses(string s) {
        segments.resize(4);
        dfs(s, 0, 0);
        return ans;
    }
};

139.范围求和2

力扣刷题续_第83张图片

 力扣刷题续_第84张图片

力扣刷题续_第85张图片

class Solution {
public:
    int maxCount(int m, int n, vector>& ops) {
        int mina = m;
        int minb = n;
        for(auto& x:ops)
        {
            mina = min(mina,x[0]);
            minb = min(minb,x[1]);
        }
        return mina*minb;
    }
};

140.把数字翻译成字符串(动态规划)

力扣刷题续_第86张图片

力扣刷题续_第87张图片

class Solution {
public:
    int translateNum(int num) {
        string src = to_string(num);
        int n = src.size();
        vector dp(n+1);
        dp[0] = 1;
        dp[1] = 1;
        for (int i = 2; i <= n; ++i) {
            auto pre = src.substr(i - 2, 2);
            if (pre <= "25" && pre >= "10") {
                dp[i] = dp[i-1]+dp[i-2];
            }
            else
            {
                dp[i] = dp[i-1];
            }
        }
        return dp[n];
    }
};

 141.

int func(int n, int m)
{
    vector> dp(122,vector(122,0));
    //dp[i][j]代表i个数(从1-i)和是j的组合数

    dp[0][0] = 1;

    for(int k=1;k<=m;++k)
        dp[0][k] = 0;

    for(int k=1;k<=n;++k)
        dp[k][0] = 1;

    for(int j=1;j<=m;++j)
        for(int i=1;i<=n;++i)
            if(j>=i)
                dp[i][j] = dp[i-1][j] + dp[i-1][j-i];
            else
                dp[i][j] = dp[i-1][j];

    return dp[n][m];
}

142.栈的压入、弹出序列

力扣刷题续_第88张图片

class Solution {
public:
    bool validateStackSequences(vector& pushed, vector& popped) {
        if(pushed.empty() || popped.empty())    return true;
        stack s;
        int index = 0;
        for(auto& x:pushed)
        {
            s.push(x);
            while(!s.empty() && s.top() == popped[index])
            {
                s.pop();
                index++;
            }
        }
        return s.empty();
    }
};

143.字符串的排列

力扣刷题续_第89张图片

class Solution {
public:
    vector permutation(string s) {
        vector res;

        dfs(res,s,0);
       
        return res;
    }

    void  dfs(vector &res,string &s,int pos){
        if(pos == s.size())
            res.push_back(s);

        for(int i=pos;i

144.扑克牌中的顺子

力扣刷题续_第90张图片

class Solution {
public:
    bool isStraight(vector& nums) {
        if(nums.empty())    return false;
        sort(nums.begin(),nums.end());
        int temp = 0;
        for(int i=1;i<5;++i)
        {
            if(nums[i-1] == 0)  continue;
            if(nums[i] == nums[i-1])    return false;
            temp+=nums[i]-nums[i-1];
        }
        return temp<5;
    }
};

145.和为s的连续正数序列

力扣刷题续_第91张图片

力扣刷题续_第92张图片

class Solution {
public:
    vector> findContinuousSequence(int target) {
        vector> ans;
        vector temp;
        for(int left = 1,right = 2;left < right;)
        {
            int sum = (right-left+1)*(left+right)/2;
            /*
                等差数列求和公式:
                    Sn = n*a1+n(n-1)d/2
                    Sn = n(a1+an)/2;
                    此题中,n = (right-left+1)   a1 = left    an = right
            */
            if(sum == target)
            {
                temp.clear();
                for(int i=left;i<=right;++i)
                {
                    temp.push_back(i);
                }
                ans.push_back(temp);
                ++left;
            }
            else if(sum < target)   right++;
            else    left++;
        }
        return ans;
    }
};

146.剪绳子2

class Solution {
public:
    int cuttingRope(int n) {
        if(n == 2)  return 1;
        if(n == 3)  return 2;
        if(n == 4)  return 4;
        long ans = 1;
        while(n>4)
        {
            ans*=3;
            n-=3;
            ans%=1000000007;
        }
        //循环结束后,绳子的长度还剩下n,此时n=1,2,3,4
        return (ans*n)%1000000007;
    }
};

 147.猜数字大小2(动态规划)

力扣刷题续_第93张图片

力扣刷题续_第94张图片

class Solution {
public:
    int getMoneyAmount(int n) {
        vector> dp(n+1,vector(n+1));
        for(int i=n-1;i>=1;--i)
        {
            for(int j=i+1;j<=n;++j)
            {
                int cur = INT_MAX;
                for(int k=i;k

148.数组中的逆序对(归并排序解法)

力扣刷题续_第95张图片

class Solution {
public:
    int ans;
    int reversePairs(vector& nums) {
        ans = 0;
        if(nums.empty())    return 0;
        vector temp(nums.size());
        MergeSort(nums,temp,0,nums.size()-1);
        return ans;
    }

    void MergeSort(vector& nums,vector& temp,int left,int right)
    {
        if(left < right)
        {
            int mid = (right-left)/2+left;
            MergeSort(nums,temp,left,mid);
            MergeSort(nums,temp,mid+1,right);
            Merge(nums,temp,left,right);
        }
    }

    void Merge(vector& nums,vector& temp,int left,int right)
    {
        int mid = (right-left)/2+left;
        int i = left;
        int j = mid+1;
        int index = 0;

        while(i<=mid && j<=right)
        {
            if(nums[i] <= nums[j])
            {
                temp[index++] = nums[i++];
            }
            else
            {
                ans+=(mid-i+1);
                temp[index++] = nums[j++];
            }
        }
        while(i<=mid)
        {
            temp[index++] = nums[i++];
        }
        while(j<=right)
        {
            temp[index++] = nums[j++];
        }
        index = 0;
        while(left<=right)
        {
            nums[left++] = temp[index++];
        }
    }
};

149.构建乘积数组

力扣刷题续_第96张图片

力扣刷题续_第97张图片

class Solution {
public:
    vector constructArr(vector& a) {
        int n = a.size();
        vector ans(n);
        int sum = 1;
        for(int i=0;i=0;--i)
        {
            ans[i]*=sum;// 再乘右边的数(不包括自己)
            sum*=a[i];
        }
        return ans;
    }
};

 150.和为s的连续正数序列

力扣刷题续_第98张图片

力扣刷题续_第99张图片

class Solution {
public:
    vector> findContinuousSequence(int target) {
        vector> ans;
        vector temp;
        for(int left = 1,right = 2;left < right;)
        {
            int sum = (right-left+1)*(left+right)/2;
            /*
                等差数列求和公式:
                    Sn = n*a1+n(n-1)d/2
                    Sn = n(a1+an)/2;
                    此题中,n = (right-left+1)   a1 = left    an = right
            */
            if(sum == target)
            {
                temp.clear();
                for(int i=left;i<=right;++i)
                {
                    temp.push_back(i);
                }
                ans.push_back(temp);
                ++left;
            }
            else if(sum < target)   right++;
            else    left++;
        }
        return ans;
    }
};

 151.扑克牌中的顺子

力扣刷题续_第100张图片

class Solution {
public:
    bool isStraight(vector& nums) {
        if(nums.empty())    return false;
        sort(nums.begin(),nums.end());
        int temp = 0;
        for(int i=1;i<5;++i)
        {
            if(nums[i-1] == 0)  continue;
            if(nums[i] == nums[i-1])    return false;
            temp+=nums[i]-nums[i-1];
        }
        return temp<5;
    }
};

 152.字符串的排列

力扣刷题续_第101张图片

class Solution {
public:
    vector permutation(string s) {
        vector res;

        dfs(res,s,0);
       
        return res;
    }

    void  dfs(vector &res,string &s,int pos){
        if(pos == s.size())
            res.push_back(s);

        for(int i=pos;i

153.栈的压入、弹出序列

class Solution {
public:
    bool validateStackSequences(vector& pushed, vector& popped) {
        if(pushed.empty() || popped.empty())    return true;
        stack s;
        int index = 0;
        for(auto& x:pushed)
        {
            s.push(x);
            while(!s.empty() && s.top() == popped[index])
            {
                s.pop();
                index++;
            }
        }
        return s.empty();
    }
};

154.范围求和2

力扣刷题续_第102张图片

力扣刷题续_第103张图片

class Solution {
public:
    int maxCount(int m, int n, vector>& ops) {
        int mina = m;
        int minb = n;
        for(auto& x:ops)
        {
            mina = min(mina,x[0]);
            minb = min(minb,x[1]);
        }
        return mina*minb;
    }
};

155.键值映射

力扣刷题续_第104张图片

struct TrieNode {
    int val;
    TrieNode * next[26];
    TrieNode() {
        this->val = 0;
        for (int i = 0; i < 26; ++i) {
            this->next[i] = nullptr;
        }
    }
};

class MapSum {
public:
    MapSum() {
        this->root = new TrieNode();
    }
    
    void insert(string key, int val) {
        int delta = val;
        if (cnt.count(key)) {
            delta -= cnt[key];
        }
        cnt[key] = val;
        TrieNode * node = root;
        for (auto c : key) {
            if (node->next[c - 'a'] == nullptr) {
                node->next[c - 'a'] = new TrieNode();
            }
            node = node->next[c - 'a'];
            node->val += delta;
        }
    }
    
    int sum(string prefix) {
        TrieNode * node = root;
        for (auto c : prefix) {
            if (node->next[c - 'a'] == nullptr) {
                return 0;
            } else {
                node = node->next[c - 'a'];
            }
        }
        return node->val;
    }
private:
    TrieNode * root;
    unordered_map cnt;
};
class MapSum {
public:
    unordered_map m;
    MapSum() {

    }
    
    void insert(string key, int val) {
        m[key] = val;
    }
    
    int sum(string prefix) {
        int ans = 0;
        for(auto& it:m)
        {
            if(it.first.find(prefix) == 0)
            {
                ans+=it.second;
            }
        }
        return ans;
    }
};

/**
 * Your MapSum object will be instantiated and called as such:
 * MapSum* obj = new MapSum();
 * obj->insert(key,val);
 * int param_2 = obj->sum(prefix);
 */

156.二叉搜索树的后序遍历序列

力扣刷题续_第105张图片

力扣刷题续_第106张图片

class Solution {
public:
    bool verifyPostorder(vector& postorder) {
        return func(postorder,0,postorder.size()-1);
    }

    bool func(vector& postorder,int left,int right)
    {
        if(left >= right)   return true;
        int index = left;
        while(postorder[index] < postorder[right] && index < right) ++index;
        for(int i=index;i

 157.山峰数组的顶部

力扣刷题续_第107张图片

class Solution {
public:
    int peakIndexInMountainArray(vector& arr) {
        int n = arr.size();
        int left = 1;
        int right = n-2;

        while(left <= right)
        {
            int mid = (left+right)/2;
            if(arr[mid] > arr[mid-1])
            {
                left = mid+1;
            }
            else
            {
                right = mid-1;
            }
        }
        return right;
    }
};

 普通方法找最大值

class Solution {
public:
    int peakIndexInMountainArray(vector& arr) {
        int ans = 0;
        int max = INT_MIN;
        for(int i=0;i max)
            {
                max = arr[i];
                ans = i;
            }
        }
        return ans;
    }
};

158.二叉树的坡度

力扣刷题续_第108张图片

class Solution {
public:
    int ans;
    int findTilt(TreeNode* root) {
        ans = 0;
        dfs(root);
        return ans;
    }

    int dfs(TreeNode* root)
    {
        if(root == nullptr) return 0;
        int leftsum = dfs(root->left);
        int rightsum = dfs(root->right);
        ans+=abs(leftsum-rightsum);
        return leftsum+rightsum+root->val;
    }
};

159.解码方式(动态规划)

力扣刷题续_第109张图片

力扣刷题续_第110张图片

class Solution {
public:
    int numDecodings(string s) {
        int n = s.size();
        if(n == 0)  return 0;
        vector dp(n+1);
        dp[0] = 1;
        for(int i=1;i<=n;++i)
        {
            if(s[i-1] != '0')
            {
                dp[i]+=dp[i-1];
            }
            if(i>1 && s[i-2] != '0' && ((s[i-2]-'0')*10+(s[i-1]-'0') <= 26))
            {
                dp[i] += dp[i-2];
            }
        }
        return dp[n];
    }
};

160.使用最小花费爬楼梯

力扣刷题续_第111张图片

class Solution {
public:
    int minCostClimbingStairs(vector& cost) {
        int n = cost.size();
        vector dp(n+1);
        dp[0] = 0;
        dp[1] = 0;
        for(int i=2;i<=n;++i)
        {
            dp[i] = min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
        }
        return dp[n];
    }
};

 161.整数拆分

力扣刷题续_第112张图片

力扣刷题续_第113张图片

class Solution {
public:
    int integerBreak(int n) {
        vector dp(n+1);
        for(int i=2;i<=n;++i)
        {
            int cur = 0;
            for(int j=1;j

162.无重叠区间

力扣刷题续_第114张图片

力扣刷题续_第115张图片

class Solution {
public:
    int eraseOverlapIntervals(vector>& intervals) {
        if (intervals.empty()) {
            return 0;
        }
        
        sort(intervals.begin(), intervals.end(), [](const auto& u, const auto& v) {
            return u[0] < v[0];
        });

        int n = intervals.size();
        vector f(n, 1);
        for (int i = 1; i < n; ++i) {
            for (int j = 0; j < i; ++j) {
                if (intervals[j][1] <= intervals[i][0]) {
                    f[i] = max(f[i], f[j] + 1);
                }
            }
        }
        return n - *max_element(f.begin(), f.end());
    }
};

力扣刷题续_第116张图片

class Solution {
public:
    int eraseOverlapIntervals(vector>& intervals) {
        int n = intervals.size();
        if(n == 0)  return 0;
        sort(intervals.begin(),intervals.end(),[](const auto& a,const auto& b)
        {
            return a[1] < b[1];
        });

        int ans = 1;
        int right = intervals[0][1];
        for(int i=1;i= right)
            {
                ans++;
                right = intervals[i][1];
            }
        }
        return n-ans;
    }
};

163.目标和

力扣刷题续_第117张图片

class Solution {
public:
    int ans;
    int findTargetSumWays(vector& nums, int target) {
        ans = 0;
        dfs(nums,target,0,0);
        return ans;
    }

    void dfs(vector& nums,int target,int index,int sum)
    {
        if(index == nums.size())
        {
            if(sum == target)
            {
                ans++;
            }
        }
        else{
            dfs(nums,target,index+1,sum+nums[index]);
            dfs(nums,target,index+1,sum-nums[index]);
        }
    }
};

164.数组中的最长山脉

力扣刷题续_第118张图片

力扣刷题续_第119张图片

class Solution {
public:
    int longestMountain(vector& arr) {
        int n = arr.size();
        int ans = 0;
        int left = 0;
        while(left+2arr[right+1])
                {
                    while(right+1 < n && arr[right] > arr[right+1])
                    {
                        ++right;
                    }//此时right代表了当前这座山的右山脚
                    ans = max(ans,right-left+1);
                }
                else//arr[right] == arr[right+1];
                {
                    ++right;
                }
            }
            left = right;
        }
        return ans;
    }
};

 165.摆动序列

力扣刷题续_第120张图片

力扣刷题续_第121张图片

力扣刷题续_第122张图片 力扣刷题续_第123张图片

class Solution {
public:
    int wiggleMaxLength(vector& nums) {
        int up = 1;
        int down = 1;
        int n = nums.size();
        for(int i=1;inums[i-1])
            {
                up = down+1;
            }
            else if(nums[i] < nums[i-1])
            {
                down = up+1;
            }
        }
        return n < 2?n:max(up,down);
    }
};

 166.二叉树的坡度

力扣刷题续_第124张图片

力扣刷题续_第125张图片

class Solution {
public:
    int ans;
    int findTilt(TreeNode* root) {
        ans = 0;
        dfs(root);
        return ans;
    }

    int dfs(TreeNode* root)
    {
        if(root == nullptr) return 0;
        int leftsum = dfs(root->left);
        int rightsum = dfs(root->right);
        ans+=abs(leftsum-rightsum);
        return leftsum+rightsum+root->val;
    }
};

167.后继者

力扣刷题续_第126张图片

class Solution {
public:
    TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
        if(root == nullptr || p == nullptr) return nullptr;
        if(root->val <= p->val)// 当前节点值小于等于目标值,那么当前目标值的后继者必然在右子树
        {
            return inorderSuccessor(root->right,p);
        }
        // 否则结果有可能是当前节点,或者在当前节点的左子树中
        // 那么先去左子树找一下试试,找不到的话返回当前节点即是结果
        TreeNode* ans = inorderSuccessor(root->left,p);
        return ans == nullptr?root:ans;
    }
};

168.判定字符是否唯一 

力扣刷题续_第127张图片

class Solution {
public:
    bool isUnique(string astr) {
        if(astr.empty())    return true;
        int mask = 0;
        for(auto& ch:astr)
        {
            int temp = ch-'a';
            if(mask & (1<

 169.最大单词长度乘积

力扣刷题续_第128张图片

class Solution {
public:
    int maxProduct(vector& words) {
        int len = words.size();
        vector mask(len);
        for(int i=0;i

170.最长和谐子序列(双指针)

力扣刷题续_第129张图片

class Solution {
public:
    int findLHS(vector& nums) {
        sort(nums.begin(),nums.end());
        int begin = 0;
        int ans = 0;
        for(int end = 0;end1)
            {
                ++begin;
            }
            if(nums[end]-nums[begin] == 1)
            {
                ans = max(ans,end-begin+1);
            }
        }
        return ans;
    }
};

171.硬币

class Solution {
public:
    int waysToChange(int n) {
        int coins[] = {1, 5, 10, 25};
        vector dp(n+1);
        dp[0] = 1;
        for(int &coin : coins){
            for(int i = coin; i <= n; i++){
                dp[i] = (dp[i] + dp[i - coin]) % 1000000007;
            }
        }
        return dp[n];
    }
};

 172.最大子矩阵

这要从最大子序和说起,由简到繁 - 最大子矩阵 - 力扣(LeetCode) (leetcode-cn.com)

class Solution {
public:
    vector getMaxMatrix(vector>& matrix) {
        int m = matrix.size();
        int n = matrix[0].size();
        int max = matrix[0][0];
        vector ans(4);

        vector> presum(m+1,vector(n));
        for(int i=1;i<=m;++i)
        {
            for(int j = 0;j arr(n);
                for(int i=0;i0)
                    {
                        sum+=arr[i];
                    }
                    else
                    {
                        sum = arr[i];
                        start =i;
                    }
                    if(sum>max)
                    {
                        max = sum;
                        ans[0] = top;
                        ans[1] = start;
                        ans[2] = end;
                        ans[3] = i;
                    }

                }
            }
        }
        return ans;
    }
};

173.迷路的机器人(回溯)

力扣刷题续_第130张图片

class Solution {
public:
    vector> ans;

    vector> pathWithObstacles(vector>& obstacleGrid) 
    {
        if(obstacleGrid.empty() || obstacleGrid[0][0] == 1 ||obstacleGrid.back().back() == 1)
        {
            return {};
        }
        vector> visited(obstacleGrid.size(),vector(obstacleGrid[0].size(),false));
        ans.push_back({0,0});
        if(dfs(obstacleGrid,visited,0,0))
        {
            return ans;
        }
        return {};
    }

    bool dfs(vector>& obstacleGrid,vector>& visited,int i,int j)
    {                         
        if(i == obstacleGrid.size()-1 && j == obstacleGrid[0].size()-1)
        {
            return true;
        }
        if(j+1

174.最长单词

力扣刷题续_第131张图片

class Solution {
public:
    unordered_set hset;
    // 单词组里面的某个单词可以由另外的两个单词组合而成
    string longestWord(vector& words) {
        sort(words.begin(), words.end(), [](string &a, string &b){
            if(a.size() == b.size()) return a <= b;//如果长度相同则按字典序排
            else return a.size() > b.size();//否则按长度降序排列
        });
        vector ans;
        for(auto w:words) hset.insert(w);//先把所有单词放到hash里
        for(auto w:words) {
            hset.erase(w);
            if(Check(w)) return w;
            hset.insert(w);
        }
        return "";
    }

    bool Check(string word) {
        if(hset.count(word)) return true;//说明单词word在words中不止一个
        // 长度
        for(int i = 1; i < word.size(); i++) {
            string left = word.substr(0, i);
            string right = word.substr(i, word.size() - left.size());
            if(hset.count(left) && Check(right)) return true;
        }
        return false;
    }
};

175.交换和

力扣刷题续_第132张图片

class Solution {
public:
    vector findSwapValues(vector& array1, vector& array2) {
        int sum1 = 0;
        int sum2 = 0;
        for(int x:array1)
        {
            sum1+=x;
        }
        for(int x:array2)
        {
            sum2+=x;
        }

        int dif = sum1-sum2;
        if((dif & 1) == 1)//如果是奇数
        {
            return {};
        }
        dif/=2;
        unordered_set s(array2.begin(),array2.end());

        for(int x:array1)
        {
            if(s.count(x-dif))
            {
                return {x,x-dif};
            }
        }
        return {};
    }
};

176.求和路径 

力扣刷题续_第133张图片

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    int ans = 0;
    int pathSum(TreeNode* root, int sum) {
        if(root == nullptr)
        {
            return 0;
        }
        dfs(root,sum);
        pathSum(root->left,sum);
        pathSum(root->right,sum);
        return ans;
    }

    void dfs(TreeNode* root,int sum)
    {
        if(root == nullptr)
        {
            return;
        }

        sum-=root->val;
        if(sum == 0)
        {
            ans++;
        }
        dfs(root->left,sum);
        dfs(root->right,sum);
    }
};

 177.最小差

class Solution {
public:
    int smallestDifference(vector& a, vector& b) {
        int m=a.size(),n=b.size();
        sort(a.begin(),a.end());
        sort(b.begin(),b.end());
        long res=INT_MAX;
        int i=0,j=0;
        while(i

 178.回复空格

力扣刷题续_第134张图片

力扣刷题续_第135张图片

class Solution {
public:
    int respace(vector& dictionary, string sentence) {
	    int sz = sentence.size();
	    vector dp(sz + 1, 0); dp[0] = 0;
	    for (int i = 1; i <= sz; i++) {
		    dp[i] = dp[i - 1] + 1;
		    for (auto& p : dictionary) {
			    int pz = p.size();
			    if (i >= p.size()) {
				    string substr = sentence.substr(i - pz, pz);
				    if (substr == p) dp[i] = min(dp[i], dp[i - pz]);
				    else dp[i] = min(dp[i], dp[i - pz] + pz);
			    }
		    }
	    }
	    return dp[sz];
    }
};

179.统计封闭岛屿的数目

力扣刷题续_第136张图片

class Solution {
public:
    int closedIsland(vector>& grid) {
        int m = grid.size();
        int n = grid[0].size();
        for(int i = 0;i>& grid,int i,int j)
    {
        if(i<0 || j<0 || i>=grid.size() || j>=grid[0].size() || grid[i][j] == 1)
        {
            return;
        }
        grid[i][j] = 1;
        dfs(grid,i+1,j);
        dfs(grid,i-1,j);
        dfs(grid,i,j+1);
        dfs(grid,i,j-1);
    }
};

 180.统计子岛屿

力扣刷题续_第137张图片

什么情况下grid2中的一个岛屿Bgrid1中的一个岛屿A的子岛?

当岛屿B中所有陆地在岛屿A中也是陆地的时候,岛屿B是岛屿A的子岛。

反过来说,如果岛屿B中存在一片陆地,在岛屿A的对应位置是海水,那么岛屿B就不是岛屿A的子岛

那么,我们只要遍历grid2中的所有岛屿,把那些不可能是子岛的岛屿排除掉,剩下的就是子岛。

class Solution {
public:
    int countSubIslands(vector>& grid1, vector>& grid2) {
        int m = grid1.size();
        int n = grid1[0].size();
        for(int i=0;i>& grid,int i,int j)
    {
        if(i<0 || j<0 || i>=grid.size() || j>=grid[0].size() || grid[i][j] == 0)
        {
            return ;
        }
        grid[i][j] = 0;
        dfs(grid,i+1,j);
        dfs(grid,i-1,j);
        dfs(grid,i,j+1);
        dfs(grid,i,j-1);
    }
};

181.岛屿的周长

力扣刷题续_第138张图片

计算出总的岛屿数量,因为有一对相邻两个陆地,边的总数就减2,那么在计算出相邻岛屿的数量就可以了。

class Solution {
public:
    int islandPerimeter(vector>& grid) {
        int sum = 0;    // 陆地数量
        int cover = 0;  // 相邻数量
        for (int i = 0; i < grid.size(); i++) {
            for (int j = 0; j < grid[0].size(); j++) {
                if (grid[i][j] == 1) {
                    sum++;
                    // 统计上边相邻陆地
                    if(i - 1 >= 0 && grid[i - 1][j] == 1) cover++;
                    // 统计左边相邻陆地
                    if(j - 1 >= 0 && grid[i][j - 1] == 1) cover++;
                    // 为什么没统计下边和右边? 因为避免重复计算
                    //因为我们遍历的方式是从上到下,从左到右进行的
                }
            }
        }
        return sum * 4 - cover * 2;
    }
};

 182.不同的岛屿数量

比如题目输入下面这个二维矩阵:

力扣刷题续_第139张图片

其中有四个岛屿,但是左下角和右上角的岛屿形状相同,所以不同的岛屿共有三个,算法返回 3。

很显然我们得想办法把二维矩阵中的「岛屿」进行转化,变成比如字符串这样的类型,然后利用 HashSet 这样的数据结构去重,最终得到不同的岛屿的个数。

如果想把岛屿转化成字符串,说白了就是序列化,序列化说白了遍历嘛。

首先,对于形状相同的岛屿,如果从同一起点出发,dfs函数遍历的顺序肯定是一样的

所以,遍历顺序从某种意义上说就可以用来描述岛屿的形状,比如下图这两个岛屿:

力扣刷题续_第140张图片

假设它们的遍历顺序是:

下,右,上,撤销上,撤销右,撤销下

如果我用分别用1, 2, 3, 4代表上下左右,用-1, -2, -3, -4代表上下左右的撤销,那么可以这样表示它们的遍历顺序:

2, 4, 1, -1, -4, -2

你看,这就相当于是岛屿序列化的结果,只要每次使用dfs遍历岛屿的时候生成这串数字进行比较,就可以计算到底有多少个不同的岛屿了

要想生成这段数字,需要稍微改造dfs函数,添加一些函数参数以便记录遍历顺序:

void dfs(int[][] grid, int i, int j, StringBuilder sb, int dir) {
    int m = grid.length, n = grid[0].length;
    if (i < 0 || j < 0 || i >= m || j >= n 
        || grid[i][j] == 0) {
        return;
    }
    // 前序遍历位置:进入 (i, j)
    grid[i][j] = 0;
    sb.append(dir).append(',');

    dfs(grid, i - 1, j, sb, 1); // 上
    dfs(grid, i + 1, j, sb, 2); // 下
    dfs(grid, i, j - 1, sb, 3); // 左
    dfs(grid, i, j + 1, sb, 4); // 右

    // 后序遍历位置:离开 (i, j)
    sb.append(-dir).append(',');
}

dir记录方向,dfs函数递归结束后,sb记录着整个遍历顺序,其实这就是回溯算法框架,你看到头来这些算法都是相通的。

有了这个dfs函数就好办了,我们可以直接写出最后的解法代码:

int numDistinctIslands(int[][] grid) {
    int m = grid.length, n = grid[0].length;
    // 记录所有岛屿的序列化结果
    HashSet islands = new HashSet<>();
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (grid[i][j] == 1) {
                // 淹掉这个岛屿,同时存储岛屿的序列化结果
                StringBuilder sb = new StringBuilder();
                // 初始的方向可以随便写,不影响正确性
                dfs(grid, i, j, sb, 666);
                islands.add(sb.toString());
            }
        }
    }
    // 不相同的岛屿数量
    return islands.size();
}

183.分发糖果

力扣刷题续_第141张图片

这道题目一定是要确定一边之后,再确定另一边,例如比较每一个孩子的左边,然后再比较右边,如果两边一起考虑一定会顾此失彼

先确定右边评分大于左边的情况(也就是从前向后遍历)

此时局部最优:只要右边评分比左边大,右边的孩子就多一个糖果,全局最优:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果

局部最优可以推出全局最优。

如果ratings[i] > ratings[i - 1] 那么[i]的糖 一定要比[i - 1]的糖多一个,所以贪心:candyVec[i] = candyVec[i - 1] + 1

再确定左孩子大于右孩子的情况(从后向前遍历)

遍历顺序这里有同学可能会有疑问,为什么不能从前向后遍历呢?

因为如果从前向后遍历,根据 ratings[i + 1] 来确定 ratings[i] 对应的糖果,那么每次都不能利用上前一次的比较结果了。

所以确定左孩子大于右孩子的情况一定要从后向前遍历!

如果 ratings[i] > ratings[i + 1],此时candyVec[i](第i个小孩的糖果数量)就有两个选择了,一个是candyVec[i + 1] + 1(从右边这个加1得到的糖果数量),一个是candyVec[i](之前比较右孩子大于左孩子得到的糖果数量)。

那么又要贪心了,局部最优:取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,保证第i个小孩的糖果数量即大于左边的也大于右边的。全局最优:相邻的孩子中,评分高的孩子获得更多的糖果。

局部最优可以推出全局最优。

所以就取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,candyVec[i]只有取最大的才能既保持对左边candyVec[i - 1]的糖果多,也比右边candyVec[i + 1]的糖果多

class Solution {
public:
    int candy(vector& ratings) {
        vector candyVec(ratings.size(), 1);
        // 从前向后
        for (int i = 1; i < ratings.size(); i++) {
            if (ratings[i] > ratings[i - 1]) candyVec[i] = candyVec[i - 1] + 1;
        }
        // 从后向前
        for (int i = ratings.size() - 2; i >= 0; i--) {
            if (ratings[i] > ratings[i + 1] ) {
                candyVec[i] = max(candyVec[i], candyVec[i + 1] + 1);
            }
        }
        // 统计结果
        int result = 0;
        for (int x:candyVec) result += x;
        return result;
    }
};

184.解数独

力扣刷题续_第142张图片

class Solution {
public:
    void solveSudoku(vector>& board) {
        if(!board.empty())
        {
            backtrack(board,0,0);
        }
    }

    bool backtrack(vector>& board, int i, int j)
    {
        int m = 9, n = 9;
        if (j == n) {
            // 穷举到最后一列的话就换到下一行重新开始。
            return backtrack(board, i + 1, 0);
        }
        if (i == m) {
            // 找到一个可行解,触发 base case
            return true;
        }

        if (board[i][j] != '.') {
            // 如果有预设数字,不用我们穷举
            return backtrack(board, i, j + 1);
        } 

        for (char ch = '1'; ch <= '9'; ch++) {
            // 如果遇到不合法的数字,就跳过
            if (!isValid(board, i, j, ch))
                continue;

            board[i][j] = ch;
            // 如果找到一个可行解,立即结束
            if (backtrack(board, i, j + 1)) {
                return true;
            }
            board[i][j] = '.';
        }
        // 穷举完 1~9,依然没有找到可行解,此路不通
        return false;
}

    bool isValid(vector>&board, int r, int c, char n) 
    {
        for (int i = 0; i < 9; i++) {
            // 判断行是否存在重复
            if (board[r][i] == n) return false;
            // 判断列是否存在重复
            if (board[i][c] == n) return false;
            // 判断 3 x 3 方框是否存在重复
            if (board[(r/3)*3 + i/3][(c/3)*3 + i%3] == n)
                return false;
        }
        return true;
}
};

185.可怜的小猪 

力扣刷题续_第143张图片

 本质上在考察数学中的 进制 问题

力扣刷题续_第144张图片

力扣刷题续_第145张图片

换底公式:

class Solution {
public:
    int poorPigs(int buckets, int minutesToDie, int minutesToTest) {
        int base = minutesToTest / minutesToDie + 1;
        int ans = ceil(log(buckets) / log(base));//log2 buckets / log2 base = log base buckets
        return ans;
    }
};

186.找到字符串中所有字母的异位词

力扣刷题续_第146张图片

class Solution {
public:
    //滑动窗口
    vector findAnagrams(string s, string p) {
        if(s.size() < p.size()) return {};
        vector cnt_s(26);
        vector cnt_p(26);
        vector ans;
        int left = 0;//滑动窗口左边界
        int right = -1;//滑动窗口右边界
        for(char& ch:p)
        {
            cnt_p[ch-'a']++;
            cnt_s[s[++right]-'a']++;
        }
        if(cnt_p == cnt_s)
        {
            ans.emplace_back(left);
        }

        while(right < s.size()-1)
        {
            cnt_s[s[++right]-'a']++;//滑动窗口右边界右移,对应的新的右边界的字符个数加一
            cnt_s[s[left++]-'a']--;//滑动窗口左边界右移,对应的之前的左边界的字符个数减一
            if(cnt_s == cnt_p)//如果现在两个串的字符个数相等,则当前子串符合条件
            {
                ans.emplace_back(left);
            }
        }
        return ans;
    }
    /*
        在方法一的基础上,我们不再分别统计滑动窗口和字符串 p 中每种字母的数量,而是统计滑动窗口和字符串p 中 每种字母数量的差;并引入变量 differ 来记录当前窗口与字符串 pp 中数量不同的字母的个数,并在滑动窗口的过程中维护它。
    在判断滑动窗口中每种字母的数量与字符串 p 中每种字母的数量是否相同时,只需要判断 differ 是否为p的长度即可。
    */
    vector findAnagrams_(string s, string p) {
        int m = s.size();
        int n = p.size();
        if(m cnt(26);
        vector ans;
        for(char& ch:p)
        {
            cnt[ch-'a']++;
        }
        int left = 0;
        int right = 0;
        while(right0)
            {
                cnt[s[right++]-'a']--;
                if(right - left == n)   ans.emplace_back(left);//判断differ
            }
            else{
                cnt[s[left++]-'a']++;
            }
        }
        return ans;
    }
};

你可能感兴趣的:(算法,leetcode)