一条小船用来运输古董到河对岸。假设船的最大载重量为MAXWEIGHT,每件古董的重量为,怎么能够装载最多数量的古董到船上呢?
样例数据:
MAXWEIGHT 为 30
给定8个古董,重量分别为:[4, 10, 7, 11, 3, 5, 14, 2]
算法分析
这个问题是一个典型的可以使用贪心算法解决的问题。
通过分析题目可以看到,小船的载重量(MAXWEIGHT)是固定的,要求装载的物品数量最多,那么应该优先选择把重量最小的物品装上船,然后不断装载剩余的物品,直到达到小船载重量的要求。
选择先装载重量最小的物品,这个选择策略就采用了贪心(Greedy)策略,从局部最优达到全局最优,从而产生最优装载问题的最优解。
算法设计与实现
package com.bean.algorithm.learning;
import java.util.Arrays;
public class OptimizedLoading {
public static int MAXWEIGHT = 30;// 小船的载重量
public static int AMOUNT = 8;// 古董个数
/*
* 装载算法(贪心算法)
* */
public static int maxLoading(int[] weight) {
//计数器,用于记录装载到小船上古董的数量
int counter = 0;
// 对weight数组进行排序
Arrays.sort(weight);
int temp = 0; // 记录装载到船上的古董重量
for (int i = 0; i < AMOUNT; i++) {
temp += weight[i]; // 贪心策略:每次装入最轻者
if (temp <= MAXWEIGHT) // 若加入最轻者后还小于载重量,则古董个数+1
counter++;
else
//超重,不能装载
break;
}
//返回装载的古董的数量
return counter;
}
public static void main(String[] args) {
int ANSWER = 0; // 记录已装载的古董个数
int[] weight = { 4, 10, 7, 11, 3, 5, 14, 2 };
ANSWER = maxLoading(weight);
System.out.println("能装入的古董最大数量为: " + ANSWER);
}
}
程序运行结果:
能装入的古董最大数量为: 5
设有n个活动的集合e={1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。每个活动i都有一个要求使用该资源的起始时间s_i和一个结束时间f_i,且s_i< f_i。如果选择了活动i,则它在半开时间区间[s_i,f_i]内占用资源。若区间[s_i,f_i]与区间[s_j,f_j]不相交,则称活动 i 与活动 j 是相容的。也就是说,当s_i ≥ f_i或s_j ≥ f_j时,活动 i 与活动 j 相容。活动安排问题就是要在所给的活动集合中选出最大的相容活动子集合。
在下面所给出的解活动安排问题的贪心算法gpeedyselector中,各活动的起始时间和结束时间存储于数组s和f{中且按结束时间的非减序:.f_1 ≤ f_2 ≤ … ≤ f_n排列。如果所给出的活动未按此序排列,我们可以用o(nlogn)的时间将它重排。
package com.bean.algorithm.beginner;
import java.util.ArrayList;
import java.util.List;
public class ActivitiesDemo {
public static List arrangeActivity(int[] start, int[] end) {
int total = start.length;
int endFlag = end[0];
List results = new ArrayList<>();
results.add(0);
for (int i = 0; i < total; i++) {
if (start[i] > endFlag) {
results.add(i);
endFlag = end[i];
}
}
return results;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] start = { 1, 3, 0, 5, 3, 5, 6, 8, 8, 2, 12 };
int[] end = { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
List results = arrangeActivity(start, end);
for (int i = 0; i < results.size(); i++) {
int index = results.get(i);
System.out.println("开始时间:" + start[index] + ",结束时间:" + end[index]);
}
}
}
程序运行结果:
开始时间:1,结束时间:4
开始时间:5,结束时间:7
开始时间:8,结束时间:11
开始时间:12,结束时间:14
给定一根长度为n的绳子,请把绳子剪成m段,每段绳子记为k[0],k[1]……k[m]。请问k[0]*k[1]……*k[m]可能的最大乘积是多少?例如:当绳子长度为8时,我们把它剪成长度分别为2,3,3段,此时最大乘积为18.
算法分析
从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到某算法中的某一步不能再继续前进时,算法停止,这就是贪婪算法。
在剪绳子中,如果绳子的长度大于5,则每次剪出的长度为3的绳子。如果剩下的长度仍然大于5,则接着剪出一段长度为3的绳子,重复这个步骤,直到剩下的长度小于5.时间和空间复杂度都为O(1)。
算法设计
可以参考我的另外一篇博文:https://blog.csdn.net/seagal890/article/details/89607705
package com.bean.algorithm.basic;
public class CutForMaxProduct4 {
// Greedy solution for Max Product Problem
public static int maxProd(int length) {
if (length < 2)
return 0;
if (length == 2)
return 1;
if (length == 3)
return 2;
int timesOf3 = length / 3; //剪长度为3的绳子段
if ((length - timesOf3 * 3) == 1) // 当长度为4的时候不能去用3剪
timesOf3 -= 1;
int timesOf2= (length - timesOf3* 3) / 2; // 这时应该把绳子剪成长度为2的两段:2*2>1*3
return ((int)(Math.pow(3, timesOf3))*((int)Math.pow(2, timesOf2)));
}
/* Driver program to test above functions */
public static void main(String[] args) {
System.out.println("Maximum Product is " + maxProd(10));
}
}
程序运行结果:
Maximum Product is 36
机器人在一个无限大小的网格上行走,从点 (0, 0) 处开始出发,面向北方。该机器人可以接收以下三种类型的命令:
-2:向左转 90 度
-1:向右转 90 度
1 <= x <= 9:向前移动 x 个单位长度
在网格上有一些格子被视为障碍物。
第 i 个障碍物位于网格点 (obstacles[i][0], obstacles[i][1])
如果机器人试图走到障碍物上方,那么它将停留在障碍物的前一个网格方块上,但仍然可以继续该路线的其余部分。
返回从原点到机器人的最大欧式距离的平方。
示例 1:
输入: commands = [4,-1,3], obstacles = []
输出: 25
解释: 机器人将会到达 (3, 4)
示例 2:
输入: commands = [4,-1,4,-2,4], obstacles = [[2,4]]
输出: 65
解释: 机器人在左转走到 (1, 8) 之前将被困在 (1, 4) 处
提示:
0 <= commands.length <= 10000
0 <= obstacles.length <= 10000
-30000 <= obstacle[i][0] <= 30000
-30000 <= obstacle[i][1] <= 30000
答案保证小于 2 ^ 31
算法分析
算法设计
class Solution {
public int robotSim(int[] commands, int[][] obstacles) {
if(commands == null || commands.length == 0)
return 0;
Set obstacleSet = new HashSet<>();
for(int[] o : obstacles)
obstacleSet.add(o[0] + "," + o[1]);
int maxVal = 0, direction = 0, x = 0, y = 0;
int[][] directions = {{0,1},{1,0},{0,-1},{-1,0}};
for(int command : commands){
if(command == -1){
direction = (direction + 1) % 4;
}else if(command == -2){
direction = (direction - 1) % 4;
if(direction < 0)
direction += 4;
}else if(command >= 1 && command <= 9){
for(int i=0; i
另外一种算法设计
class Solution {
public int robotSim(int[] commands, int[][] obstacles) {
int[][] walk = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
Map map = new HashMap<>();
for (int i = 0; i < obstacles.length; i++)
map.put(obstacles[i][0] + "," + obstacles[i][1], true);
int p = 0, q = 0, k = 0;
int max = 0;
for (int command : commands) {
if (command == -1)
k = (k + 1) % 4;
else if (command == -2)
k = (k - 1 + 4) % 4;
else {
for (int i = 0; i < command; i++) {
if (map.containsKey((p + walk[k][0]) + "," + (q + walk[k][1])))
break;
p += walk[k][0];
q += walk[k][1];
max = Math.max(max, p * p + q * q);
}
}
}
return max;
}
}
给定一个用字符数组表示的 CPU 需要执行的任务列表。其中包含使用大写的 A - Z 字母表示的26种不同种类的任务。任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。CPU 在任何一个单位时间内都可以执行一个任务,或者在待命状态。
然而,两个相同种类的任务之间必须有长度为 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务,或者在待命状态。
你需要计算完成所有任务所需要的最短时间。
示例 1:
输入: tasks = ["A","A","A","B","B","B"], n = 2
输出: 8
执行顺序: A -> B -> (待命) -> A -> B -> (待命) -> A -> B.
注:
任务的总个数为 [1, 10000]
n 的取值范围为 [0, 100]
算法分析
算法设计
package com.bean.algorithm.learning;
import java.util.Arrays;
public class TaskScheduler {
public int leastInterval(char[] tasks, int n) {
// count char freq, task name doesn't matter, only freq matters
int[] freq = new int[26];
for (char c : tasks)
freq[c - 'A']++;
// sort first, so we have max freq at freq[25]
Arrays.sort(freq);
int time = 0;
while (freq[25] > 0) { // while we still have task to do, start from most freq task
// GREEDY
// each round/row, try to finish n tasks
for (int i = 0, p = 25; i <= n; i++) { // n is the cooling down factor, p points to the next task to consume
if (p >= 0 && freq[p] > 0) { // if there is still task to do
freq[p]--; // do task
p--; // move p to next freq task
time++; // take one cycle
} else if (freq[25] != 0) { // if this is NOT last row, need to fill in idle cycle
time++; // take one cycle
} // else freq[25] == 0 . no more task to do and last row. we WON'T fill in idle
// cycle
}
// sort again so next round we're going to start from most freq task and consume
// n task if possible
Arrays.sort(freq);
}
return time;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
TaskScheduler taskScheduler=new TaskScheduler();
char[] tasks= {'A','A','A','B','B','B'};
int n=2;
int result=-1;
result=taskScheduler.leastInterval(tasks, n);
System.out.println("result = "+result);
}
}
程序运行结果:
result = 8
给定一个字符串S,检查是否能重新排布其中的字母,使得两相邻的字符不同。
若可行,输出任意可行的结果。若不可行,返回空字符串。
示例 1:
输入: S = "aab"
输出: "aba"
示例 2:
输入: S = "aaab"
输出: ""
注意:
S 只包含小写字母并且长度在[1, 500]区间内。
算法分析
给定一个字符串,挪动给定的字符串中字符的位置,使得返回的字符串需要相邻的两个字符不能相同。
思路:
算法设计
class Solution {
public String reorganizeString(String S) {
int[] arr = new int[26];
int lenght = S.length();
if(S.length() == 1) return S;
char[] ret = new char[lenght];
int maxLength = 0;
for(char a: S.toCharArray()) {
if(maxLength < ++arr[a - 'a'])
maxLength = arr[a - 'a'];
}
if(maxLength * 2 - 1 > S.length())
return "";
int odd = 0, even = 1;
for(int i = 0; i < 26; i++) {
while(arr[i] > 0 && arr[i] < lenght / 2 + 1 && even < lenght) {
ret[even] = (char)(i + 'a');
arr[i] --;
even += 2;
}
while(arr[i] > 0) {
ret[odd] = (char)(i + 'a');
arr[i] --;
odd += 2;
}
}
return new String(ret);
}
}