• 贪心思想


    贪心思想

    保证每次操作都是局部最优的,并且最后得到的结果是全局最优的。

    以下题为leetcode原题。

    1. 分配饼干

    455. Assign Cookies (Easy)

    思路描述:

    首先对孩子和饼干进行从小到大排序,那么依次比较,
    如果饼干大于孩子的胃,则加1,
    否则指向下一块饼干。
    此方法也可称为双指针法。
    

    代码实现:

    public static int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);
    
        int num = 0;
        int i = 0, j = 0;
        while (i < g.length && j < s.length) {
            //此处如果饼干大于孩子的胃,则num+1 同时, i j同时加1
            if (s[j] >= g[i]) {
                ++num;
                i++;
            }
            //此处 if不成立时候,只需 指向饼干的指针指向下一块饼干
            j++;
        }
        return num;
    }
    

    2. 无重叠区间

    435. Non-overlapping Intervals (Medium)

    思路描述:

    题目求的是找到需要移除区间的最小数量,使剩余区间互不重叠;
    则求出最多有多少区间互不重叠,总的区间数-最多区间不重叠=移除的最小区间数量;
    
    找出能存放的最大区间个数,则区间的末尾非常重要,选择的区间末尾越小,
    留给后面的区间的空间越大,那么后面能够选择的区间个数也就越大。
    
    首先对区间的末尾进行排序,然后每次选择末尾最小,并且和前一个区间不重叠的区间
    

    代码实现:

    public int eraseOverlapIntervals(int[][] intervals) {
        //需要添加判断,当数组个数为0时,返回0
        if (intervals.length == 0) {
            return 0;
        }
        //对二维数组根据行中的值排序排序
        Sort(intervals);
        int num = 0;
        int end = intervals[0][1];
    
        for (int i = 1; i < intervals.length; i++) {
            if (intervals[i][0] >= end) {
                //符合条件 ++
                num++;
                //end进行替换
                end = intervals[i][1];
            }
        }
        //至少存在一个
        num++;
        return intervals.length - num;
    }
    
    /**
    * 对二维数组根据第二列排序
    * @param arr
    */
    private void Sort(int[][] arr) {
        Arrays.sort(arr, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[1] - o2[1];
            }
        });
        //lambda表达式
        // Arrays.sort(arr,((o1, o2) -> o1[1]-o2[1]));
    }
    

    3. 投飞镖刺破气球

    452. Minimum Number of Arrows to Burst Balloons (Medium)

    思路描述:

    将题转化为  
    求解区间最多不重合区间个数(此时如果区间的端点相等也算重合),
    即是求所需的最小弓箭数
    

    代码实现:

    /**
    * 思路 :将题转化为  求解区间最多不重合区间个数(此时如果区间的端点相等也算重合),即是求所需的最小弓箭数
    *
    * @param points
    * @return
    */
    public static int findMinArrowShots(int[][] points) {
        //如果没有区间,则弓箭数为0
        if (points.length == 0) {
            return 0;
        }
        sort(points);
        int num = 1;
        int end = points[0][1];
        for (int i = 1; i < points.length; i++) {
            if (end < points[i][0]) {
                //符合条件++
                num++;
                //此时符合条件,进行替换,一定是符合条件时执行该语句
                end = points[i][1];
            }
        }
        return num;
    }
    
    private static void sort(int[][] arr) {
        Arrays.sort(arr, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[1] - o2[1];
            }
        });
    }
    

    4. 根据身高和序号重组队列

    思路描述:

    * 思路: 这道题 本身并没有思路 参考了 leetcode 上面的解析后,有点理解
    * <p>
    *     首先按照H高度降序(这是让高个字先排序),再按照K升序(根据K找位置),
    *     排序结束后,再按照K来插入,因为先排的高个子,所以高个子排完序后,低个子插入并不会影响它的相对位置。
    *     所以根据K来插入元素。
    *
    * 1.排序规则:按照H高度降序排序,K个数升序排序
    * 2.遍历后的数组,根据K插入到K的位置上
    

    代码实现:

    public int[][] reconstructQueue(int[][] people) {
        // [7,0], [7,1], [6,1], [5,0], [5,2], [4,4]
        // 再一个一个插入。
        // [7,0]
        // [7,0], [7,1]
        // [7,0], [6,1], [7,1]
        // [5,0], [7,0], [6,1], [7,1]
        // [5,0], [7,0], [5,2], [6,1], [7,1]
        // [5,0], [7,0], [5,2], [6,1], [4,4], [7,1]
        //先按照 H降序 K升序进行排序
        Arrays.sort(people, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[0] == o2[0] ? o1[1] - o2[1] : o2[0] - o1[0];
            }
        });
        List<int[]> list=new LinkedList<>();
        //再根据K 对数组进行插入
        for (int[] person : people) {
            list.add(person[1],person);
        }
        //将一个存放一维数组的list转化为一个二维数组
        // return list.toArray(new int[list.size()][2]);
        //此处传入people更加方便,速度会变慢
        return list.toArray(people);
    }
    

    5. 买卖股票最大的收益

    121. Best Time to Buy and Sell Stock (Easy)

    思路描述:

    方法一: 暴力法
    
    方法二:优化过
    		首先用数组中的第一个元素作为min,遍历数组,如果数组元素小于min,则进行替换,
         否则,计算此元素和min的差值是否大于max,如果大于则进行替换,否则继续执行
    

    代码实现:

    暴力法:

    public static int maxProfit(int[] prices) {
    
            int max=0;
            for (int i = 0; i < prices.length-1; i++) {
                for (int j = i+1; j < prices.length; j++) {
                    if (prices[j]-prices[i]>max){
                        max=prices[j]-prices[i];
                    }
                }
            }
            return max;
        }
    

    优化后算法:

    public static int maxProfit3(int[] prices){
        if (prices.length<=0)
            return 0;
        //第一个元素作为min
        int min=prices[0];
        int max=0;
        //遍历元素
        for (int i = 1; i < prices.length; i++) {
            //如果数组元素比min小,则替换,否则,进行运算 找出max.
            if(prices[i]<=min){
                min=prices[i];
            }else {
                max=Math.max(prices[i]-min,max);
            }
        }
        return max;
    }
    

    6. 买卖股票最大的收益2

    122. Best Time to Buy and Sell Stock II (Easy)

    思路描述:

    * 对于 [a, b, c, d],如果有 a <= b <= c <= d ,
    * 那么最大收益为 d - a。而 d - a = (d - c) + (c - b) + (b - a) ,
    * 因此当访问到一个 prices[i] 且 prices[i] - prices[i-1] > 0,
    * 那么就把 prices[i] - prices[i-1] 添加到收益中。
    

    代码实现:

    private static int maxProfit4(int[] prices) {
        //初始利润为0
        int profit=0;
        //从1遍历数组
        for (int i = 1; i < prices.length; i++) {
            int num=prices[i]-prices[i-1];
            //如果相邻两次差值大于0,则加入到利润中。 根据上述规律。
            if(num>0){
                profit+=num;
            }
        }
        return profit;
    }
    

    7. 种植花朵

    605. Can Place Flowers (Easy)

    思路描述:

    从1 到 arr.length-1遍历,
    如果第一个则判断当前和下一个是否有花,没有花,则flowerbed[i]=1(种花),num++
    如果是末尾则判断当前和上一个是否有花,没有花,则flowerbed[i]=1(种花),num++
    如果是中间位置,则判断当前、上一个和下一个是否同时有花,没有花,则flowerbed[i]=1(种花),num++
    

    代码实现:

    public boolean canPlaceFlowers(int[] flowerbed, int n) {
        int num=0;
        if(flowerbed.length==1){
            if(flowerbed[0]==0){
                num=1;
            }
            return num>=n;
        }
        //遍历
        for (int i = 0; i < flowerbed.length; i++) {
            //判断第一个花盆
            if(i==0){
                if(flowerbed[i]==0 && flowerbed[i+1]==0){
                    num++;
                    flowerbed[i]=1;
                }
            }else if (i==flowerbed.length-1){ //判断最后一个花盆
                if(flowerbed[i]==0 && flowerbed[i-1]==0){
                    num++;
                    flowerbed[i]=1;
                }
            }else { //判断中间花盆
                if(flowerbed[i]==0 && flowerbed[i-1]==0 && flowerbed[i+1]==0){
                    num++;
                    flowerbed[i]=1;
                }
            }
        }
        //是否满足要求
        return num>=n;
    }
    

    8. 判断是否是子序列

    思路:

    也可称为此方法为双指针法

    两个指针分别指向s,t
    如果指向的字符相等则同时指向下一个字符,指针均+1
    否则,只有长字符串的指针加1,
    循环结束条件是 两个指针有任意一个指向末尾。
    return 短指针>=短字符串的长度
    

    代码实现:

    public static boolean isSubsequence(String s, String t) {
        //i指向长的,j指向短的
        int i=0,j=0;
        while (i<t.length() && j<s.length()){
            if(t.charAt(i)==s.charAt(j)){
                j++;
            }
            i++;
        }
        return j>=s.length();
    }
    

    9. 子数组最大的和

    53. Maximum Subarray (Easy)

    思路描述:

    本题参考leetcode题解,大神解法
    
    首先对数组遍历,当前最大连续子序列和为sum,结果为ans
    if sum>0 则 sum对结果有增益效果,则sum保留并加上当前遍历数字
    if sum<0 则 sum对结果无增益效果,需要舍弃,则sum直接更新为当前遍历数字
    每次比较sum和ans的代销,将最大值置为ans,遍历结束返回结果
    

    代码实现:

    public int maxSubArray2(int[] nums) {
    
        //存放最终结果
        int ans=nums[0];
        //存放最大连续子序列的和
        int sum=0;
        for (int num : nums) {
            //sum对结果有增益效果,加上
            if(sum>0){
                sum+=num;
            }else {
                //sum对结果无增益效果,果断舍弃,更新为当前遍历数字
                sum=num;
            }
            //比较两者的最大值,赋值给ans
            ans=Math.max(ans,sum);
        }
        return ans;
    }
    

    DP法:

    public int maxSubArray(int[] nums) {
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        int max = nums[0];
        for (int i = 1; i < nums.length; i++) {
            //此处判断dp[i-1]+nums[i]和nums[i]的较大值,这样才能比较出连续和
            dp[i] = Math.max(dp[i- 1] + nums[i], nums[i]);	
            if (max < dp[i]) {
                max = dp[i];
            }
        }
        return max;
    }
    
  • 相关阅读:
    Leetcode: Summary Ranges
    Leetcode: Kth Smallest Element in a BST
    Leetcode: Basic Calculator II
    Leetcode: Basic Calculator
    Leetcode: Count Complete Tree Nodes
    Leetcode: Implement Stack using Queues
    Leetcode: Maximal Square
    Leetcode: Contains Duplicate III
    Leetcode: Invert Binary Tree
    Leetcode: The Skyline Problem
  • 原文地址:https://www.cnblogs.com/jimlau/p/11947148.html
Copyright © 2020-2023  润新知