贪心例题:跳跃游戏
题干: 给定一个非负整数数组,假定你的初始位置为数组第一个下标,数组中的每个元素代表你在那个位置能够跳跃的最大长度,请确认你是否能够跳跃到数组的最后一个下标。
从起点开始选择第二个,并不是说第一步跳就选最远的,而是寻找一种一定能满足的关系,就像数学归纳法一样,每一步的贪心都能保证最终的结果,所以只有都满足递推关系了才进行贪心。
所以第一步选最远的那个只是保证了起点这个位置是跳最远的,只是贪心了一步,这里的贪心应该是考虑起点所能跳的位置以及该位置所支持跳到的再下一个最远距离两个因素。
你会发现这个规律:(本节点所选的下一位置距离+该“下一节点”所能跳的距离)的最大值 = 最优解,假设有abc三个节点可到达,而c节点满足这个关系,所以选择跳到c为什么呢?不选ab不会错过最优解吗?
原因是选了c就确定了所能到达的范围一定是最远的,因为位置a和位置b能到达的位置, 位置c都可以到达; 这个距离是可到达的最远距离,也就是起点跳到该节点c的距离+c所能到达的最大距离,保证这个最大就是最远距离,不断地循环,直到到达终点,或者c的可跳距离为0(因为只要可跳不为0就一定能到达终点,就一下跳一个呗)
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| import java.util.Scanner; public class Main{ public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt();
int[]a = new int[n]; for(int i= 0 ;i< n ;i++) { a[i] = sc.nextInt(); } int i; int l; int r; for( i= 0 ;i< n && a[i]!= 0 ;) { r = i + a[i]; l = i + 1; for(int j= i+1 ;j< n && j<= i+a[i] ;j++) { if(j+a[j] >= r){ r = j+ a[j]; l = j; } } i = l; } if(i< n-1) { System.out.println("false"); }else{ System.out.println("true"); } } }
|
DFS和回溯息息相关,那么贪心和动态规划呢?两者都是利用归纳法去寻找一种确定的递推关系。
区别点:贪心问题的每一步都是局部最优解,不一定有一个确定的公式,而动态规划总体最优解是局部最优解的一个,所以我们贪心时无需保存每一步,只需要保证最优即可,而动态规划需要有一个dp[i]保存局部解。
典例:活动安排问题
上面的两种解决方法都是经过数学归纳法证明的,不一定是唯一最优解,但一定是最优解(之一)
经过代码分析:可以得知贪心的时间复杂度是O(n2)
活动安排会场相对比较复杂,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| package cupidity;
import java.util.Scanner;
public class pj1 { public static void main(String[] args) { Scanner input = new Scanner(System.in); int num = -1; int geshu = 0; num = input.nextInt();
int[] s = new int[num]; int[] f = new int[num]; for (int i = 0; i < num; i++) { s[i] = input.nextInt(); f[i] = input.nextInt(); }
for (int i = 0; i < s.length; i++) { int temp1 = 0; int temp2 = 0; for(int j = i+1; j < s.length; j++) { if (s[i] > s[j]) { temp1 = s[i]; s[i] = s[j]; s[j] = temp1; temp2 = f[i]; f[i] = f[j]; f[j] = temp2; } } } int[] anpai = new int[num]; for (int i = 0; i < num; i++) { for (int j = 0; j < num; j++) { if (anpai[j] < s[i]) { anpai[j] = f[i]; break; } } } for (int i = 0; i < num; i++) { if (anpai[i] != 0) { geshu++; } } System.out.println("至少安排的会场个数:"+geshu); } }
|
附一个插入排序代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| package TestSort;
import java.util.Arrays;
public class Test_InsertSort { public static void InsertSort(int[] arr){ int insertVal = 0; int insertIndex = 0; for(int i = 1; i < arr.length; i++){ insertVal = arr[i]; insertIndex = i - 1;
while(insertIndex >= 0 && insertVal < arr[insertIndex]){ arr[insertIndex + 1] = arr[insertIndex]; insertIndex--; }
if(insertIndex + 1 != i){ arr[insertIndex + 1] = insertVal; } }
}
public static void main(String[] args) { int[] arr = {23, 43, 3, 32, 67, 78, 34, 56}; System.out.println("排序前:"); System.out.println(Arrays.toString(arr));
InsertSort(arr);
System.out.println("排序后:"); System.out.println(Arrays.toString(arr)); }
}
|
如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !