贪心算法
定义
贪心算法,又称贪婪算法。一种分级处理方法,是指在解决问题时,将完整的问题划分成多个步骤,认为只要每个步骤都是最优解(也就是局部最优解),最终得到的结果就是最优的。
实质上,贪心算法得到的并不是全局最优解,全局最优解需要采用动态规划算法。
思路
贪心算法一般按如下步骤进行:
- 建立数学模型来描述问题 。
- 把求解的问题分成若干个子问题 。
- 对每个子问题求解,得到子问题的局部最优解 。
- 把子问题的解局部最优解合成原来解问题的一个解
简易算法模型
Soulution() {
建立数学模型
拆解子问题
找寻目标
while(下一步还有子问题待解决){
获得子问题的局部最优解
}
根据目标整合每一步的局部最优解推导至全局最优解
}
经典例题
股票买卖最佳时机
问题分析
-
建立模型
-
变量:
已知 n 天的股票价格 prices[0: n-1]
-
操作:
经过 n 天之后,其中第 i 天买入,第r天卖出的多轮操作,买入和卖出可以是同一天
-
目标:
获得最大的利润
-
-
拆解成子问题
为简化分析,把一对买入卖出操作简化为当天买入,第二天卖出。 (这一点非常重要)
在不考虑手续费的情况下,比如 第1天买入,第3天卖出。
实质上等同于 第一天买入,第二天卖出,第二天买入,第三天卖出。
-
子问题的局部最优解
因为问题简化为当天买入,隔天卖出,那么只要确定全部买入的时机即可。
很明显,只要能盈利就是买入时机,盈利也就是 第二天价格 > 第一天 即可。
-
局部是否可以推导成全局最优
根据上面的拆解,只要每个操作都盈利,且所有能盈利的时机都操作了,那么可以认为即使从全局的角度来看,也实现了全部最优。
代码实现
/**
* 贪心算法计算最大利润(不考虑交易次数)
* @param nums
* @return
*/
public static int maxProfit(int[] nums) {
int count = 0;
int length = nums.length -1;
List<Integer> buyList = new ArrayList<>();
for (int i = 0; i < length; i++) {
int profit = Math.max(0, nums[i+1] - nums[i]);
if (profit > 0) {
count += profit;
buyList.add(i);
}
}
System.out.println(buyList);
return count;
}
/**
* 贪心算法计算最大利润(尽可能少的交易次数)
* @param nums
* @return
*/
public static int maxProfitPro(int[] nums) {
int count = 0;
int length = nums.length -1;
LinkedList<Integer> buyList = new LinkedList<>();
for (int i = 0; i < length; i++) {
int profit = Math.max(0, nums[i+1] - nums[i]);
if (profit > 0 ) {
count += profit;
buyList.add(i);
}
}
//
int size = buyList.size();
size = size -1;
Set<Integer> result = new LinkedHashSet<>();
Set<Integer> index = new LinkedHashSet<>();
result.add(buyList.get(0));
index.add(0);
for (int i = 1; i < size; i++) {
Integer pre = buyList.get(i - 1);
Integer current = buyList.get(i);
Integer next = buyList.get(i+1);
if (index.contains(i-1)) {
if (current-pre!=1) {
result.add(current);
index.add(i);
}
} else {
if (next-current!=1) {
result.add(current);
index.add(i);
}
}
}
result.add(buyList.get(size));
System.out.println(buyList);
System.out.println(result);
return count;
}
测试结果
public static void main(String[] args) {
int[] nums = {1,5,6,9,2,4,6,6,10};
int maxProfit = maxProfit(nums);
System.out.println(maxProfit);
int maxProfitPro = maxProfitPro(nums);
System.out.println(maxProfitPro);
}
//输出
[0, 1, 2, 4, 5, 7]
16
[0, 1, 2, 4, 5, 7]
[0, 2, 4, 7]
16