当前位置: 首页 > article >正文

代码随想录-笔记-其七

我们来到了贪心算法的章节。

贪心算法和其他部分不太一样的是,他更多的是突出一种思路:通过求局部最优解来求全局最优解。因为只是一个大的思想逻辑,针对不同题型总是有不同的解决方案,所以贪心算法也不想其他算法那样有一个很经典的模板。

455. 分发饼干 - 力扣(LeetCode)

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。

对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是满足尽可能多的孩子,并输出这个最大数值。

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(), g.end());
        sort(s.begin(), s.end());
        int child_i=0;
        for(int i=0;i<s.size();++i){
            if(child_i>=g.size())break;
            if(s[i]>=g[child_i]){
                ++child_i;
            }
        }
        return child_i;
    }
};

376. 摆动序列 - 力扣(LeetCode)

如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。

  • 例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。

  • 相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。

子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。

给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        if (nums.size() < 2) return nums.size();
        int prediff = 0,curdiff=0;
        int res = 1; 
        for (int i = 1; i < nums.size(); ++i) {
            curdiff = nums[i] - nums[i - 1];
            if (curdiff * prediff <= 0 && curdiff != 0) {
                ++res;
                prediff = curdiff;
            }
        }

        return res;
    }
};

53. 最大子数组和 - 力扣(LeetCode)

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。子数组是数组中的一个连续部分。

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int presum=0,res=INT_MIN;
        for(int num:nums){
            presum=max(num,presum+num);
            res=max(res,presum);
        }
        return res;
    }
};

122. 买卖股票的最佳时机 II - 力扣(LeetCode)

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润 。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int result = 0;
        for (int i = 1; i < prices.size(); i++) {
            result += max(prices[i] - prices[i - 1], 0);
        }
        return result;
    }
};

55. 跳跃游戏 - 力扣(LeetCode)

给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int rightmost=0;
        for(int i=0;i<=rightmost;++i){
            rightmost=max(rightmost,i+nums[i]);
            if(rightmost>=nums.size()-1){return true;}
        }
        return false;
    }
};

45. 跳跃游戏 II - 力扣(LeetCode)

给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]

每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:

  • 0 <= j <= nums[i] 
  • i + j < n

返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]

class Solution {
public:
    int jump(vector<int>& nums) {
        int rightmost=0,end=0,step=0;
        for(int i=0;i<nums.size()-1;++i){
            rightmost=max(rightmost,i+nums[i]);
            if(i==end){
                end=rightmost;
                ++step;
            }
        }
        return step;
    }
};

这里可能乍一看比较难理解的是为什么i要小于nums.size()-1,但其实很简单:我们要的就是执行到nums.size()-1的位置,如果我们写小于nums.size()就会多执行一次循环,或者说我们就是利用(i==end)而i不取nums.size()-1的条件来判断。

1005. K 次取反后最大化的数组和 - 力扣(LeetCode)

给你一个整数数组 nums 和一个整数 k ,按以下方法修改该数组:

  • 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。

重复这个过程恰好 k 次。可以多次选择同一个下标 i 。

以这种方式修改数组后,返回数组 可能的最大和 。

class Solution {
public:
    int largestSumAfterKNegations(vector<int>& nums, int k) {
        int res=0;
        sort(nums.begin(),nums.end());
        for(int i=0;i<nums.size();++i){
            if(k>0&&nums[i]<0){
                nums[i]=-nums[i];
                --k;
            }
            res+=nums[i];
        }
        int minabs=*min_element(nums.begin(), nums.end());
        if(k%2==1)res-=2*minabs;
        return res;
    }
};

134. 加油站 - 力扣(LeetCode)

在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。

你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。

给定两个整数数组 gas 和 cost ,如果你可以按顺序绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则 保证 它是 唯一 的。

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int cursum=0,totalsum=0,start=0;
        for(int i=0;i<gas.size();++i){
            cursum+=gas[i]-cost[i];
            if(cursum<0){
                start=i+1;
                cursum=0;
            }
            totalsum+=gas[i]-cost[i];
        }
        if(totalsum<0)return -1;
        return start;
    }
};

135. 分发糖果 - 力扣(LeetCode)

n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。

你需要按照以下要求,给这些孩子分发糖果:

  • 每个孩子至少分配到 1 个糖果。
  • 相邻两个孩子评分更高的孩子会获得更多的糖果。

请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。

class Solution {
public:
    int candy(vector<int>& ratings) {
        int n=ratings.size();
        vector<int> candy(n,1);
        for(int i=1;i<n;++i){
            if(ratings[i]>ratings[i-1]){
                candy[i]=candy[i-1]+1;
            }
        }
        for(int i=n-2;i>=0;--i){
            if(ratings[i]>ratings[i+1]){
                candy[i]=max(candy[i],candy[i+1]+1);
            }
        }
        return accumulate(candy.begin(), candy.end(),0);
    }
};

860. 柠檬水找零 - 力扣(LeetCode)

在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。

每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。

注意,一开始你手头没有任何零钱。

给你一个整数数组 bills ,其中 bills[i] 是第 i 位顾客付的账。如果你能给每位顾客正确找零,返回 true ,否则返回 false 。

class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {
        int five=0,ten=0,twenty=0;
        for(int pay:bills){
            if(pay==5){
                five++;
            }
            else if(pay==10){
                if(!five)return false;
                else{
                    five--;
                    ten++;
                }
            }
            else if(pay==20){
                if(!five||!ten&&five<3)return false;
                else{
                    if(!ten){
                        five-=3;
                    }
                    else{
                        five--;
                        ten--;
                    }
                }
            }
        }
        return true;
    }
};

406. 根据身高重建队列 - 力扣(LeetCode)

假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。

请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。

class Solution {
public:
    static bool cmp(const vector<int>& a,const vector<int>& b){
        if(a[0]==b[0])return a[1]<b[1];
        return a[0]>b[0];
    }
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        sort(people.begin(), people.end(),cmp);
        vector<vector<int>> queue;
        for(int i=0;i<people.size();++i){
            int pos=people[i][1];
            queue.insert(queue.begin()+pos, people[i]);
        }
        return queue;
    }
};

452. 用最少数量的箭引爆气球 - 力扣(LeetCode)

有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i] = [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。

一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstartxend, 且满足  xstart ≤ x ≤ xend,则该气球会被 引爆 。可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后,可以无限地前进。

给你一个数组 points ,返回引爆所有气球所必须射出的 最小 弓箭数 

class Solution {
public:
    static bool cmp(const vector<int>& a,const vector<int>& b){
        return a[0]<b[0];
    }
    int findMinArrowShots(vector<vector<int>>& points) {
        sort(points.begin(), points.end(), cmp);
        int res=1;
        for(int i=1;i<points.size();++i){
            if(points[i][0]>points[i-1][1]){
                res++;
            }
            else{
                points[i][1]=min(points[i-1][1],points[i][1]);
            }
        }
        return res;
    }
};

435. 无重叠区间 - 力扣(LeetCode)

给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 

注意 只在一点上接触的区间是 不重叠的。例如 [1, 2] 和 [2, 3] 是不重叠的。

class Solution {
public:
    static bool cmp(const vector<int>& a,const vector<int>& b){
        return a[1]<b[1];
    }
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        sort(intervals.begin(), intervals.end(), cmp);
        int res=0,end=intervals[0][1];
        for(int i=1;i<intervals.size();++i){
            if(intervals[i][0]<end){
                res++;
            }
            else end=intervals[i][1];
        }
        return res;
    }
};

763. 划分字母区间 - 力扣(LeetCode)

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。

注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。

返回一个表示每个字符串片段的长度的列表。

class Solution {
public:
    vector<int> partitionLabels(string s) {
        int last[26];
        for(int i=0;i<s.size();++i){
            last[s[i]-'a']=i;
        }
        int start=0,end=0;
        vector<int> res;
        for(int i=0;i<s.size();++i){
            end=max(end,last[s[i]-'a']);
            if(i==end){
                res.push_back(end-start+1);
                start=end+1;
            }
        }
        return res;
    }
};

56. 合并区间 - 力扣(LeetCode)

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        sort(intervals.begin(), intervals.end());
        vector<vector<int>> res;
        res.push_back(intervals[0]);
        for(int i=0,j=i+1;j<intervals.size();++j){
            if(res[i][1]>=intervals[j][0]){
                res[i][1]=max(res[i][1],intervals[j][1]);
            }
            else{
                res.push_back(intervals[j]);
                ++i;
            }
        }
        return res;
    }
};

738. 单调递增的数字 - 力扣(LeetCode)

当且仅当每个相邻位数上的数字 x 和 y 满足 x <= y 时,我们称这个整数是单调递增的。

给定一个整数 n ,返回 小于或等于 n 的最大数字,且数字呈 单调递增 。

class Solution {
public:
    int monotoneIncreasingDigits(int n) {
        string str=to_string(n);
        int flag=str.size();
        for(int i=str.size()-1;i>0;--i){
            if(str[i]<str[i-1]){
                flag=i;
                str[i-1]--;
            }
        }
        for(int i=flag;i<str.size();++i){
            str[i]='9';
        }
        return stoi(str);
    }
};

968. 监控二叉树 - 力扣(LeetCode)

给定一个二叉树,我们在树的节点上安装摄像头。

节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。

计算监控树的所有节点所需的最小摄像头数量。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int res;
    int traversal(TreeNode* cur){
        if(!cur)return 2;
        int left=traversal(cur->left);
        int right=traversal(cur->right);
        if(left==2&&right==2)return 0;
        if(left==0||right==0){
            res++;
            return 1;
        }
        if(left==1||right==1)return 2;
        return -1;
    }
    int minCameraCover(TreeNode* root) {
        res=0;
        if(traversal(root)==0){
            res++;
        }
        return res;
    }
};


http://www.kler.cn/a/444753.html

相关文章:

  • Vulhub:Redis[漏洞复现]
  • Linux文件:动静态库制作 动态库链接原理解析
  • 力扣438-找到字符串中所有字母异位词
  • CSDN数据大屏可视化【开源】
  • android 登录界面编写
  • 深入详解线性代数基础知识:理解矩阵与向量运算、特征值与特征向量,以及矩阵分解方法(如奇异值分解SVD和主成分分析PCA)在人工智能中的应用
  • 【C语言程序设计——选择结构程序设计】求阶跃函数的值(头歌实践教学平台习题)【合集】
  • 深度学习基础--自定义函数对数据集进行图像分类,以车牌号识别为例
  • MCU驱动使用
  • MFC 应用程序语言切换
  • #Java篇:java项目init和写接口流程步骤详细
  • UG NX二次开发(C#)-如何设置UGOpen的UF_CAM_geom_type_e枚举类型
  • Go语言封装Cron定时任务
  • 【c++丨STL】set/multiset的使用
  • 2025年NISP考试时间是什么时候?NISP要多少钱?NISP考试时间及费用超全解说!
  • tryhackme-Pre Security-HTTP in Detail(HTTP的详细内容)
  • 2024159读书笔记|《南山册页:齐白石果蔬册鱼虫册》节选
  • 【Rust自学】4.3. 所有权与函数
  • WPF+MVVM案例实战与特效(四十三)- 打造动态炫酷彩虹字控件,让你的界面动起来
  • SQLite 命令
  • 亚信安全春节14天双倍假期通告
  • 在 Windows 上添加 github SSH 密钥
  • Unity录屏插件-使用Recorder录制视频
  • vscode不同的项目使用不同的环境变量或编译环境
  • 《小米创业思考》
  • 【数据库系列】MongoTemplate 基本入门:MongoDB 的增删改查