贪心算法思路总结及其java实现

1. 贪心算法条件与思路的解题步骤

1.一次性:某个状态以后的过程不会影响以前的状态,只与当前状态有关。
2.局部最优集合能得到全局最优。
(如果某次选择会对之后选择产生影响,局部最优不能获得全局最优可以直接KO贪心思路)
第一步,判断是否属于贪心算法的情况:对一组数据加了一定的限制,希望从中选出几个数据,在满足限制值的情况下,达到最大期望值。
第二步,用简单例子检测贪心算法是否最优。

2.贪心算法的分类

依据个人经验分成了三大类
1.分饼干,跳跃游戏,环绕加油站等每次从最小的开始分配

从问题的某一初始解出发;
    while (到达目标边界)
    {
         if(该阶段的状态满足最优条件)加入此局部最优解;
          进入下一阶段;
    }
    return 由所有解元素组合成问题的一个可行解;

  1. 教师排课器,任务调度等区间覆盖的问题
    选择几个不相交的区间,从左到右将[lmin, rmax]覆盖上。按照起始端从小到大对这 n 个区间排序。
    每次选择:左端点跟前面已覆盖区间不重合的、尽量小的区间,这样可以让剩下的未覆盖区间尽可能的大,就可以放置更多的区间。
  2. 背包价值和钱币找零问题
    贡献相同期望值的情况下,每次价值越大,总体的数量/重量就更少

注:求最小生成树的Prim算法和Kruskal算法都是漂亮的贪心算法。

leetcode里贪心算法的代码实现

1.简单题455分发饼干
import java.util.Arrays;

 public class AssignCookie{
     public static int contentChildren(int[]g,int[]s){
         assert g.length>0||s.length>0;
         Arrays.sort(g);
         Arrays.sort(s);
         //定义第i个小孩的appetite对应第j块饼干
         int i=0,j=0;
         //当小孩没满足完或饼干没发完
         while(i<g.length&&j<s.length){
             if(g[i]<=s[j])
                 i++;
             j++;
         }
         //被满足的小孩个数
         return i;
     }
 }
中等题134. 加油站
/**
 *在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。
 * 你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。
 * 如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1。
 */
public class GasStation {
    /**
     *一旦遇到第一个无法到达的点 i,直接更换起始点为 i+1。中间的 [1,i-1] 的点一定不是起始点
     * @param gas
     * @param cost
     */
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int sum = 0;//选定起点到现在的油缸量
        int total = 0;//总的加油与耗油差值
        int result = 0;//选定的起点
        for(int i = 0;i<gas.length;i++){
            total += gas[i]-cost[i];
            if(sum<0){
                sum = gas[i]-cost[i];
                result = i;
            }
            else
                sum += gas[i]-cost[i];
        }
        //边界条件是能跑完全程
        return total>=0?result:-1;
    }
}
贪心算法简单题392. 判断子序列

public class isSubsequence {
    /*
     * 给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
     * 你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。
     *字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。
     */
    public boolean isSubsequence(String s, String t) {
        if(0==s.length()) return true;
        //母串序列索引i,子串j
        int sub = 0,j = 0;
        //不能用for循环是考虑到s比t长
        while( sub<s.length()&&j< t.length()){
            //如果不同只有母串后移
            if(s.charAt(sub)==t.charAt(j))
                sub++;
            j++;
        }
        //返回结果里判别是否子串全找到了,很有技巧
        return  sub==s.length();
    }
}

192.跳跃游戏

public class JumpGame {
    public static boolean canJump(int[] nums){
        assert nums.length>0;
        if(nums.length==1)return true;
        //数组首位为0且0不是唯一元素肯定跳不到最后
        if(nums.length>1&&nums[0]==0)return false;
        for (int i = 1; i < nums.length-1; i++) {
            int j = i - 1;
            while (nums[i] == 0) {
                //前面两个if是找到j的情况,说明这个0元素是可以被到达或跳过的
               // if (nums[j] >= i - j&&i==nums.length-1) break;
                if (nums[j] > i - j) break;
                if (j <= 0) return false;
                j--;
            }
        }
        return true;
    }

    //just for test
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String s = input.next();
        String[] arr = s.split(",");
        int[] arry = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            arry[i] = Integer.parseInt(arr[i]);
        }
        boolean result =canJump(arry);
        System.out.println(result);
    }
}
  1. 最大子序和
import java.util.Scanner;

/**
 * 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
 * 输入[-2,1,-3,4,-1,2,1,-5,4];输出6;因为连续子数组 [4,-1,2,1] 的和最大,为 6。
 */
public class MaxSubarray {
    public static int maxSubarray(int[] nums) {
        //sum存子序和,max表示选好子序手标的某次的和
        int sum = nums[0];
        int max = 0;
        for(int i=0;i<nums.length;i++){
            //if(max+nums[i]<nums[i])
            if(max<0) max = nums[i];
            else max+=nums[i];
            //如果不加这个结果就会子序数组首标找对,尾标可能加进没有使整体<0但变小的数
            sum = Math.max(sum,max);
        }
        return sum;
    }

    //just for test
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        String s= input.next();
        String[] arr = s.split(",");
        int[] arry = new int[arr.length];
        for(int i=0;i<arr.length;i++)
        {
            arry[i]=Integer.parseInt(arr[i]);
        }
        int result = maxSubarray(arry);
        System.out.println(result);
    }
}

发布了21 篇原创文章 · 获赞 4 · 访问量 1356

猜你喜欢

转载自blog.csdn.net/smile001isme/article/details/105038375