• LeetCode刷题(1)


    贪心问题

    问题描述:贪心算法或贪心思想采用贪心的策略,保证每次操作都是局部最优的,从而使最后得到的结果是全局最优的。

    455.Assign Cookie

    题目描述
    有一群孩子和一堆饼干,每个孩子有一个饥饿度,每个饼干都有一个大小。每个孩子只能吃最多一个饼干,且只有饼干的大小大于孩子的饥饿度时,这个孩子才能吃饱。求解最多有多少孩子可以吃饱。
    输入输出样例
    输入两个数组,分别代表孩子的饥饿度和饼干的大小。输出最多有多少孩子可以吃饱的数量。

    Input: [1,2], [1,2,3]
    Output: 2

    思路
    将孩子饥饿度和饼干大小两个数组都按从小到大排序,每次让最小的饼干满足饥饿度最小的孩子,两个指针分别指向孩子饥饿度和饼干大小,遍历饼干数组,如果饼干大小能满足孩子饥饿度,则孩子饥饿度指针走一步。返回孩子饥饿度指针走的步数。

    代码

    class Solution {
        public int findContentChildren(int[] g, int[] s) {
            Arrays.sort(g);
    		Arrays.sort(s);
    		int gi=0,si=0;
    		while(gi<g.length && si<s.length){
    			if(s[si]>=g[gi]){
    				gi++;
    			}
    			si++;
    		}
    		return gi;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    135.Candy

    题目描述
    一群孩子站成一排,每一个孩子有自己的评分。现在需要给这些孩子发糖果,规则是如果一个孩子的评分比自己身旁的一个孩子要高,那么这个孩子就必须得到比身旁孩子更多的糖果;所有孩子至少要有一个糖果。求解最少需要多少个糖果。
    输入输出样例
    输入是一个数组,表示孩子的评分。输出是最少糖果的数量。

    Input: [1,0,2]
    Output: 5

    思路
    先从左往右满足高个子比矮个子糖多这个规则,再从右往左满足高个子比矮个子糖多。具体来说,先每个孩子给一颗糖。从左往右遍历孩子,如果a[i]>a[i-1],则让icandy[i]糖果增加为candy[i-1]+1;再从右往左遍历,如果a[i-1]>a[i]&&candy[i-1]<=candy[i],则candy[i-1]=candy[i+1],再求解candy数组之和即可。

    代码

    class Solution {
        public int candy(int[] ratings) {
            int n = ratings.length;
            int[] candies = new int[n];
            Arrays.fill(candies,1); //初始化
            for(int i=1;i<n;i++){
                if(ratings[i]>ratings[i-1]){ //从左往右遍历,右大于左,则右糖+1
                    candies[i]=candies[i-1]+1;
                }
            }
            for(int i=ratings.length-1;i>0;i--){ //从右往左遍历,左大于右,且左糖少
                if(ratings[i-1]>ratings[i] && candies[i-1]<=candies[i]){
                    candies[i-1]=candies[i]+1;
                }
            }
            int sum=0;
            for (int candy :
                    candies) {
                sum += candy;
            }
            return  sum;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    435. Non-overlapping Intervals

    题目描述
    给定多个区间,计算让这些区间互不重叠所需要移除区间的最少个数。起止相连不算重叠。
    输入输出样例
    输入是一个数组,数组由多个长度固定为2 的数组组成,表示区间的开始和结尾。输出一个
    整数,表示需要移除的区间数量。

    Input: [[1,2], [2,4], [1,3]]
    Output: 1

    注意:区间类型题,需要根据实际情况判断按区间开头排序还是按区间结尾排序。

    思路
    将区间按照右端点大小进行排序,遍历区间对,如果某区间左断点比上一个的右端点小,说明有重叠,移除该区间,计数加1。使用一个pre指针,每次指向不重复区间序列最右侧区间对的右端点,即每次保证有最多个不重叠的区间。

    代码

    class Solution {
        public int eraseOverlapIntervals(int[][] intervals) {
            Comparator<int[]> comparator = new Comparator<int[]>() {
                @Override
                public int compare(int[] o1, int[] o2) {
                    return o1[1]-o2[1];
                }
            };
            Arrays.sort(intervals,comparator);
            int pre = intervals[0][1]; //每次指向无重叠区间的最后一个区间右端点
            int count = 0;
            for(int i=1;i<intervals.length;i++){
                if(intervals[i][0]<pre){ //说明添加该区间时就重叠了
                    count++;
                }else {
                    pre = intervals[i][1]; //不重叠时,更新pre
                }
            }
            return count;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    605. Can Place Flowers (Easy)

    题目描述
    给你一个整数数组 flowerbed 表示花坛,由若干 0 和 1 组成,其中 0 表示没种植花,1 表示种植了花。另有一个数 n ,能否在不打破种植规则的情况下种入 n 朵花?能则返回 true ,不能则返回 false。

    输入输出样例
    示例 1:

    输入:flowerbed = [1,0,0,0,1], n = 1
    输出:true

    示例 2:

    输入:flowerbed = [1,0,0,0,1], n = 2
    输出:false

    思路
    从头遍历数组,如果能满足条件就插入,将该元素置为1,同时n-1。如果当前元素i为0,看i-1和i+1,如果a[i-1]和a[i+1]都为零,则满足插入条件。考虑条件:i若为首元素,此时只看a[i+1],i若为末尾元素,此时只看a[i-1]

    代码

    class Solution {
        public boolean canPlaceFlowers(int[] flowerbed, int n) {
    	for(int i=0;i<flowerbed.length;i++){
    	//巧妙地规避了判断是否是头和尾
            if(flowerbed[i]==0 && (i==0 || flowerbed[i-1]==0) && (i==flowerbed.length-1 || flowerbed[i+1]==0)){
                    flowerbed[i]=1;
                    n--;
                }
            }
            return n<=0;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    452. Minimum Number of Arrows to Burst Balloons

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

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

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

    输入输出样例
    示例 1:

    输入:points = [[10,16],[2,8],[1,6],[7,12]]
    输出:2
    解释:气球可以用2支箭来爆破:
    在x = 6处射出箭,击破气球[2,8]和[1,6]。
    输入:points = [[10,16],[2,8],[1,6],[7,12]]

    示例 2:

    输入:points = [[1,2],[3,4],[5,6],[7,8]]
    输出:4
    解释:每个气球需要射出一支箭,总共需要4支箭。

    示例 3:

    输入:points = [[1,2],[2,3],[3,4],[4,5]]
    输出:2
    解释:气球可以用2支箭来爆破:
    在x = 2处发射箭,击破气球[1,2]和[2,3]。
    在x = 4处射出箭,击破气球[3,4]和[4,5]。

    思路
    和区间相邻的435有些类似。将区间按照左端点从小到大排列,定义一个pre指向重叠区域的右端点,如果有其他气球的左端点points[i][0]<=pre,pre更新为较小的右端点,则这些区间可以用同一支箭引爆。

    代码

    class Solution {
        public int findMinArrowShots(int[][] points) {
            Comparator<int[]> comparator = new Comparator<int[]>() {
                @Override
                public int compare(int[] o1, int[] o2) {
                    return Integer.compare(o1[0], o2[0]);
                }
            };
            Arrays.sort(points,comparator);
            int pre=points[0][1];
            int count=1;
            for(int i=1;i<points.length;i++){
                if(points[i][0]<=pre){
                    pre = Math.min(pre,points[i][1]);
                    continue;
                }
                count++;
                pre = points[i][1];
            }
            return count;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    763. Partition Labels (Medium)

    问题描述
    字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。

    输入输出样例
    示例:

    输入:S = “ababcbacadefegdehijhklij”
    输出:[9,7,8]
    解释:
    划分结果为 “ababcbaca”, “defegde”, “hijhklij”。
    每个字母最多出现在一个片段中。
    像 “ababcbacadefegde”, “hijhklij” 的划分是错误的,因为划分的片段数较少。

    思路
    先遍历一次字符串,记录每个字符最后一次出现的下标。再次遍历字符串,使用一个end指向第一个片段结尾(初始为0),每次遍历一个字符,比较end和最后一次出现的位置,如果该位置比end远,使用该位置更新end。当元素i遍历到end时,划分为第一个片段。

    代码

    class Solution {
        public List<Integer> partitionLabels(String s) {
            List<Integer> list = new LinkedList<>();
            int[] last = new int[26]; //last每个位置存放对应字母最后一次出现位置
            for(int i=0;i<s.length();i++){
                last[s.charAt(i)-'a']=i;
            }
            int start=0,end=0;
            for(int i=0;i<s.length();i++){
                end = Math.max(end,last[s.charAt(i)-'a']);
                if(i==end){ //找到了片段尾
                    list.add(end-start+1);
                    start = end+1; //更新头和尾
                    end = start;
                }
            }
            return list;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    122. Best Time to Buy and Sell Stock II

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

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

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

    输入输出样例

    示例 1:

    输入:prices = [7,1,5,3,6,4]
    输出:7
    解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
    随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。

    思路
    每次交易利益都最大化,从而保证最终利益最大化。遍历价格数组,遇到price[i+1]>price[i]时,在第i天买入,遇到跌price[i+1]<price[i]之前卖出去。后面重复操作,把每次挣的钱相加,即为最大利润。

    代码

    class Solution {
        public int maxProfit(int[] prices) {
            int s = 0; //总利润
            for(int i=0;i<prices.length-1;i++){
                if(prices[i]<prices[i+1]){//可以买入的时机
                    int j = i+1;
                    int low = prices[i];
    				//j找到下一个开始下降的拐点
                    while (j<prices.length && prices[j]>=low){
                        low = Math.max(low,prices[j]); //迭代low
                        j++;
                    }
                    s += prices[j-1]-prices[i]; //j退回最高点j-1卖出
                    i = j -1; //更新i到价格的最高点,之后i自动加1,开启下一轮投资
                }
            }
            return s;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    406. Queue Reconstruction by Height (Medium)

    问题描述

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

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

    输入输出样例

    示例 1:

    输入:people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
    输出:[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
    解释:
    编号为 0 的人身高为 5 ,没有身高更高或者相同的人排在他前面。
    编号为 1 的人身高为 7 ,没有身高更高或者相同的人排在他前面。
    编号为 2 的人身高为 5 ,有 2 个身高更高或者相同的人排在他前面,即编号为 0 和 1 的人。
    编号为 3 的人身高为 6 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
    编号为 4 的人身高为 4 ,有 4 个身高更高或者相同的人排在他前面,即编号为 0、1、2、3 的人。
    编号为 5 的人身高为 7 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
    因此 [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]] 是重新构造后的队列。

    思路
    贪心:保证每次都将身高小的插到身高高的前面,不破坏规则。先按身高从大到小进行排序,(如果身高相同,ki小的人排在前面)。再次遍历数组people,如果当前人peole[i][ki]<i,即前面比他高的人比ki多,此时就把当前people[i]插到people[ki]的位置。(有插入操作,考虑用链表)

    代码

    class Solution {
        public int[][] reconstructQueue(int[][] people) {
            Comparator<int[]> comparator = new Comparator<int[]>() {
                @Override
                public int compare(int[] o1, int[] o2) {
                    if(o1[0]==o2[0]){
                        return Integer.compare(o1[1],o2[1]);
                    }else return Integer.compare(o2[0],o1[0]);
                }
            };
    
            Arrays.sort(people,comparator);
            List<int[]> list = new LinkedList<>();
            for(int i=0;i<people.length;i++){
                list.add(people[i][1],people[i]); //利用链表的优势,直接将其插到ki的位置
            }
            return list.toArray(new int[list.size()][]); //list集合转化为数组
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    665. Non-decreasing Array (Easy)

    问题描述
    给你一个长度为 n 的整数数组 nums ,请你判断在 最多 改变 1 个元素的情况下,该数组能否变成一个非递减数列。

    我们是这样定义一个非递减数列的: 对于数组中任意的 i (0 <= i <= n-2),总满足 nums[i] <= nums[i + 1]。

    输入输出样例

    示例 1:

    输入: nums = [4,2,3]
    输出: true
    解释: 你可以通过把第一个 4 变成 1 来使得它成为一个非递减数列

    思路
    遍历数组,每次如果遇到a[i]>a[i+1]时,就判断是否满足题目条件。有如下几种情况:


    可见只有前三种情况满足删除一个元素是非递减数列。代码中,可以将“拐点”拉平表示删除,然后来判断是否是递增。
    代码

    class Solution {
        public boolean checkPossibility(int[] nums) {
            for (int i = 0; i < nums.length-1; i++) {
                int x=nums[i],y=nums[i+1];
                if(y<x){
                    nums[i]=y;
                    if(isSorted(nums))return true;
                    nums[i]=x;
                    nums[i+1]=x;
                    return isSorted(nums);
                }
    
            }
            return true;
        }
        public boolean isSorted(int[] nums){
            for (int i = 0; i < nums.length-1; i++) {
                if(nums[i+1]<nums[i])return false;
            }
            return true;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    堡垒机的自动化运维,快速安全提升运维效率
    【三】安装k8s+kuboard, 拉取harbor镜像并执行yml文件
    Web SSH 的原理与在 ASP.NET Core SignalR 中的实现
    Google Earth Engine APP ——Forest Health监测APP(可下载)
    C语言_断言assert详解
    测试计划包括哪些内容?
    计算机组成与结构
    在 Meta 中避免 Presto 中的数据孤岛:从 Raptor 到 RaptorX 的旅程
    css怎么实现文字描边
    1.3操作系统基本概念
  • 原文地址:https://blog.csdn.net/ha_lee/article/details/125561596