股票交易日
在股市的交易日中,假设最多可进行两次买卖(即买和卖的次数均小于等于2),规则是必须一笔成交后进行另一笔(即买-卖-买-卖的顺序进行)。给出一天中的股票变化序列,请写一个程序计算一天可以获得的最大收益。请采用实践复杂度低的方法实现。
给定价格序列prices及它的长度n,请返回最大收益。保证长度小于等于500。
如下:
[10, 22, 5, 75, 65, 80], 6
返回:
87
风口的猪
风口之下,猪都能飞。当今中国股市牛市,真可谓“错过等七年”。 给你一个回顾历史的机会,已知一支股票连续n天的价格走势,以长度为n的整数数组表示,数组中第i个元素(prices[i])代表该股票第i天的股价。
假设你一开始没有股票,但有至多两次买入1股而后卖出1股的机会,并且买入前一定要先保证手上没有股票。若两次交易机会都放弃,收益为0。 设法计算你能获得的最大收益。 输入数值范围:2<=n<=100,0<=prices[i]<=100
输入:
[3, 8, 5, 1, 7, 8] 6
返回:
12
public class Stock {
public static void main(String[] args) {
// int[] dataSet = {10, 22, 5, 75, 65, 80};
int[] dataSet = {3, 8, 5, 1, 7, 8};
int result = maxProfit(dataSet, dataSet.length);
System.out.println(result);
}
public static int maxProfit(int[] dataSet, int n) {
int sum = 0;
for (int i = 0; i < dataSet.length; i++) {
int tmp = getMax(dataSet, 0, i - 1) + getMax(dataSet, i, dataSet.length-1);
if (tmp > sum) {
sum = tmp;
}
}
return sum;
}
private static int getMax(int[] dataSet, int left, int right) {
if (left >= right) {
return 0;
}
int min = dataSet[left];
int max = 0;
for (int i = left; i <= right; i++) {
if (dataSet[i] - min > max) {
max = dataSet[i] - min;
}
if (dataSet[i] < min) {
min = dataSet[i];
}
}
return max;
}
}
最长公共字串
求两个字符串的最长公共子串,如“abcdefg”和“adefgwgeweg”的最长公共子串为“defg”(子串必须是连续的)
public class MaxSubString {
public static void main(String[] args) {
String str1 = "abcdefg";
String str2 = "adefgwgeweg";
System.out.println(getMaxSubString(str1, str2));
}
public static List<String> getMaxSubString(String str1, String str2) {
if (StringUtils.isEmpty(str1) || StringUtils.isEmpty(str2)) {
return null;
}
String max;
String min;
if (str1.length() > str2.length()) {
max = str1;
min = str2;
} else {
max = str2;
min = str1;
}
List<String> subStrings = Lists.newArrayList();
String maxSubString = StringUtils.EMPTY;
for (int i = 0; i < min.length(); i++) {
for (int begin = 0, end = min.length() - i; begin < end; begin++) {
String tmp = min.substring(begin, end);
if (max.contains(tmp) && tmp.length() >= maxSubString.length()) {
maxSubString = tmp;
subStrings.add(maxSubString);
}
}
}
return subStrings;
}
}
回文串
给定一个字符串,问是否能通过添加一个字母将其变为回文串。
输入:
coco
返回:
true
public class PharseString {
public static void main(String[] args) {
String str = "coco";
System.out.println(isPhraseString(str));
}
public static boolean isPhraseString(String str) {
for (int i = 1; i < str.length() / 2; i++) {
if (str.toCharArray()[i] != str.toCharArray()[str.length() - i]) {
return false;
}
}
return true;
}
}
最大公约数和最小公倍数
public class MaxCommonDivisorAndMinCommonMultiple {
public static void main(String[] args) {
int m = 8;
int n = 12;
System.out.println(maxCommonDivisor(m, n) + " " + minCommonMultiple(m, n));
}
public static int maxCommonDivisor(int m, int n) {
if (m < n) {
int tmp = m;
m = n;
n = tmp;
}
while (n != 0) {
int tmp = m % n;
m = n;
n = tmp;
}
return m;
}
public static int minCommonMultiple(int m, int n) {
return m * n / maxCommonDivisor(m, n);
}
}
字典序列化
我们程序中用到了一个数组 a ,数组的每个元素都是一个字典(map/dict)。
字典的 key/value 都是字符串,字符串中可包含任意字符。
示例:
a[0]["k1"] = "v1"
a[0]["k2"] = "v2"
a[1]["A"] = "XXX"
...
实际使用过程中,我们自定义了一个基于字符串的存储结构,数组元素之间用“换行”分割,
字典元素之间使用“分号”分割, key/value 之间用“等号”分割。
上述数据序列化之后,应该得到一个字符串:
"k1=v1;k2=v2\nA=XXX"
请实现一个“保存”函数、一个“加载”函数。
text = store(a); //把数组保存到一个字符串中
a = load(text); //把字符串中的内容读取为字典数组
请考虑所有边界情况,不要出现bug。在满足上述需求的前提下,可自行增加一些规则和约定。
// 约定:每个字典的key/value不能为 换行、分割、等号
public class Test {
public static void main(String[] args) {
// List<Map<String, String>> mapList = Lists.newArrayList();
// Map<String, String> map1 = Maps.newHashMap();
// map1.put("k1", "v1");
// map1.put("k2", "v2");
// mapList.add(map1);
// Map<String, String> map2 = Maps.newHashMap();
// map2.put("A", "XXX");
// map2.put("B", " ");
// map2.put(" ", "C");
// map2.put(" ", " ");
// mapList.add(map2);
// Object[] strings = mapList.toArray();
// String result = store(strings);
// System.out.println(result);
String str = "k1=v1;?=、";
Object[] objects = load(str);
System.out.println(objects);
}
private static String store(Object[] strings) {
StringBuilder str = new StringBuilder();
for (int i = 0; i < strings.length; i++) {
Map<String, String> map = (Map<String, String>) strings[i];
int j = 0;
for (String key : map.keySet()) {
str.append(key).append("=").append(map.get(key));
if (j < map.size() - 1) {
str.append(";");
}
j++;
}
if (i < strings.length - 1) {
str.append("\\n");
}
}
return str.toString();
}
private static Object[] load(String str) {
List<Map<String, String>> mapList = Lists.newLinkedList();
String[] maps = str.split("\n");
for (int i = 0; i < maps.length; i++) {
Map map = Maps.newLinkedHashMap();
String[] keyValues = maps[i].split(";");
for (int j = 0; j < keyValues.length; j++) {
String[] keyValue = keyValues[j].split("=");
if (keyValue.length == 2) {
map.put(keyValue[0], keyValue[1]);
}
}
mapList.add(map);
}
return mapList.toArray();
}
}
路径规划
我们有一个有向无环图,权重在节点上。
需求:从一个起点开始,找到一条节点权重之和最大的最优路径。
输入: n个节点,m个路径,起点
输出: 最优路径的权重值之和
举例:
3个节点与权重: A=1, B=2, C=2
3条路径: A->B, B->C, A->C
起点: A
输出: 5 (最优路径是 A->B->C , 权重之和是 1+2+2=5)
请考虑算法效率优化,考虑异常情况(比如输入的图有环路)要避免死循环或者崩溃。
public class Travel {
public static void main(String[] args) {
String[] vertex = {"a", "b", "c", "d", "e"};
int[] weight = {0, 1, 1, 3, 6};
double[][] matrix = {
{0, 1, 0, 1, 0},
{0, 0, 1, 0, 0},
{0, 0, 0, 0, 1},
{0, 0, 0, 0, 1},
{0, 0, 0, 0, 0}};
Graph<String> graph = new Graph<>(matrix, vertex, weight);
System.out.println(graph.getMinWeight(graph.startSearch()));
}
public static class Graph<T> {
// 邻接矩阵
private double[][] matrix;
// 顶点数组
private String[] vertex;
// 顶点数组对应权重值
private int[] weight;
// 顶点的数目
private int vertexNum;
// 当前结点是否还有下一个结点,判断递归是否结束的标志
private boolean noNext = false;
// 所有路径的结果集
private List<List<String>> result = Lists.newArrayList();
public Graph(double[][] matrix, String[] vertex, int[] weight) {
if (matrix.length != matrix[0].length) {
throw new IllegalArgumentException("该邻接矩阵不是方阵");
}
if (matrix.length != vertex.length) {
throw new IllegalArgumentException("结点数量和邻接矩阵大小不一致");
}
if (vertex.length != weight.length) {
throw new IllegalArgumentException("邻接矩阵大小和权重值数量不一致");
}
this.matrix = matrix;
this.vertex = vertex;
this.weight = weight;
vertexNum = matrix.length;
}
/**
* 深度遍历的递归
*/
private void DFS(int begin, List<String> path) {
// 将当前结点加入记录队列
path.add(vertex[begin]);
// 标记回滚位置
int rollBackNum = -1;
// 遍历相邻的结点
for (int i = 0; i < vertexNum; i++) {
if ((matrix[begin][i] > 0)) {
// 临时加入相邻结点,试探新的路径是否已遍历过
path.add(vertex[i]);
if (containBranch(result, path)) {
// 路径已存在,将相邻结点再移出记录队伍
path.remove(vertex[i]);
// 记录相邻点位置,用于循环结束发现仅有当前一个相邻结点时回滚事件
rollBackNum = i;
// 寻找下一相邻结点
continue;
} else {
// 路径为新路径,准备进入递归,将相邻结点移出记录队伍,递归中会再加入,防止重复添加
path.remove(vertex[i]);
// 递归
DFS(i, path);
}
}
// 终止递归
if (noNext) {
return;
}
}
if (rollBackNum > -1) {
// 循环结束仅有一个相邻结点,从这个相邻结点往下递归
DFS(rollBackNum, path);
} else {
// 当前结点没有相邻结点,设置flag以结束递归
noNext = true;
}
}
/**
* 开始深度优先遍历
*/
public List<List<String>> startSearch() {
for (int i = 0; i < countPathNumber(); i++) {
// 用于存储遍历过的点
List<String> path = new LinkedList<>();
noNext = false;
// 开始遍历
DFS(0, path);
// 保存结果
result.add(path);
}
return result;
}
/**
* 获取权重值最大的路径
*/
public MaxWeight getMaxWeight(List<List<String>> lists) {
Map<String, Integer> weightMap = Maps.newHashMap();
for (int i = 0; i < vertex.length; i++) {
weightMap.put(vertex[i], weight[i]);
}
int max = 0;
int index = 0;
for (int i = 0; i < lists.size(); i++) {
int w = 0;
for (String str : lists.get(i)) {
w += weightMap.get(str);
}
if (w > max) {
max = w;
index = i;
}
}
return new MaxWeight(lists.get(index), max);
}
/**
* 获取权重值最小的路径
*/
public MaxWeight getMinWeight(List<List<String>> lists) {
Map<String, Integer> weightMap = Maps.newHashMap();
for (int i = 0; i < vertex.length; i++) {
weightMap.put(vertex[i], weight[i]);
}
int min = 0;
int index = 0;
for (int i = 0; i < lists.size(); i++) {
int w = 0;
for (String str : lists.get(i)) {
w += weightMap.get(str);
}
if(min == 0){
min = w;
index = i;
}
if (w < min) {
min = w;
index = i;
}
}
return new MaxWeight(lists.get(index), min);
}
class MaxWeight {
private List<String> path;
private int weight;
public List<String> getPath() {
return path;
}
public void setPath(List<String> path) {
this.path = path;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public MaxWeight(List<String> path, int weight) {
this.path = path;
this.weight = weight;
}
@Override
public String toString() {
return "MaxWeight{" +
"path=" + path +
", weight=" + weight +
'}';
}
}
/**
* 计算路径的分支数量
*/
private int countPathNumber() {
int[] numberArray = new int[vertexNum];
for (int i = 0; i < vertexNum; i++) {
for (int j = 0; j < vertexNum; j++) {
if (matrix[j][i] > 0) {
numberArray[j]++;
}
}
}
int number = 1;
for (int k = 0; k < vertexNum; k++) {
if (numberArray[k] > 1) {
number++;
}
}
return number;
}
/**
* 判断当前路径是否被已有路径的结果集合所包含
*/
private boolean containBranch(List<List<String>> nodeLists, List<String> edges) {
for (List<String> list : nodeLists) {
if (list.containsAll(edges)) {
return true;
}
}
return false;
}
}
}
字符串全排列
public class Test {
public static void main(String[] args) {
String str = "abc";
allArrange(str.toCharArray(), 0);
}
public static void allArrange(char[] chars, int n) {
if (n == chars.length - 1) {
System.out.println(String.valueOf(chars));
}
for (int i = n; i < chars.length; i++) {
char tmp = chars[i];
chars[i] = chars[n];
chars[n] = tmp;
allArrange(chars, n + 1);
}
}
}
字符串转数字
public class Test {
public static void main(String[] args) {
String str = "123";
System.out.print(strToInt(str));
}
public static int strToInt(String str) {
int result = 0;
// 空字符串返回0
if (str.length() == 0) {
return result;
}
char[] chars = str.toCharArray();
char base = '0';
for (int i = chars.length; i > 0; i--) {
result += (chars[chars.length - i] - base) * Math.pow(10, i - 1);
}
return result;
}
}