[日记]LeetCode算法·十五——贪心③

LeetCode解题策略:区间处理与算法应用
文章介绍了在LeetCode上解决无重叠区间、划分字母区间、合并区间、单调递增数字和监控二叉树等问题的策略。主要涉及排序、哈希表和贪心算法的应用,同时提到了动态规划的学习计划。

1 无重叠区间

LeetCode:无重叠区间
与这射气球的思路一致,根据起点排序,根据终点调整。

class Solution {
static bool cmp(vector<int>& a,vector<int>& b)
{
    return a[0]<b[0];
}

public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        sort(intervals.begin(),intervals.end(),cmp);
        int count=0;
        int left=0;
        int right=1;
        //从左往右看
        while(right<intervals.size())
        {
            //无重叠
            if(intervals[left][1]<=intervals[right][0])
            {
                left=right;
                ++right;
            }
            //有重叠
            else
            {
                //删除一个区间
                ++count;
                //因为right[0]>=left[0],所以right和left都不会与之前的区间重叠
                //那么比较right和left的优异在于它们的终止区间,谁更靠左

                //left更靠左
                if(intervals[left][1]<=intervals[right][1])
                {
                    ++right;
                }
                //right更靠左
                else
                {
                    left=right;
                    ++right;
                }
            }
        }
        return count;
    }
};

2 划分字母区间

LeetCode:划分字母区间
两种思路,都利用了哈希思想。
1 利用哈希表,存储每种字母的个数,在一个区间内其各个字母的次数之和一定等于整个字符串的个数之和。
2 利用哈希表,记录每个字母出现的最后位置,当下标与最后位置重合代表着抵达一个区间末尾。

字母个数
class Solution {
public:
    vector<int> partitionLabels(string s) {
        //使用哈希表
        vector<int> result;
        unordered_set<char> part_used;
        int alpha[26]={0};
        for(int i=0;i<s.size();++i)
        {
            //计数
            ++alpha[s[i]-'a'];
        }

        //开始初始化第一段区间
        int flag=alpha[s[0]-'a'];
        result.push_back(1);
        part_used.insert(s[0]);
        for(int i=1;i<s.size();++i)
        {
            //如果本段区间内已经有元素s[i]了
            if(part_used.find(s[i])!=part_used.end())
            {
                --flag;
            }
            //新加入的字母
            else
            {
                part_used.insert(s[i]);
                flag+=alpha[s[i]-'a'];
            }

            //判断flag
            //此处还不是一段完整的区间
            if(flag!=0)
                result[result.size()-1]++;
            //此处是完整的区间
            else
            {
                result[result.size()-1]++;
                //重新初始化
                if(i<s.size()-1)
                {
                    result.push_back(1);
                    part_used.clear();
                    flag=alpha[s[i+1]-'a'];
                    part_used.insert(s[i+1]);
                    ++i;
                }
            }
        }
        return result;
    }
};
最终位置
class Solution {
public:
    vector<int> partitionLabels(string s) {
        //使用哈希表
        vector<int> result;
        unordered_set<char> part_used;
        int alpha[26]={0};
        //记录每个字母所出现的最远边界
        for(int i=0;i<s.size();++i)
        {
            alpha[s[i]-'a']=i;
        }
        //目前的最远边界与当前坐标一致时,代表到达区间边界
        int edge=-1;
        int pre_edge=-1;
        for(int i=0;i<s.size();i++)
        {
            edge=max(alpha[s[i]-'a'],edge);
            if(edge==i)
            {
                result.push_back(edge-pre_edge);
                pre_edge=edge;
            }
        }
        return result;
    }
};

3 合并区间

LeetCode:合并区间
与435的题目1没有区别。

class Solution {
static bool cmp(vector<int>& a,vector<int>& b)
{
    return a[0]<b[0];
}
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        sort(intervals.begin(),intervals.end(),cmp);
        vector<vector<int>> result;

        result.push_back(intervals[0]);

        for(int i=1;i<intervals.size();++i)
        {
            //不重叠
            if(intervals[i][0] > result.back()[1])
            {
                result.push_back(intervals[i]);
            }
            else
            {
                result.back()[1]=max(result.back()[1],intervals[i][1]);
            }
        }
        
        return result;
    }
};

4 单调递增的数字

LeetCode:单调递增的数字
遇到递减,直接将之后的位数全部置为9,然后向前逐步减位,每次减位的后续都置9,知道满足递增为止。

class Solution {
public:
    int monotoneIncreasingDigits(int n) {
        if(n<10)return n;
        //保留一份,方便直接返回
        int N=n;
        vector<int> n_pos;

        //打散n得到各个位的数
        while(n!=0)
        {
            n_pos.push_back(n%10);
            n=n/10;
        }
        reverse(n_pos.begin(),n_pos.end());

        //从n开始,只要遇到一组递减,前一位数-1,后面全部置9
        //然后向前回溯是否递减,直到无递减或到头

        int index=0;
        //找到第一个递减数组
        for(;index<n_pos.size()-1;++index)
        {
            if(n_pos[index]>n_pos[index+1])
            {
                --n_pos[index];
                break;
            }
        }
        //没有递减数组,直接返回
        if(index==n_pos.size()-1)
            return N;

        //有递减数组,后续置9
        for(int i=index+1;i<n_pos.size();++i)
        {
            n_pos[i]=9;
        }

        //向前逐步减1
        for(int i=index-1;i>=0;--i)
        {
            //满足递增跳出
            if(n_pos[i]<=n_pos[i+1])
                break;
            else
            {
                //不满足,就当前位减一,并且后续置9
                --n_pos[i];
                n_pos[i+1]=9;
            }
        }
        //累加得到结果
        int result=0;
        for(int i=0;i<n_pos.size();i++)
        {
            result=result*10+n_pos[i];
        }
        return result;
    }
};

5 监控二叉树

LeetCode:监控二叉树
从叶子结点的父节点向上出发,每隔两层放置一个摄像头。
利用遍历过程的返回值,判断根节点的状态:未覆盖/摄像头/已覆盖。并且最后还需要对根节点进行检查。

class Solution {
public:
    int result;
    int traversal(TreeNode* root)
    {
        //0代表无覆盖,1代表有摄像头,2代表有覆盖
        //递归终止条件,空节点认为有覆盖
        if(root== nullptr)return 2;

        int left=traversal(root->left);
        int right=traversal(root->right);
        //左右有一个没有覆盖,放置摄像头
        if(left==0 || right==0)
        {
            ++result;
            return 1;
        }
        //此时left和right都不可能为0
        //左右有一个摄像头,自己被覆盖
        if(left==1 || right==1)return 2;
        return 0;
    }
    int minCameraCover(TreeNode* root) {
        result=0;
        int root_state=traversal(root);
        if(root_state==0)result++;
        return result;
    }
};

6 总结

贪心算法就这样告一段落了,也正好是二月的最后一天了,明天开始动态规划。另外实验室中双屏的主屏幕一直黑屏,把我恶心坏了。
——2023.2.28

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值