贪心算法
最佳支付方法
1元、5元、10元、20元、100元、200元的钞票支付X元(1,5,10,20,100,200是成倍数关系)
思路:
成倍数关系意味着,大额一定可以用小额表示,所以尽量先用大额。
import java.util.Scanner;
/**
* @Author: TJW
* @Description:
* @Date: 2018/12/9
*/
public class Greedy_coins {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int total = scanner.nextInt();
int coins[] = new int[]{1,5,10,20,100,200};
int numOfCoins[] = new int[]{9,8,7,3,1,3};//每一枚硬币最大数目限制
int sum = 0;
int left = total;
for(int i=coins.length-1;i>=0;i--){
if(left>=0){
int num = Math.min(numOfCoins[i],left/coins[i]);
left-=num*coins[i];
sum+=num;
}
}
System.out.println(sum);
}
}
如果零钱不是倍数关系,使用动态规划求解,可以看
https://blog.csdn.net/xiaowei_innocence/article/details/84893683
摇摆序列
给定一个序列,找出最长摇摆序列(相邻的数值差呈正负交替出现)
思路:
找到子序列递增或递减的头尾,忽略中间部分。
package GreedyAlgorithm;
/**
* @Author: TJW
* @Description:
* @Date: 2018/12/10
*/
public class Greedy_swing_array {
/*
贪心规律: 当序列有一段连续的递增(或递减)时,为形成摇摆子序列,
我们只需要保留这段连续的递增(或递减)的首尾元素,
这样更有可能使得尾部的后一个元素成为摇摆子序列的下一个元素。
*/
public static void main(String[] args) {
int[] array = new int[]{1,17,5,10,13,15,10,5,16,8};
int start = 0;
int up = 1;
int down = 2;
int state = start;
int length = 1;
for(int i=1;i<array.length;i++){
switch (state){
case 0:
if(array[i]>array[i-1]){
state = up;
length++;
}
if(array[i]<array[i-1]){
state = down;
length++;
}
break;
case 1:
if(array[i]<array[i-1]){
state = down;
length++;
}
break;
case 2:
if(array[i]>array[i-1]){
state = up;
length++;
}
break;
}
}
System.out.println(length);
}
}
移除K个数字
已知一个使用字符串表示非负整数num,将num中的k个数字移除,求移除k个数字后,可以获得的最小的可能的新数字
思路:
遍历的数字大于栈顶元素,则将该数字push入栈,如果小于栈顶元素则进行pop弹栈,直到栈为空,或者不能再删除数字(k==0)或栈顶小于当前元素为止。
特殊情况:
第一种特殊情况:一种特殊情况是在栈为空的时候,进去的为0,例如数字是num=100200,此时先取出1,1进入栈,但是第二个0的时候,此时1出栈,但0不能进栈,因为此时栈内为空。
第二种特殊情况:数字是单调递增的时候,例如12345678,此时在入栈完成后,检查栈的大小,如果栈的size()大于原先的字符串中的数字的长度减去2,此时要做处理,直接删除最后的两个数字。
package GreedyAlgorithm;
import org.omg.Messaging.SYNC_WITH_TRANSPORT;
import java.util.Stack;
/**
* @Author: TJW
* @Description:
* @Date: 2018/12/10
*/
public class Greedy_remove_k {
public static void main(String[] args) {
String num = "100200";
int k = 3;
Stack<Integer> stack = new Stack<>();
for(int i=0;i<num.length();i++){
Integer temp = Integer.parseInt(num.substring(i,i+1));
if(!temp.equals(0)){
stack.push(temp);
break;
}
}
/*
如果遍历的数字大于栈顶元素,则将该数字push入栈,
如果小于栈顶元素则进行pop弹栈,
直到栈为空,或者不能再删除数字(k==0)或栈顶小于当前元素为止
*/
for(int i=1;i<num.length();i++){
Integer before = stack.pop();
stack.push(before);
Integer current = Integer.parseInt(num.substring(i,i+1));
if(current>=before){
stack.push(current);
}else{
if(current.equals(0)){
int temp = stack.pop();
k--;
while (temp!=0&&!stack.empty()&&k>=0){
temp = stack.pop();
k--;
}
stack.push(temp);
k++;
stack.push(current);
}else{
while(before>current&&k>=0){
before = stack.pop();
k--;
}
stack.push(before);
k++;
stack.push(current);
}
}
/*System.out.println(i+":"+stack);
System.out.println("k:"+k);*/
}
for(int i=0;i<stack.size()&&i<num.length()-k;i++){
System.out.print(stack.get(i));
}
}
}
跳跃游戏
一个数组存储了非负整型数据,数组中第i个元素nums[i],代表了可以从数组第i个位置最多向前跳跃nums[i]步,已知数组各元素的情况下,求是否可以从数组第0个位置跳跃到数组的最后一个元素的位置。
思路:
贪心算法就是在相同选择数目里要走更多的路,故如果选两个num[i1],num[i1+x],0<=x<=num[i],应该要最远路径。如果不可到达,则是要停滞在某个位置。
package GreedyAlgorithm;
/**
* @Author: TJW
* @Description:
* @Date: 2018/12/10
*/
public class Greedy_min_steps {
public static void main(String[] args) {
//int num[] = new int[]{3,2,1,0,4};
int num[]={2,3,1,1,1,4};
int count = 0;
int loc = 0;
while(loc!=num.length-1){
int max_step = 0;
int j = -1;//记录步数
for(int i=1;i<=num[loc];i++){
if(max_step<=(num[i]+i)){
max_step = num[i]+i;
j=i;
}
}
if(j!=-1){
if(num[j]+j==j&&j!=num.length-1){
count=-1;
break;
}
}
loc+=j;
count++;
}
if(count==-1){
System.out.println("cannot access");
}else{
System.out.println("steps:"+count);
}
}
}
射气球问题
已知在一个平面上有一定数量的气球,平面可以看作是一个坐标系,在平面的x轴的不同位置安排弓箭手向y轴方向射箭,弓箭可以向y轴走无穷远,给定气球的宽度xstart<=x<=xend,问至少需要多少弓箭手,将全部气球打爆?
思路:
对于某个气球,至少需要使用1只弓箭将它击穿,在这只气球将其击穿的同时,尽可能击穿其他更多的气球。(这里体现了贪心的思想)
先按左坐标排序,然后选择看右坐标判断是否重叠,虽然看了几个博客都说要维护一个射手区间,但是射手区间应该只用到了右坐标,和左坐标无关。
package GreedyAlgorithm;
import java.util.ArrayList;
import java.util.Collections;
/**
* @Author: TJW
* @Description:
* @Date: 2018/12/10
*/
class Node implements Comparable<Node>{
int left;
int right;
public Node(int left, int right){
this.left = left;
this.right = right;
}
@Override
public int compareTo(Node o) {
return left-o.left;
}
}
public class Greedy_shot {
public static void main(String[] args) {
ArrayList<Node> list = new ArrayList<>();
Node n1 = new Node(10,16);
Node n2 = new Node(2,8);
Node n3 = new Node(1,6);
Node n4 = new Node(7,12);
list.add(n1);
list.add(n2);
list.add(n3);
list.add(n4);
Collections.sort(list);
//int start = n1.left;
int end = n1.right;
int count = 1;
for(int i=1;i<list.size();i++){
if(list.get(i).left<=end){
//start = list.get(i).left;
if(list.get(i).right<end){
end = list.get(i).right;
}
}else{
//start = list.get(i).left;
end = list.get(i).right;
count++;
}
}
System.out.println("count:"+count);
}
}
参考:
https://blog.csdn.net/chenkaibsw/article/details/80214911
https://blog.csdn.net/bajin7353/article/details/80703727