题一:求给定二叉树的最小深度
题目描述:
求给定二叉树的最小深度。最小深度是指树的根节点到最近叶子节点的最短路径上的结点的数量。
说明:叶子节点是指没有子节点的节点
示例;
给定二叉树 [3,9,20,null,null,15,7]
返回它的最小深度:2
考点:树 深度优先搜索 广度优先搜索
解法:
- C语言
//定义一个树节点结构 TreeNode
struct TreeNode
{
int val;
struct TreeNode *left;
struct TreeNode *right;
};
//递归
int minDepth(struct TreeNode* root){
int leftDepth = 1,rightDepth = 1;
if(root == NULL){
return 0;
}
else{
leftDepth += minDepth(root->left);
rightDepth += minDepth(root->right);
}
if(root->left == NULL){
return rightDepth;
}
else if(root->right == NULL){
return leftDepth;
}
else{
return leftDepth<rightDepth?leftDepth:rightDepth;
}
}
- Java
package leetcodetest1;
//定义一个二叉树节点结构TreeNode
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x){
val = x;
}
}
//方法一:递归
/**
* 深度优先搜索解决
*
* 复杂度分析:
* 时间复杂度:访问每个节点一次,时间复杂度为o(N),其中N是节点个数
* 空间复杂度:最坏情况下,整棵树是非平衡的,例如每个节点都只有一个孩子,递归会调用 N(树的高度)次,因此栈的空间开销是 O(N) 。但在最好情况下,树是完全平衡的,高度只有 log(N),因此在这种情况下空间复杂度只有 O(log(N))
*/
class Solution{
public int minDepth(TreeNode root) {
if(root == null){
return 0;
}
if((root.left == null) && (root.right == null)) {
return 1;
}
int min_depth = Integer.MAX_VALUE;
if(root.left != null) {
min_depth = Math.min(minDepth(root.left), min_depth);
}
if(root.right != null) {
min_depth = Math.min(minDepth(root.right), min_depth);
}
return min_depth + 1;
}
}
//方法二:深度优先搜索迭代
/**
* 可以利用栈将上述解法的递归变成迭代
*
* 思路:对于每个节点,按照深度优先搜索策略访问,同时在访问到叶子节点时更新最小深度
*
*做法:从一个包含根节点的栈开始,当前深度为1,然后开始迭代,弹出栈顶元素,将它的孩子节点压入栈。当遇到叶子节点时跟新最小深度
*
* 复杂度分析:
* 时间复杂度:每个节点恰好被访问一遍,复杂度为O(N)
* 空间复杂度:最坏情况会在栈中保存整棵树,空间复杂度为O(N)
*/
class Solution{
public int minDepth(TreeNode root) {
LinkedList<Pair<TreeNode,Integer>> stack = new LinkedLis<>();
if(root == null) {
return 0;
}
else {
stack.add(new Pair(root,1));
}
int min_depth = Integer.MAX_VALUE;
while(!stack.isEmpty()) {
Pair<TreeNode, Integer> current = stack.pollLast();
root = current.getKey();
int current_depth = current.getValue();
if ((root.left == null) && (root.right == null)) {
min_depth = Math.min(min_depth, current_depth);
}
if (root.left != null) {
stack.add(new Pair(root.left, current_depth + 1));
}
if (root.right != null) {
stack.add(new Pair(root.right, current_depth + 1));
}
}
return min_depth;
}
}
//方法三:广度优先搜索迭代
/**
* 深度优先搜索方法缺陷是所有的结点必须访问到,以保证能够找到最小的深度,复杂度为O(N)
*
*我们可以使用广度优先搜索优化。按照树的层次去迭代,第一个访问到的叶子就是最小深度节点,这样就不用遍历所有的节点了
*
*复杂度分析:
* 时间复杂度:最坏情况下,这是一颗平衡树,我们按照树的层次一层一层的访问完所有的节点,除去最后一层的结点,我们访问了N/2个节点,复杂度为o(N)
*
* 空间复杂度:和时间复杂度相同
*
*/
class Solution {
public int minDepth(TreeNode root) {
LinkedList<Pair<TreeNode, Integer>> stack = new LinkedList<>();
if (root == null) {
return 0;
}
else {
stack.add(new Pair(root, 1));
}
int current_depth = 0;
while (!stack.isEmpty()) {
Pair<TreeNode, Integer> current = stack.poll();
root = current.getKey();
current_depth = current.getValue();
if ((root.left == null) && (root.right == null)) {
break;
}
if (root.left != null) {
stack.add(new Pair(root.left, current_depth + 1));
}
if (root.right != null) {
stack.add(new Pair(root.right, current_depth + 1));
}
}
return current_depth;
}
}
- python
#-*- codeing = utf-8 -*-
#@Time : 2020/4/29 19:16
#@Author : wzj
#@File : demo.py
#@Software : PyCharm
#定义树节点结构TreeNode
class TreeNode:
def __init__(self,x):
self.val = x;
self.left = None
self.right = None
#方法一:递归
class Solution:
def minDepth(self,root):
if not root:
return 0
children = [root.left,root.right]
if not any(children):
return 1
min_depth = float('inf')
for c in children:
if c:
min_depth = min(self.minDepth(c),min_depth)
return min_depth+1
#方法二:深度优先搜索迭代
class Solution:
def minDepth(self, root):
if not root:
return 0
else:
stack, min_depth = [(1, root),], float('inf')
while stack:
depth, root = stack.pop()
children = [root.left, root.right]
if not any(children):
min_depth = min(depth, min_depth)
for c in children:
if c:
stack.append((depth + 1, c))
return min_depth
#方法三:广度优先搜索迭代
from collections import deque
class Solution:
def minDepth(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if not root:
return 0
else:
node_deque = deque([(1, root),])
while node_deque:
depth, root = node_deque.popleft()
children = [root.left, root.right]
if not any(children):
return depth
for c in children:
if c:
node_deque.append((depth + 1, c))
题二:计算逆波兰式(后缀表达式)的值
题目描述:
计算逆波兰式(后缀表达式)的值
运算符仅包含“+”,“-”,“*”和“/”,被操作数可能是整数或其它表达式
说明:
- 整数除法只保留整数部分
- 给定逆波兰表达式总是有效的即表达式总会得出有效值且不存在除数为0的情况
例如:
输入: [“2”, “1”, “+”, “3”, “*”]
输出: 9
解释: ((2 + 1) * 3) = 9
输入: [“4”, “13”, “5”, “/”, “+”]
输出: 6
解释: (4 + (13 / 5)) = 6
输入: [“10”, “6”, “9”, “3”, “+”, “-11”, “", “/”, "”, “17”, “+”, “5”, “+”]
输出: 22
解释:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
考点:栈
解法:
- C语言
/**
* 思路:
* 操作数入栈,运算符决定操作数出栈和结果入栈
*
*
* 需要注意的只有两点:
* 1. 出栈的两个数,必定是最后那个出栈的数在前,先出栈的数在后,不能颠倒了运算的顺序
* 2. 即便碰到的操作数会出现带有负号的情况,但对于C语言来说只需要 atoi 函数就可以解决
*
* atoi函数介绍:
* atoi() 函数用来将字符串转换成整数(int),其原型为:
* int atoi (const char * str);
* /
#define MAXSIZE 100
#define INCREASESIZE 100
/* 动态顺序栈结构 */
typedef struct stack {
int* data;
int top;
int stacksize;
}Stack;
/* 入栈,栈满拓展栈空间 */
void Push(Stack* obj, int x) {
if (obj->top == obj->stacksize - 1) {
obj->data = (int*)realloc(obj->data, sizeof(int) * (obj->stacksize + INCREASESIZE));
obj->stacksize += INCREASESIZE;
}
obj->data[++obj->top] = x;
}
/* 取栈顶的同时出栈 */
int TopAndPop(Stack* obj) {
int x = obj->data[obj->top--];
return x;
}
int evalRPN(char ** tokens, int tokensSize){
Stack* obj = (Stack*)malloc(sizeof(Stack));
obj->top = -1;
obj->stacksize = MAXSIZE;
obj->data = (int*)malloc(sizeof(int) * MAXSIZE);
int x, y;
for (int i = 0; i < tokensSize; i++) {
//如果是运算符,取两次栈顶,计算,并将结果入栈
if (!strcmp(tokens[i], "+")) {
x = TopAndPop(obj); y = TopAndPop(obj);
Push(obj, y + x);
}
else if(!strcmp(tokens[i], "-")) {
x = TopAndPop(obj); y = TopAndPop(obj);
Push(obj, y - x);
}
else if(!strcmp(tokens[i], "*")) {
x = TopAndPop(obj); y = TopAndPop(obj);
Push(obj, y * x);
}
else if(!strcmp(tokens[i], "/")) {
x = TopAndPop(obj); y = TopAndPop(obj);
Push(obj, y / x);
}
//子字符串为操作数,将其化为整型并入栈
else {
Push(obj, atoi(tokens[i]));
}
}
return TopAndPop(obj); //返回最后栈的唯一一个数
}
- java
//纯数组模拟栈实现(效率比栈更好)
/**
*优化的操作:
* 数组最大长度问哦tokens.length / 2 +1
* switch代替if-else
* Integer.parseInt代替Integer.valueOf减少自动拆箱装箱操作
*
*/
class Solution{
public static int evalRPN(String[] tokens) {
int[] numStack = new int[tokens.length/2+1];
int index = 0;
for(String s:tokens) {
switch(s) {
case "+":
numStack[index - 2] += numStack[--index];
break;
case "-":
numStack[index - 2] -= numStack[--index];
break;
case "*":
numStack[index - 2] *= numStack[--index];
break;
case "/":
numStack[index - 2] /= numStack[--index];
break;
default:
// numStack[index++] = Integer.valueOf(s);
//valueOf改为parseInt,减少自动拆箱装箱操作
numStack[index++] = Integer.parseInt(s);
break;
}
}
return numStack[0];
}
}
- python
#基于栈实现
from typing import List
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
symbol = ["+", "-", "*", "/"]
recList = []
if len(tokens) == 0:
return 0
else:
for c in tokens:
if c not in symbol:
recList.append(c)
else:
b = int(recList.pop())
a = int(recList.pop())
if c == "+":
recList.append(str(a + b))
elif c == "-":
recList.append(str(a - b))
elif c == "*":
recList.append(str(a * b))
elif c == "/":
recList.append(str(int(a / b)))
return recList[0]
题三:对于给定的n个位于同一二维平面上的点,求最多能有多少个点位于同一条直线上
题目描述:
对于给定的n个位于同一二维平面上的点,求最多能有多少个点位于同一条直线上
考点:穷举
例如:
输入: [[1,1],[2,2],[3,3]]
输出: 3
解释:
输入: [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
输出: 4
解释:
解法:
- java
public int maxPoints(int[][] points) {
if (points.length < 3) {
return points.length;
}
int res = 0;
//遍历每个点
for (int i = 0; i < points.length; i++) {
int duplicate = 0;
int max = 0;//保存经过当前点的直线中,最多的点
HashMap<String, Integer> map = new HashMap<>();
for (int j = i + 1; j < points.length; j++) {
//求出分子分母
int x = points[j][0] - points[i][0];
int y = points[j][1] - points[i][1];
if (x == 0 && y == 0) {
duplicate++;
continue;
}
//进行约分
int gcd = gcd(x, y);
x = x / gcd;
y = y / gcd;
String key = x + "@" + y;
map.put(key, map.getOrDefault(key, 0) + 1);
max = Math.max(max, map.get(key));
}
//1 代表当前考虑的点,duplicate 代表和当前的点重复的点
res = Math.max(res, max + duplicate + 1);
}
return res;
}
private int gcd(int a, int b) {
while (b != 0) {
int temp = a % b;
a = b;
b = temp;
}
return a;
}
- python
'''
思路:
首先如果点数小于 3 个,直接返回点数(因为肯定能组成直线)。
我们对所有点遍历,记录包含这个点在内的所有直线中,能组成的点数最多的直线的点数数量。
返回这些数量的最大值。
我们对一个点遍历的时候,再遍历所有点:
维护两个变量
一个来记录和这个点相同的点(重复点)
一个来记录非重复点和这个点组成的各个直线以及它们拥有的点数
即使用哈希表,键为斜率,值是这个直线拥有的点数。这里使用 Counter 直接统计各个直线拥有的点数。
返回最多拥有点数的直线所拥有的点数与重复点之和。
'''
from collections import Counter
class Solution:
def maxPoints(self, points: List[List[int]]) -> int:
def K(i, j):
return float('Inf') if i[1] - j[1] == 0 else (i[0] - j[0]) / (i[1] - j[1])
if len(points) <= 2:
return len(points)
maxans = 0
for i in points:
same = sum(1 for j in points if j == i)
hashmap = Counter([K(i, j) for j in points if j != i])
tempmax = hashmap.most_common(1)[0][1] if hashmap else 0
maxans = max(same + tempmax, maxans)
return maxans
参考自:python代码