Algorithm learning: 1-1 greedy algorithm

Keywords: C++ Algorithm leetcode greedy algorithm

The so-called greedy algorithm is to ensure that each operation is a local optimal solution, so that the final result is a global optimal solution.

Exercise 1:455. Distribute cookies

The key to using greedy algorithm is to find greedy strategy, that is, each operation is a local optimal solution.

As can be seen from the question, to satisfy as many children as possible, as long as the child with the smallest appetite is allocated the smallest size of biscuits that can satisfy him, this is the greedy strategy of this question.

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        if(g.size()==0||s.size()==0) return 0;  //Consider special circumstances

        sort(g.begin(),g.end());  //Sort in ascending order
        sort(s.begin(),s.end());

        int cnt=0;
        int j=0;
        for(int i=0;i<g.size();){
            if(s[j]>=g[i]){
                //If the biscuit size is greater than or equal to the appetite value
                ++i;
                ++cnt;
            }
            ++j;
            if(j==s.size()) break;
        }

        return cnt;
    }
};
class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(),g.end());  //Sort in ascending order
        sort(s.begin(),s.end());

        int child=0,cookie=0;
        while(child<g.size()&&cookie<s.size()){
            if(g[child]<=s[cookie])++child;
            ++cookie;
        }
        return child;
    }
};

135 distribute candy

We can split this sentence into two rules: the children with high scores must get more candy among the adjacent children.
Left rule: when ratings [i-1] < ratings [i], student I will have more candy than child i-1.
Right rule: when rating [i] > rating [i+1], student I will have more candy than student i+1.

Problem solving ideas:
1. Walk from left to right and record the minimum number of candy required at the current point;
2. Walk from right to left and record the minimum number of candy required at the current point;
3 take the maximum value of each point, and the sum is the result.

class Solution {
public:
    int candy(vector<int>& ratings) {
        int n=ratings.size();
        vector<int>vec(n,0);
        int left=0;
        for(int i=0;i<n;++i){
            if(i>0&&ratings[i]>ratings[i-1]){
                vec[i]=++left;
            }
            else{
                left=1;
                vec[i]=left;
            }
        }

        int right=0,ret=0;
        for(int i=n-1;i>=0;--i){
            if(i<n-1&&ratings[i]>ratings[i+1]){
                ++right;
            }else{
                right=1;
            }
            ret+=max(right,vec[i]);
        }
        return ret;
    }
};

452. Detonate the balloon with the least number of arrows

**Greedy strategy: * * first arrange all balloons and the right boundary in ascending order, so you can shoot the smallest balloon on the right boundary every time. The balloon on the right side of the left boundary in front of the right boundary will not explode, and the others have exploded. Then select the smallest balloon on the right boundary among the balloons that have not exploded. By analogy, it is the optimal solution to solve this problem.

class Solution {
public:
    int findMinArrowShots(vector<vector<int>>& points) {
        int n=points.size();
        //Arrange from small to large according to the right boundary
        sort(points.begin(),points.end(),
        [](const vector<int>&a,const vector<int>& b){
            return a[1]<b[1];
        });

        int cnt=1;
        int prev=points[0][1];
        for(int i=1;i<n;++i){
            if(points[i][0]>prev){
                ++cnt;
                prev=points[i][1];
            }
        }

        return cnt;
    }
};

763. Division of letter interval

dynamic programming

greedy strategy

Record the first occurrence time and the last occurrence time end of all characters;
Sort by left boundary from small to large;
Left record the left boundary of the current segment;
pos records the right boundary of the current segment;

Left is set as the left bound of the first interval, which must be 0;
pos is set as the right bound of the first interval;
Enter the cycle, starting from the next interval of the first interval;
If the left bound of the next interval is less than pos, it means that it should be divided into a segment. Therefore, update pos to the larger value of the current pos and this interval;
If the right bound of the next interval is greater than pos, it means that [left,pos] is a segment and the segment length is recorded; Update left to the left bound of the current interval and pos to the right bound of the current interval.

class Solution {
public:
    vector<int> partitionLabels(string s) {
        int n = s.size();
        vector<vector<int>>position(26,vector<int>(2,-1));

        unordered_map<char, int>ch_cnt;
        //position records the subscript of the first and last occurrence of a character
        for (int i = 0;i < n;++i) {
            if (ch_cnt[s[i]] == 0)
                position[s[i] - 'a'][0] = i;
            position[s[i] - 'a'][1] = i;
            ++ch_cnt[s[i]];
        }

        //Sort: sort the interval of each character from small to large according to the left boundary
        sort(position.begin(), position.end(),
            [](const vector<int>& a, const vector<int>& b) {
                return a[0] < b[0];
            });

        //It doesn't matter
        int i = 0;
        while (i < 26 && position[i][0] == -1)
            ++i;

        vector<int>ret;  //Storage results
        int left = 0;
        int pos = position[i][1]; //Record right bound
        for (i = i + 1;i < 26;++i) {
            if (i == 25) {
                if(position[i][0]>pos){
                    ret.push_back(pos - left + 1);
                    ret.push_back(position[i][1]-position[i][0]+1);
                    break;
                }else{
                    pos = max(position[i][1], pos);
                    ret.push_back(pos-left+1);
                }  
            }
            if (position[i][0] < pos) {
                //If there are overlapping parts
                //Update the pos and select a larger one
                pos = max(position[i][1], pos);
            }
            else {
                //No coincident parts
                ret.push_back(pos - left + 1);
                left = position[i][0];
                pos = position[i][1];
            }
        }
        return ret;
    }
};

Posted by Pastulio on Mon, 27 Sep 2021 06:37:57 -0700