校招算法笔面试 | 校招笔面试真题-BST判定

题目## 题目

题目链接

解题思路

  1. 基本思路:

    • 使用递归方法遍历二叉树,检查每个节点是否满足二分查找树的性质。
    • 对于每个节点,确保其左子树的所有节点值小于该节点值,右子树的所有节点值大于该节点值。
  2. 实现方法:

    • 解析输入构建二叉树。
    • 使用辅助函数进行递归检查,传递当前节点的值范围。

代码

#include <iostream>
#include <unordered_map>
#include <sstream>
#include <limits>
using namespace std;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

bool isBST(TreeNode* node, int minVal, int maxVal) {
    if (!node) return true;
    if (node->val <= minVal || node->val >= maxVal) return false;
    return isBST(node->left, minVal, node->val) && isBST(node->right, node->val, maxVal);
}

int main() {
    int rootVal;
    cin >> rootVal;

    unordered_map<int, TreeNode*> nodes;
    TreeNode* root = new TreeNode(rootVal);
    nodes[rootVal] = root;

    string line;
    cin.ignore(); // 忽略换行符
    while (getline(cin, line)) {
        int parentVal, leftVal, rightVal;
        char colon, pipe;
        stringstream ss(line);
        ss >> parentVal >> colon >> leftVal >> pipe >> rightVal;

        if (nodes.find(parentVal) == nodes.end()) {
            nodes[parentVal] = new TreeNode(parentVal);
        }
        TreeNode* parent = nodes[parentVal];

        if (leftVal != -1) {
            parent->left = new TreeNode(leftVal);
            nodes[leftVal] = parent->left;
        }
        if (rightVal != -1) {
            parent->right = new TreeNode(rightVal);
            nodes[rightVal] = parent->right;
        }
    }

    // 检查是否为二分查找树
    if (isBST(root, numeric_limits<int>::min(), numeric_limits<int>::max())) {
        cout << 1 << endl; // 是二分查找树
    } else {
        cout << 0 << endl; // 不是二分查找树
    }

    return 0;
}
import java.util.*;

public class Main {
    static class TreeNode {
        int val;
        TreeNode left, right;
        TreeNode(int x) {
            val = x;
        }
    }

    static boolean isBST(TreeNode node, int minVal, int maxVal) {
        if (node == null) return true;
        if (node.val <= minVal || node.val >= maxVal) return false;
        return isBST(node.left, minVal, node.val) && isBST(node.right, node.val, maxVal);
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int rootVal = sc.nextInt();
        sc.nextLine(); // 读取换行符

        Map<Integer, TreeNode> nodes = new HashMap<>();
        TreeNode root = new TreeNode(rootVal);
        nodes.put(rootVal, root);

        while (sc.hasNextLine()) {
            String line = sc.nextLine();
            String[] parts = line.split(":|\\|");
            int parentVal = Integer.parseInt(parts[0]);
            int leftVal = Integer.parseInt(parts[1]);
            int rightVal = Integer.parseInt(parts[2]);

            if (!nodes.containsKey(parentVal)) {
                nodes.put(parentVal, new TreeNode(parentVal));
            }
            TreeNode parent = nodes.get(parentVal);

            if (leftVal != -1) {
                parent.left = new TreeNode(leftVal);
                nodes.put(leftVal, parent.left);
            }
            if (rightVal != -1) {
                parent.right = new TreeNode(rightVal);
                nodes.put(rightVal, parent.right);
            }
        }

        // 检查是否为二分查找树
        if (isBST(root, Integer.MIN_VALUE, Integer.MAX_VALUE)) {
            System.out.println(1); // 是二分查找树
        } else {
            System.out.println(0); // 不是二分查找树
        }
    }
}
import sys
sys.setrecursionlimit(100000)  # 扩大递归栈深度

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

def is_bst(node, min_val, max_val):
    if not node:
        return True
    if node.val <= min_val or node.val >= max_val:
        return False
    return is_bst(node.left, min_val, node.val) and is_bst(node.right, node.val, max_val)

def main():
    root_val = int(input())
    
    nodes = {}
    root = TreeNode(root_val)
    nodes[root_val] = root
    
    try:
        while True:
            line = input().strip()
            if not line:
                break
                
            # 解析输入行
            parts = line.split(':')
            parent_val = int(parts[0])
            left_val, right_val = map(int, parts[1].split('|'))
            
            # 如果父节点不存在,创建父节点
            if parent_val not in nodes:
                nodes[parent_val] = TreeNode(parent_val)
            parent = nodes[parent_val]
            
            # 创建左右子节点
            if left_val != -1:
                parent.left = TreeNode(left_val)
                nodes[left_val] = parent.left
            if right_val != -1:
                parent.right = TreeNode(right_val)
                nodes[right_val] = parent.right
                
    except EOFError:
        pass
    
    # 检查是否为二分查找树
    if is_bst(root, float('-inf'), float('inf')):
        print(1)  # 是二分查找树
    else:
        print(0)  # 不是二分查找树

if __name__ == "__main__":
    main()


算法及复杂度

  • 算法:二叉树遍历
  • 时间复杂度: O ( n ) \mathcal{O(n)} O(n),其中 n n n 为节点数量
  • 空间复杂度: O ( n ) \mathcal{O(n)} O(n),用于存储树的节点

题目链接

解题思路

这是一道树形结构的路径选择问题,主要约束条件如下:

  1. 每条道路要么全部布置花灯,要么完全不布置
  2. 至少要有一条通向首都的路径布置花灯
  3. 每个城市最多选择两条相连道路布置花灯
  4. 所有布置花灯的道路必须构成连通子图
  5. 总路径长度不能超过给定上限 m m m

代码

#include <bits/stdc++.h>
using namespace std;

using Array = vector<int>;

set<int> dfs(int root, vector<Array>& sons, Array& d, int m) {
    if (sons[root].size() == 0)
        return set<int>({0});
    vector<set<int>> sts;
    for (auto it = sons[root].begin(); it != sons[root].end(); ++it) {
        sts.push_back(dfs(*it, sons, d, m));
    }
    set<int> ret({0});
    // 选择单条路径
    for (auto it = sts.begin(); it != sts.end(); ++it)
        for (auto it2 = it->begin(); it2 != it->end(); ++it2)
            if (d[sons[root][it - sts.begin()]] + *it2 <= m)
                ret.insert(d[sons[root][it - sts.begin()]] + *it2);
    // 选择两条路径
    for (auto it_i = sts.begin(); next(it_i) != sts.end(); ++it_i) {
        for (auto it_j = it_i + 1; it_j != sts.end(); ++it_j) {
            for (auto it = it_i->begin(); it != it_i->end(); ++it) {
                for (auto it2 = it_j->begin(); it2 != it_j->end(); ++it2) {
                    if (d[sons[root][it_i - sts.begin()]] + d[sons[root][it_j - sts.begin()]] + *it + *it2 <= m)
                        ret.insert(d[sons[root][it_i - sts.begin()]] + d[sons[root][it_j - sts.begin()]] + *it + *it2);
                }
            }
        }
    }
    return ret;
}

int main() {
    int m, n;
    while (cin >> m >> n) {
        vector<Array> sons(n);
        Array father(n, -1), d(n, 0);
        for (int i = 0, u, v, dd; i < n - 1; i++) {
            cin >> u >> v >> dd;
            d[v] = dd;
            sons[u].push_back(v);
            father[v] = u;
        }
        int root = 0;
        for (; root < father.size() && father[root] != -1; ++root) {}
        set<int> st = dfs(root, sons, d, m);
        cout << (st.empty() ? 0 : *st.rbegin()) << endl;
    }
    return 0;
}
import java.util.*;

public class Main {
    static class Node {
        List<Integer> sons = new ArrayList<>();
    }
    
    static TreeSet<Integer> dfs(int root, Node[] nodes, int[] dist, int m) {
        if (nodes[root].sons.isEmpty()) {
            return new TreeSet<>(Arrays.asList(0));
        }
        
        List<TreeSet<Integer>> childPaths = new ArrayList<>();
        for (int son : nodes[root].sons) {
            childPaths.add(dfs(son, nodes, dist, m));
        }
        
        TreeSet<Integer> result = new TreeSet<>();
        result.add(0);
        
        // 选择单条路径
        for (int i = 0; i < childPaths.size(); i++) {
            for (int len : childPaths.get(i)) {
                if (dist[nodes[root].sons.get(i)] + len <= m) {
                    result.add(dist[nodes[root].sons.get(i)] + len);
                }
            }
        }
        
        // 选择两条路径
        for (int i = 0; i < childPaths.size() - 1; i++) {
            for (int j = i + 1; j < childPaths.size(); j++) {
                for (int len1 : childPaths.get(i)) {
                    for (int len2 : childPaths.get(j)) {
                        int total = dist[nodes[root].sons.get(i)] + 
                                  dist[nodes[root].sons.get(j)] + len1 + len2;
                        if (total <= m) result.add(total);
                    }
                }
            }
        }
        return result;
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            int m = sc.nextInt();
            int n = sc.nextInt();
            Node[] nodes = new Node[n];
            int[] father = new int[n];
            int[] dist = new int[n];
            Arrays.fill(father, -1);
            
            for (int i = 0; i < n; i++) nodes[i] = new Node();
            
            for (int i = 0; i < n - 1; i++) {
                int u = sc.nextInt();
                int v = sc.nextInt();
                int d = sc.nextInt();
                nodes[u].sons.add(v);
                father[v] = u;
                dist[v] = d;
            }
            
            int root = 0;
            while (root < n && father[root] != -1) root++;
            
            TreeSet<Integer> paths = dfs(root, nodes, dist, m);
            System.out.println(paths.isEmpty() ? 0 : paths.last());
        }
    }
}
from collections import defaultdict

def dfs(root, sons, dist, m):
    if not sons[root]:
        return {0}
    
    child_paths = []
    for son in sons[root]:
        child_paths.append(dfs(son, sons, dist, m))
    
    result = {0}
    
    # 选择单条路径
    for i, paths in enumerate(child_paths):
        for length in paths:
            total = dist[sons[root][i]] + length
            if total <= m:
                result.add(total)
    
    # 选择两条路径
    for i in range(len(child_paths)):
        for j in range(i + 1, len(child_paths)):
            for len1 in child_paths[i]:
                for len2 in child_paths[j]:
                    total = dist[sons[root][i]] + dist[sons[root][j]] + len1 + len2
                    if total <= m:
                        result.add(total)
    
    return result

while True:
    try:
        m = int(input())
        n = int(input())
        sons = defaultdict(list)
        father = [-1] * n
        dist = [0] * n
        
        for _ in range(n - 1):
            u, v, d = map(int, input().split())
            sons[u].append(v)
            father[v] = u
            dist[v] = d
        
        root = next(i for i in range(n) if father[i] == -1)
        paths = dfs(root, sons, dist, m)
        print(max(paths) if paths else 0)
        
    except EOFError:
        break

算法及复杂度

  • 算法:DFS + 动态规划
  • 时间复杂度: O ( n ⋅ 2 d ) \mathcal{O}(n \cdot 2^d) O(n2d) - n n n 为节点数, d d d 为最大度数
  • 空间复杂度: O ( n ) \mathcal{O}(n) O(n) - 需要存储树结构和路径长度
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值