zoukankan      html  css  js  c++  java
  • LeetCode 贪心

    基础部分

    455. 分发饼干

    简单

    假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

    注意:

    你可以假设胃口值为正。
    一个小朋友最多只能拥有一块饼干。

    示例 1:

    输入: [1,2,3], [1,1]
    
    输出: 1
    
    解释: 
    你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
    虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
    所以你应该输出1。
    

    示例 2:

    输入: [1,2], [1,2,3]
    
    输出: 2
    
    解释: 
    你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。
    你拥有的饼干数量和尺寸都足以让所有孩子满足。
    所以你应该输出2.
    
    class Solution {
        public int findContentChildren(int[] g, int[] s) {
            Arrays.sort(g);
            Arrays.sort(s);
            int res = 0;
            int i = g.length-1;
            int j = s.length-1;
            while (i >= 0 && j >=0){
                if (s[j] >= g[i]){ //满足了拿去吃
                    res++;
                    j--;
                }
                i--;
            }
            return res;
        }
    }
    

    435. 无重叠区间

    中等

    给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。

    注意:

    1. 可以认为区间的终点总是大于它的起点。
    2. 区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。

    示例 1:

    输入: [ [1,2], [2,3], [3,4], [1,3] ]
    
    输出: 1
    
    解释: 移除 [1,3] 后,剩下的区间没有重叠。
    

    示例 2:

    输入: [ [1,2], [1,2], [1,2] ]
    
    输出: 2
    
    解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。
    

    示例 3:

    输入: [ [1,2], [2,3] ]
    
    输出: 0
    
    解释: 你不需要移除任何区间,因为它们已经是无重叠的了。
    
    class Solution {
        public int eraseOverlapIntervals(int[][] intervals) {
            int len = intervals.length;
            if (len < 2) return 0;
            Arrays.sort(intervals,(a,b)->(a[0]-b[0])); //以第一位升序排列
            List<int[]> list = new LinkedList<>();
            list.add(intervals[0]);
            for (int i = 0; i < intervals.length; i++) {
                int tail = list.get(list.size()-1)[1];
                if (tail > intervals[i][0]){
                    if (tail > intervals[i][1]) //留尾巴短的,后边不易重叠
                        list.get(list.size()-1)[1] = intervals[i][1];
                }else list.add(intervals[i]);
            }
            return len - list.size();
        }
    }
    

    452. 用最少数量的箭引爆气球

    中等

    在二维空间中有许多球形的气球。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。由于它是水平的,所以y坐标并不重要,因此只要知道开始和结束的x坐标就足够了。开始坐标总是小于结束坐标。平面内最多存在104个气球。

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

    Example:

    输入:
    [[10,16], [2,8], [1,6], [7,12]]
    
    输出:
    2
    
    解释:
    对于该样例,我们可以在x = 6(射爆[2,8],[1,6]两个气球)和 x = 11(射爆另外两个气球)。
    
    class Solution {
        public int findMinArrowShots(int[][] points) {
            if (points.length < 2) return points.length;
            Arrays.sort(points,(a,b)->(a[0]-b[0]));
            int res = 0;
            int i = 0;
            while (i < points.length){
                res++;
                int last = points[i][1];
                do {
                    i++;
                    if (i < points.length && points[i][1] < last) 
                        last = points[i][1]; //整体的尾巴往前才能都中
                }while (i < points.length && points[i][0] <= last);
            }
            return res;
        }
    }
    

    406. 根据身高重建队列

    中等

    假设有打乱顺序的一群人站成一个队列。 每个人由一个整数对(h, k)表示,其中h是这个人的身高,k是排在这个人前面且身高大于或等于h的人数。 编写一个算法来重建这个队列。

    注意:
    总人数少于1100人。

    示例

    输入:
    [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
    
    输出:
    [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
    
    class Solution {
        public int[][] reconstructQueue(int[][] people) {
            Arrays.sort(people,(a,b)->a[1]-b[1]); //第二位正序
            Arrays.sort(people,(a,b)->b[0]-a[0]); //第一位倒序
            for (int i = 0; i < people.length; i++)
                if (people[i][1] != i) { //people[i][1]:该去的位置
                    int j = i;
                    int[] tmp = people[j];
                    while (j != tmp[1]) { //tmp很关键,因为i和j都变化了,必须tmp
                        people[j] = people[j - 1];
                        j--;
                    }
                    people[j] = tmp;
                }
            return people;
        }
    }
    

    121. 买卖股票的最佳时机

    简单

    给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

    如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。

    注意:你不能在买入股票前卖出股票。

    示例 1:

    输入: [7,1,5,3,6,4]
    输出: 5
    解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
         注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
    

    示例 2:

    输入: [7,6,4,3,1]
    输出: 0
    解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
    
    class Solution {
        public int maxProfit(int[] prices) {
            int res = 0;
            int prof = 0;
            for (int i = 1; i < prices.length; i++) {
                int minus = prices[i] - prices[i-1];
                prof += minus;
                if (prof < 0) prof = 0; //负收益还不如不买
                else if (prof > res) res = prof;
            }
            return res;
        }
    }
    

    122. 买卖股票的最佳时机 II

    简单

    给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

    设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

    注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

    示例 1

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

    示例 2:

    输入: [1,2,3,4,5]
    输出: 4
    解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
         注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
         因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
    

    示例 3:

    输入: [7,6,4,3,1]
    输出: 0
    解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
    

    提示:

    • 1 <= prices.length <= 3 * 10 ^ 4
    • 0 <= prices[i] <= 10 ^ 4
    class Solution {
        public int maxProfit(int[] prices) {
            int prof = 0;
            for (int i = 1; i < prices.length; i++) {
                int minus = prices[i] - prices[i-1];
                prof += minus > 0 ? minus : 0;
            }
            return prof;
        }
    }
    

    605. 种花问题

    简单

    假设你有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花卉不能种植在相邻的地块上,它们会争夺水源,两者都会死去。

    给定一个花坛(表示为一个数组包含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. 数组内已种好的花不会违反种植规则。
    2. 输入的数组长度范围为 [1, 20000]。
    3. n 是非负整数,且不会超过输入数组的大小。
    class Solution {
        public boolean canPlaceFlowers(int[] flowerbed, int n) {
            int k = 0;
            for (int i = 0; i < flowerbed.length && k<n; i++) {
                if (flowerbed[i] == 0){
                    if (i+1 == flowerbed.length || flowerbed[i+1] == 0){
                        flowerbed[i] = 1;
                        k++;
                        i++; //下一个地方肯定不能种,跳过
                    }
                }else {
                    i++; //下一个地方肯定不能种,跳过
                }
            }
            return k >= n;
        }
    }
    

    392. 判断子序列

    简单

    给定字符串 st ,判断 s 是否为 t 的子序列。

    你可以认为 st 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。

    字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace""abcde"的一个子序列,而"aec"不是)。

    示例 1:
    s = "abc", t = "ahbgdc"

    返回 true.

    示例 2:
    s = "axc", t = "ahbgdc"

    返回 false.

    后续挑战 :

    如果有大量输入的 S,称作S1, S2, ... , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?

    class Solution {
        public boolean isSubsequence(String s, String t) {
            char[] schars = s.toCharArray();
            char[] tchars = t.toCharArray();
            int i, j;
            for (i = 0,j = 0; i < schars.length; i++) {
                while (j < tchars.length && tchars[j] != schars[i]) j++;
                if (j >= tchars.length) break;
                j++;
            }
            return i == schars.length;
        }
    }
    

    665. 非递减数列

    简单

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

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

    示例 1:

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

    示例 2:

    输入: nums = [4,2,1]
    输出: false
    解释: 你不能在只改变一个元素的情况下将其变为非递减数列。
    

    说明:

    • 1 <= n <= 10 ^ 4
    • - 10 ^ 5 <= nums[i] <= 10 ^ 5
    class Solution {
        public boolean checkPossibility(int[] nums) {
            int fix = 0;
            for (int i = 1; i < nums.length && fix <= 1; i++){
                if (nums[i] < nums[i-1]){
                    fix++;
                    if (i-2 >= 0 && nums[i]<nums[i-2]){ //突然有个数字小了
                        nums[i]=nums[i-1];
                    }else { //前边的数字小了
                        nums[i-1]=nums[i];
                    }
                }
            }
            return fix <= 1;
        }
    }
    

    53. 最大子序和

    简单

    给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

    示例:

    输入: [-2,1,-3,4,-1,2,1,-5,4],
    输出: 6
    解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
    

    进阶:

    如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。

    class Solution {
        public int maxSubArray(int[] nums) {
            int res = Integer.MIN_VALUE;
            int sum = 0;
            for (int i = 0; i < nums.length; i++) {
                sum += nums[i];
                res = res > sum ? res : sum;
                sum = sum < 0 ? 0 : sum;
            }
            return res;
        }
    }
    

    763. 划分字母区间

    中等

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

    示例 1:

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

    提示:

    • S的长度在[1, 500]之间。
    • S只包含小写字母 'a''z'
    class Solution {
        public List<Integer> partitionLabels(String S) {
            char[] chars = S.toCharArray();
            Map<Character,Integer> map = new HashMap<>();
            for (int i = 0; i < chars.length; i++) {
                map.put(chars[i],i);
            }
            List<Integer> list = new LinkedList<>();
            int max = 0;
            int i = 0;
            int j = 0;
            while (j < chars.length){
                max = Math.max(max,map.get(chars[j]));
                if (j++ == max) {
                    list.add(j-i);
                    i = j;
                }
            }
            return list;
        }
    }
    

    频率排序

    135. 分发糖果

    困难

    老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。

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

    • 每个孩子至少分配到 1 个糖果。
    • 相邻的孩子中,评分高的孩子必须获得更多的糖果。

    那么这样下来,老师至少需要准备多少颗糖果呢?

    示例 1:

    输入: [1,0,2]
    输出: 5
    解释: 你可以分别给这三个孩子分发 2、1、2 颗糖果。
    

    示例 2:

    输入: [1,2,2]
    输出: 4
    解释: 你可以分别给这三个孩子分发 1、2、1 颗糖果。
         第三个孩子只得到 1 颗糖果,这已满足上述两个条件。
    
    class Solution {
        public int candy(int[] ratings) {
            int len = ratings.length;
            int[] res = new int[len];
            res[0] = 1;
            for (int i = 1; i < len; i++) {
                if (ratings[i] == ratings[i-1]) res[i] = 1;
                else if (ratings[i] > ratings[i-1]) res[i] = res[i-1]+1;
                else { //发现前面的孩子给少了
                    res[i] = 1;
                    int j = i;
                    do {
                        j--;
                        if (res[j] <= res[j+1]){
                            res[j] = res[j+1] + 1;
                        }else {
                            break;
                        }
                    }while (j > 0 && ratings[j] < ratings[j-1]);
                }
            }
            int candys = 0;
            for (int candy : res) candys += candy;
            return candys;
        }
    }
    

    316. 去除重复字母

    困难

    给你一个仅包含小写字母的字符串,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证返回结果的字典序最小(要求不能打乱其他字符的相对位置)。

    示例 1:

    输入: "bcabc"
    输出: "abc"
    

    示例 2:

    输入: "cbacdcbc"
    输出: "acdb"
    
    public class Solution {
       public String removeDuplicateLetters(String s) {
           int[] cnt = new int[26];
           int pos = 0;
           for (int i = 0; i < s.length(); i++) //字母出现次数的字典
               cnt[s.charAt(i) - 'a']++;
           for (int i = 0; i < s.length(); i++) {
               if (s.charAt(i) < s.charAt(pos)) pos = i; //后边的比pos的字典顺序小
               if (--cnt[s.charAt(i) - 'a'] == 0) break; //字典里减没了,pos可以放第一位
           }
           return s.length() == 0 ? "" : s.charAt(pos) + 
                   removeDuplicateLetters(s.substring(pos + 1) //递归
                   .replaceAll("" + s.charAt(pos), "") //这个字符统计完了,全部去掉
           ); 
       }
    }
    

    45. 跳跃游戏 II

    困难

    给定一个非负整数数组,你最初位于数组的第一个位置。

    数组中的每个元素代表你在该位置可以跳跃的最大长度。

    你的目标是使用最少的跳跃次数到达数组的最后一个位置。

    示例:

    输入: [2,3,1,1,4]
    输出: 2
    解释: 跳到最后一个位置的最小跳跃数是 2。
         从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
    

    说明:

    假设你总是可以到达数组的最后一个位置。

    class Solution {
        public int jump(int[] nums) {
            int res = 0;
            for (int i = nums.length - 1; i > 0; ) {
                int pos = i - 1;
                for (int j = 0; j < i; j++)
                    if (nums[j] >= i-j) pos = Math.min(pos,j);
                res++;
                i = pos;
            }
            return res;
        }
    }
    

    714. 买卖股票的最佳时机含手续费

    中等

    给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。

    你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。

    返回获得利润的最大值。

    注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。

    示例 1:

    输入: prices = [1, 3, 2, 8, 4, 9], fee = 2
    输出: 8
    解释: 能够达到的最大利润:  
    在此处买入 prices[0] = 1
    在此处卖出 prices[3] = 8
    在此处买入 prices[4] = 4
    在此处卖出 prices[5] = 9
    总利润: ((8 - 1) - 2) + ((9 - 4) - 2) = 8.
    

    注意:

    • 0 < prices.length <= 50000.
    • 0 < prices[i] < 50000.
    • 0 <= fee < 50000.
    //未通过,不知道为什么
    class Solution {
        public int maxProfit(int[] prices, int fee) {
            int sum = 0;
            int[] profs = new int[prices.length-1];
            for (int i = 0; i < profs.length; i++)
                profs[i] = prices[i+1] - prices[i];
            int prof = 0;
            int drop = 0;
            for (int i = 0; i < profs.length; i++) {
                if (prof == 0 && profs[i] < 0) continue;
                if (profs[i] < 0){
                    drop += profs[i];
                    if (drop <= -fee) { //赔fee块钱,还不如交管理费卖了
                        if (prof > fee) sum += prof-fee;
                        drop = 0;
                        prof = 0;
                    }
                }else {
                    prof += drop + profs[i];
                    drop = 0;
                }
            }
            sum += prof > fee ? prof - fee : 0; //最后一波没加上
            return sum;
        }
    }
    

    402. 移掉K位数字

    中等

    给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。

    注意:

    • num 的长度小于 10002 且 ≥ k。
    • num 不会包含任何前导零。

    示例 1 :

    输入: num = "1432219", k = 3
    输出: "1219"
    解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219。
    

    示例 2 :

    输入: num = "10200", k = 1
    输出: "200"
    解释: 移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。
    

    示例 3 :

    输入: num = "10", k = 2
    输出: "0"
    解释: 从原数字移除所有的数字,剩余为空就是0。
    
    class Solution {
        public String removeKdigits(String num, int k) {
            LinkedList<Character> stack = new LinkedList<>();
    
            for(char digit : num.toCharArray()) {
                while(!stack.isEmpty() && k > 0 && stack.peekLast() > digit) {
                    //stack不为空,k大于0,前面的数大于后面的数
                    stack.removeLast(); //去掉前面的数
                    k -= 1; //去掉一次少一次机会
                }
                stack.addLast(digit);
            }
            
            for(int i=0; i<k; ++i) stack.removeLast(); //还有机会没用完
            
            StringBuilder res = new StringBuilder();
            while (stack.peekFirst() == '0') stack.pollFirst();
            for (Character c : stack) res.append(c);
    
            return res.length() > 0 ? res.toString() : "0";
        }
    }
    

    1029. 两地调度

    简单

    公司计划面试 2N 人。第 i 人飞往 A 市的费用为 costs[i][0],飞往 B 市的费用为 costs[i][1]

    返回将每个人都飞到某座城市的最低费用,要求每个城市都有 N 人抵达

    示例:

    输入:[[10,20],[30,200],[400,50],[30,20]]
    输出:110
    解释:
    第一个人去 A 市,费用为 10。
    第二个人去 A 市,费用为 30。
    第三个人去 B 市,费用为 50。
    第四个人去 B 市,费用为 20。
    
    最低总费用为 10 + 30 + 50 + 20 = 110,每个城市都有一半的人在面试。
    

    提示:

    1. 1 <= costs.length <= 100
    2. costs.length 为偶数
    3. 1 <= costs[i][0], costs[i][1] <= 1000
    class Solution {
        public int twoCitySchedCost(int[][] costs) {
            int potA = costs.length/2;
            int potB = costs.length/2;
            Arrays.sort(costs,(x, y)->Math.abs(y[0]-y[1])-Math.abs(x[0]-x[1])); //相差越多权重越高,,权重高的人先挑
            int res = 0;
            for (int i = 0; i < costs.length; i++) {
                int a = costs[i][0];
                int b = costs[i][1];
                if (a < b) {
                    if (potA-- > 0) res += a;
                    else res += b;
                } else {
                    if (potB-- > 0) res += b;
                    else res += a;
                }
            }
            return res;
        }
    }
    
    //官方的,(A地-B地)的升序,这么简单吗,凭什么
    class Solution {
        public int twoCitySchedCost(int[][] costs) {
            Arrays.sort(costs,(a,b)->a[0]-a[1]-b[0]+b[1]);
            int total = 0;
            int n = costs.length / 2;
            for (int i = 0; i < n; ++i) total += costs[i][0] + costs[i + n][1];
            return total;
        }
    }
    
  • 相关阅读:
    CISCO 过载NAT配置(小型网络)
    CISCO静态路由配置
    CISCO 动态路由(RIP)
    CISCO 动态路由(OSPF)
    20191315 2.3.1测试
    cat userlist课上练习
    xxd
    2021-2022-1 20191315《信息安全系统设计与实现(上)》学习笔记6
    团队作业(二):需求分析
    2021-2022-1 20191315《信息安全系统设计与实现(上)》学习笔记5
  • 原文地址:https://www.cnblogs.com/peng8098/p/leetcode03.html
Copyright © 2011-2022 走看看