LeetCode + 《剑指Offer II》刷题笔记。

贪心

870 Advantage Shuffle

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
    public int[] advantageCount(int[] nums1, int[] nums2) {
        int n=nums1.length;
        TreeMap<Integer,Integer> map=new TreeMap<>();
        for(int num:nums1){
            map.put(num,map.getOrDefault(num,0)+1);
        }
        int[] ans=new int[n];
        for(int i=0;i<n;i++){
            Integer higher=map.higherKey(nums2[i]);
            if(higher==null){
                higher=map.firstKey();
            }
            ans[i]=higher;
            if(map.get(higher)==1){
                map.remove(higher);
            }else{
                map.put(higher,map.get(higher)-1);
            }
        }
        return ans;
    }
}
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(n)

优化:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public:
    vector<int> advantageCount(vector<int>& nums1, vector<int>& nums2) {
        int n=nums1.size();
        vector<int> idx1(n),idx2(n);
        for(int i=0;i<n;i++){
            idx1[i]=i;
            idx2[i]=i;
        }
        sort(idx1.begin(),idx1.end(),[&](int i,int j){return nums1[i]<nums1[j];});
        sort(idx2.begin(),idx2.end(),[&](int i,int j){return nums2[i]<nums2[j];});
        vector<int> res(n);
        int left=0,right=n-1;
        for(int i=0;i<n;i++){
            if(nums1[idx1[i]]>nums2[idx2[left]]){
                res[idx2[left]]=nums1[idx1[i]];
                left++;
            }else{
                res[idx2[right]]=nums1[idx1[i]];
                right--;
            }
        }
        return res;
    }
};
  • 时间复杂度:O(nlogn)
  • 空间复杂度:O(n)

1328 Break a Palindrome

贪心:找回文串中第一个大于’a’的字符,替换成’a’。如果没有,说明整串都是a,最后一个换成b。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Solution {
public:
    string breakPalindrome(string palindrome) {
        int len=palindrome.length();
        if(len==1) return "";
        for(int i=0;i<len/2;i++){
            if(palindrome[i]>'a'){
                palindrome[i]='a';
                return palindrome;
            }
        }
        palindrome[len-1]='b';
        return palindrome;
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

分配问题

455 Assign Cookies

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        int maxContent=0;
        sort(g.begin(),g.end());
        sort(s.begin(),s.end());
        int i=0,j=0;
        while(i<g.size() && j<s.size()){
            if(s[j]>=g[i]){
                maxContent++;
                i++;
                j++;
            }else{
                j++;
            }
        }
        return maxContent;
    }
};
  • 时间复杂度:O(mlogm+nlogn)
  • 空间复杂度:O(logm+logn)

135 Candy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
    int candy(vector<int>& ratings) {
        int n=ratings.size();
        if(n==1) return 1;
        vector<int> candies(n,1);
        for(int i=1;i<n;i++){
            if(ratings[i]>ratings[i-1]){
                candies[i]=candies[i-1]+1;
            }
        }
        for(int i=n-1;i>0;i--){
            if(ratings[i-1]>ratings[i]){
                candies[i-1]=max(candies[i-1],candies[i]+1);
            }
        }
        return accumulate(candies.begin(),candies.end(),0);
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

区间问题

需要根据实际情况判断按区间开头排序还是按结尾排序。

435 Non-overlapping Intervals

Greedy

采取的贪心策略:优先保留结尾小且不相交的区间。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        if(intervals.empty()) return 0;
        int n=intervals.size();
        sort(intervals.begin(),intervals.end(),[](vector<int>& a,vector<int>& b){
            return a[1]<b[1];
        });
        int res=0;
        int prev=intervals[0][1];
        for(int i=1;i<n;i++){
            if(intervals[i][0]<prev){
                res++;
            }else{
                prev=intervals[i][1];
            }
        }
        return res;
    }
};
  • 时间复杂度:O(nlogn)
  • 空间复杂度:O(logn)

452 Minimum Number of Arrows to Burst Balloons

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
    int findMinArrowShots(vector<vector<int>>& points) {
        int minArrow=1;
        sort(points.begin(),points.end(),[](vector<int>& a,vector<int>& b){
            return a[0]<b[0];
        });
        int n=points.size();
        for(int i=1;i<n;i++){
            if(points[i][0]>points[i-1][1]){
                minArrow++;
            }else{
                //更新最小右边界
                points[i][1]=min(points[i][1],points[i-1][1]);
            }
        }
        return minArrow;
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

ELSE

334 Increasing Triplet Subsequence

双向遍历

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
    bool increasingTriplet(vector<int>& nums) {
        int n=nums.size();
        if(n<3) return false;
        //维护数组 nums 中的每个元素左边的最小值和右边的最大值
        vector<int> leftMin(n),rightMax(n);
        leftMin[0]=nums[0];
        for(int i=1;i<n;i++){
            leftMin[i]=min(leftMin[i-1],nums[i]);
        }
        rightMax[n-1]=nums[n-1];
        for(int i=n-2;i>=0;i--){
            rightMax[i]=max(rightMax[i+1],nums[i]);
        }
        for(int i=1;i<n-1;i++){
            if(leftMin[i-1]<nums[i] && nums[i]<rightMax[i+1]) return true;
        }
        return false;
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

Greedy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Solution {
public:
    bool increasingTriplet(vector<int>& nums) {
        int n=nums.size();
        if(n<3) return false;
        int first=nums[0],second=INT_MAX;
        for(int i=1;i<n;i++){
            int num=nums[i];
            if(num>second) return true;
            else if(num>first) second=num;
            else first=num;
        }
        return false;
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

605 Can Place Flowers

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
    bool canPlaceFlowers(vector<int>& flowerbed, int n) {
        vector<int> temp;
        temp.push_back(0);
        for(int flower:flowerbed){
            temp.push_back(flower);
        }
        temp.push_back(0);
        //skip first & last
        for(int i=1;i<temp.size()-1;i++){
            if(temp[i-1]==0 && temp[i]==0 && temp[i+1]==0){
                temp[i]=1;
                n--;
            }
        }
        return n<=0;
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Solution {
public:
    bool canPlaceFlowers(vector<int>& flowerbed, int n) {
        int size=flowerbed.size();
        for(int i=0;i<size;i++){
            if(flowerbed[i]==0 
            && (i==0 || flowerbed[i-1]==0) 
            && (i==size-1 || flowerbed[i+1]==0)){
                flowerbed[i]=1;
                n--;
            }
        }
        return n<=0;
    }
};

注意:(i==0 || flowerbed[i-1]==0)(i==size-1 || flowerbed[i+1]==0)的顺序是判断i==0和i==size-1在判0前面,否则会有runtime error: addition of unsigned offset…

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
    bool canPlaceFlowers(vector<int>& flowerbed, int n) {
        int empty=0;
        if(flowerbed[0]==0){
            empty=1;
        }
        for(int i=0;i<flowerbed.size();i++){
            if(flowerbed[i]==1){
                n-=(empty-1)/2;
                empty=0;
            }else{
                empty+=1;
            }
        }
        n-=empty/2;
        return n<=0;
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

763 Partition Labels

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
    vector<int> partitionLabels(string s) {
        int len=s.length();
        //key:letter value:last occurance index
        unordered_map<char,int> mp;
        for(int i=0;i<len;i++){
            mp[s[i]]=i;
        }
        vector<int> res; 
        int start=0;
        int end=0;
        for(int i=0;i<len;i++){
            end=max(end,mp[s[i]]);
            if(i==end){
                res.push_back(i-start+1);
                start=i+1;
            }
        }
        return res;
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(∣Σ∣),其中 Σ = 26。

769 Max Chunks To Make Sorted

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Solution {
public:
    int maxChunksToSorted(vector<int>& arr) {
        int res=0;
        //arr:0~n-1
        int maxValue=-1;
        for(int i=0;i<arr.size();i++){
            maxValue=max(maxValue,arr[i]);
            if(i==maxValue){
                res+=1;
            }
        }
        return res;
    }
};

注意:若数组存在重复元素,该解法无法得到正确答案。

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
    int maxChunksToSorted(vector<int>& arr) {
        stack<int> stk;
        for(int a:arr){
            if(stk.empty() || a>=stk.top()){
                stk.push(a);
            }else{
                int maxValue=stk.top();
                stk.pop();
                while(!stk.empty() && a<stk.top()){
                    stk.pop();
                }
                stk.push(maxValue);
            }
        }
        return stk.size();
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

768 Max Chunks To Make Sorted II

新添加的数字可能会改变原数组的分块方式。如果新添加的数字大于或等于原数组最后一个块的最大值,则这个新添加的数字可以自己形成一个块。如果新添加的数字小于原数组最后一个块的最大值,则它必须融入之前的块。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
    int maxChunksToSorted(vector<int>& arr) {
        stack<int> stk;
        for(int a:arr){
            if(stk.empty() || a>=stk.top()){
                stk.push(a);
            }else{
                int maxValue=stk.top();
                stk.pop();
              	//判断加入a需要合并的所有排序块,每pop()一个代表合并一个块
                while(!stk.empty() && a<stk.top()){
                    stk.pop();
                }
                stk.push(maxValue);
            }
        }
        return stk.size();
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)