1. 题目
- 给定一个数组,它的第i个元素是这支股价的第i天的价格,只能持有一股,买卖次数不限,无交易中介费。
- 二叉树的层次遍历:给定一个二叉树,返回其按层次遍历的节点值
2. 基本知识
2.1 贪心算法
2.1.1 定义
又叫贪婪算法,在对问题求解时,总是做出在当前看来最好的选择。
2.1.2 适用场景
- 问题能够分为子问题来解决,子问题的最优解能递推到最终问题的最优解。
- 贪心与动态规划的不同在于,它对每个子问题的解决方案都做出选择,不能回退。而动态规划则会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能。
2.2 深度优先和广度优先搜索
2.2.1 广度优先搜索
又叫BFS(Breadth First Search),是最简便的图的搜索算法之一。
广度优先使用队列(Queue)来实现,整个过程可以看做一个倒立的树形。
- 把根节点放到队列的末尾
- 每次从队列的头部取出一个元素,查看他的所有下一级元素,把他们放到队列的队尾,并把这些元素记为下一级的前驱
- 找到所要找的元素时结束程序
- 如果遍历完整个树,也结束程序
2.2.2 深度优先搜索
又叫DFS(Depth First Search),对每一个可能的分支路径深入到不能深入位置,而且每个节点只访问一次。
深度优先所有使用栈(Stack)来实现,整个过程可以看做倒立的树形
- 把根节点压入栈
- 每次从栈中弹出一个元素,并把它压入栈中,标记为下一个节点的前驱
- 找到所要找的元素结束
- 如果整个树遍历完,也结束程序
3. 算法题解题
3.1 给定一个数组,它的第i个元素是这支股价的第i天的价格,只能持有一股,买卖次数不限,无交易中介费。
解法1:暴力解法
两层循环,找到每个元素和之后元素的最大差值,加上之前的利润数据,得到最大的利润数。
时间复杂度为O(n2),空间复杂度也为O(1)
public static int maxProfit(int[] prices){
return calculate(prices, 0);
}
private static int calculate(int[] prices ,int start){
if (start >= prices.length)
return 0;
int max= 0;
for (int i = start; i < prices.length - 1; i++) {
for (int j = i +1; j< prices.length-1;j++){
int temp = 0;
if (prices[i] < prices[j]){
temp = calculate(prices, j + 1) + prices[j] - prices[i];
if (max < temp)
max = temp;
}
}
}
return max;
}
解法2:贪心算法
只要后一天比前一天价格高,那么就卖出,把所有天数之前的利润差值加起来就是总利润数
时间复杂度O(n) 空间复杂度O(1)
public static int maxProfit(int[] prices){
int profit = 0;
for (int i = 1; i < prices.length; i++) {
if (prices[i] > prices[i-1]){
profit +=prices[i] - prices[i-1];
}
}
return profit;
}
3.2 二叉树的层次遍历:给定一个二叉树,返回其按层次遍历的节点值
解法1: 递归
使用的广度优先搜索,不断递归遍历左右子树,同时记录层数,直到左右子节点都没有为止。
解法时间复杂度O(n), 空间复杂度O(n)
List<List<Integer>> lists = new ArrayList<List<Integer>>();
public List<List<Integer>> levelOrder(TreeNode root){
if (root == null) return lists;
helper(root, 0);
return lists;
}
private void helper(TreeNode node, int level) {
if (lists.size() == level){
lists.add(new ArrayList<Integer>());
lists.get(level).add(node.val);
if (node.left != null){
// 遍历左子树
helper(node.left,level +1);
}
if (node.right != null){
// 遍历右子树
helper(node.right,level + 1);
}
}
}
解法2:迭代
迭代法也是使用的广度优先搜索,使用Queue的数据结构辅助计算,在每次将当前的值添加到list中之后,判断是否有左右节点,如果有,就都添加到Queue中,等到执行到下个level时,再遍历所有TreeNode,重复上一个步骤,直到所有节点处理完毕。
List<List<Integer>> lists = new ArrayList<List<Integer>>();
public List<List<Integer>> levelOrder(TreeNode root){
if (root == null) return lists;
Queue<TreeNode> treeNodes = new LinkedList<>();
treeNodes.add(root);
int level = 0;
while (!treeNodes.isEmpty()){
// 开始当前level的计算
lists.add(new ArrayList<Integer>());
int size = treeNodes.size();
// 根据队列大小,循环处理其中的TreeNode
for (int i = 0; i < size; i++) {
TreeNode node = treeNodes.remove();
// 将当前节点值存入当前层的list中
lists.get(level).add(node.val);
if (node.left != null){
// 子节点放入Queue
treeNodes.add(node.left);
}
if (node.right != null){
// 子节点放入Queue
treeNodes.add(node.right);
}
}
// 继续下次循环
level ++;
}
return lists;
}