很佩服面试出leetcode题的人。。。。。。老子不刷题,刷不完。。。写的不对就给你挂掉的人,牛逼。。。
腾讯面试体验最好,引导候选人一点点写。
https://leetcode-cn.com/problemset/all/
这个哥哥总结的很好
https://blog.csdn.net/weixin_33991418/article/details/91810578
在股市的交易日中,假设最多可进行两次买卖(即买和卖的次数均小于等于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 风口的猪 {
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”(子串必须是连续的)
import com.sun.deploy.util.StringUtils;
import java.util.List;
public class 最长公共子串 {
public static void main(String[] args) {
String str1 = "abcdefg";
String str2 = "adefgwgeweg";
System.out.println(getMaxSubString(str1, str2));
}
public static List 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 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;
}
}
public class 最大公约数和最小公倍数 {
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。在满足上述需求的前提下,可自行增加一些规则和约定。
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class 字典序列化 {
/**
*
*/
private static final long serialVersionUID = -546082353499911945L;
public static void main(String[] args) {
List
我们有一个有向无环图,权重在节点上。
需求:从一个起点开始,找到一条节点权重之和最大的最优路径。
输入: 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)
请考虑算法效率优化,考虑异常情况(比如输入的图有环路)要避免死循环或者崩溃。
import java.util.List;
import java.util.Map;
public class 路径规划 {
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 graph = new Graph<>(matrix, vertex, weight);
System.out.println(graph.getMinWeight(graph.startSearch()));
}
public static class Graph {
// 邻接矩阵
private double[][] matrix;
// 顶点数组
private String[] vertex;
// 顶点数组对应权重值
private int[] weight;
// 顶点的数目
private int vertexNum;
// 当前结点是否还有下一个结点,判断递归是否结束的标志
private boolean noNext = false;
// 所有路径的结果集
private List> 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 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> startSearch() {
for (int i = 0; i < countPathNumber(); i++) {
// 用于存储遍历过的点
List path = new LinkedList<>();
noNext = false;
// 开始遍历
DFS(0, path);
// 保存结果
result.add(path);
}
return result;
}
/**
* 获取权重值最大的路径
*/
public MaxWeight getMaxWeight(List> lists) {
Map 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> lists) {
Map 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 path;
private int weight;
public List getPath() {
return path;
}
public void setPath(List path) {
this.path = path;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public MaxWeight(List 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> nodeLists, List edges) {
for (List list : nodeLists) {
if (list.containsAll(edges)) {
return true;
}
}
return false;
}
}
}
}
public class 字符串全排列 {
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 字符串转数字 {
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;
}
}
day1:请找出数组中的某个数,它的左侧数字相加之和等于右边之和
PS 自己写了20多分钟,无百度 无粘贴。面试要求10分钟写完,可能么?需要说明的是,要判断数组长度为奇数 偶数,懒 只判断了偶数情况,奇数情况类似。
public class findSumIndex {
/**
* 逐一遍历
* @param array
* @return
*/
public static int findIndexSB(int array[]) {
for (int i = 1; i < array.length; i++) {
int totalLeft = 0;
for (int le = 0; le < i; le++) {
totalLeft += array[le];
}
int totalRight = 0;
for (int ri = i + 1; ri < array.length; ri++) {
totalRight += array[ri];
}
if (totalLeft == totalRight) {
return i;
}
}
return -1;
}
/**
* 二分查找
* @param array
* @return
*/
// 既然某个数字的左边的值等于右边,那么可以算出数组的全部数值,然后加入一个二分查找的办法,
// 定位到中间,如果左边的值*2=数组的和-当前位置的值,那么就可以说找到了,如果大于,那就向前移动,小于就向后移动
public static int findIndex2(int array[]) {
// 判断数组不为空 数组长度不为0
if (array == null || array.length == 0) {
return -1;
}
int length = array.length;
int left = 0;
int right = length - 1;
int middle = 0;
if (length % 2 == 0) {
middle = length / 2;
} else if (length % 2 != 0) {
middle = length / 2 + 1;
}
int total = 0;
// 计算数组总和
for (int i : array) {
total += i;
}
do {
// 判断中间index左边的和
int totalLeft = 0;
for (int le = 0; le < middle; le++) {
totalLeft += le;
}
// 数组总和减去中间元素 应该等于左右之和
int doubleV = (total - array[middle]);
// 左边之和*2小于总和 说明被查找的元素在middle右侧
// 1 1 1 1 1 3 2 1 2 如3是要找到位置
if (totalLeft * 2 < doubleV) {
// 要找的元素往后移动 中间index赋值给左侧index 从middle到右侧作为新的二分查找数组长度。中间到右侧再取一半
left = middle;
middle = middle + (length - middle) / 2;
// 左边之和*2大于总和 说明被查找的元素在middle左侧
} else if (totalLeft * 2 > doubleV) {
right = middle;
middle = left + (middle - left) / 2;
} else {
return middle;
}
} while (middle > left && middle < right);
{
return -1;
}
}
public static void main(String[] args) {
int[] arr = {1, 1, 1, 3, 2, 1};
// int[] arr = {1, 2, 3, 2, 1};
findIndex2(arr);
findIndexSB(arr);
System.out.println(findIndex2(arr));
System.out.println(findIndexSB(arr));
}
}
day2:两数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
import java.util.Arrays;
import java.util.HashMap;
/**
* 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那两个整数,并返回他们的数组下标
* 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍
*
* 示例:
* 给定 nums = [2, 7, 11, 15], target = 9
*
* 因为 nums[0] + nums[1] = 2 + 7 = 9
* 所以返回 [0, 1]
*/
public class twoNum {
public static int[] findIndex(int[] nums, int target) {
// map遍历
// 时间复杂度可能会是log(n),所以整体复杂度应该略大于O(n)
HashMap hm = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int a = nums[i];
int b = target - a;
hm.put(a, i);
if (hm.containsKey(b)) {
return new int[]{hm.get(b), i};
}
}
return null;
}
public static void main(String[] args) {
int[] arr = {2, 7, 11, 15};
int target = 9;
int[] toFind = findIndex(arr, target);
// 打印int数组
System.out.println(Arrays.toString(toFind));
}
}
day3:最长回文子串
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd"
输出: "bb"
待续。。。