登录
OAmaster

You are given a tree with N nodes numbered 0..N-1. Each node holds the letter 'a' or 'b'. The tree is described by an array A of length N where A[k] is the parent of node k, with A[root] = -1. Letters are stored in a string S (S[k] is the letter of node k). Return the number of vertices on the longest path such that no two adjacent nodes on the path share the same letter.

Example

solution("ab", [-1, 0]) = 2
solution("abbab", [-1, 0, 0, 0, 2]) = 3

For S = "abbab", A = [-1, 0, 0, 0, 2], the longest alternating path is 1 — 0 — 2.

解法

树根固定后,节点 u DFS 每个孩子 v:取 v 处最长向下链;若 S[v] != S[u] 则可挂到 u。在 u 处合并最长的两条链更新答案(经过 u 的路径),返回 top1 + 1 给父亲。复杂度 O(N)

import sys
from collections import defaultdict

def solution(S: str, A: list[int]) -> int:
    n = len(A)
    if n == 1:
        return 1

    sys.setrecursionlimit(n + 100)

    children = defaultdict(list)
    root = -1
    for v, p in enumerate(A):
        if p == -1:
            root = v
        else:
            children[p].append(v)

    ans = 1

    def dfs(u: int) -> int:
        # returns longest valid chain ending at u (inclusive), extending downward
        nonlocal ans
        downs = []
        for v in children[u]:
            child_chain = dfs(v)
            if S[v] != S[u]:
                downs.append(child_chain)

        downs.sort(reverse=True)
        top1 = downs[0] if len(downs) >= 1 else 0
        top2 = downs[1] if len(downs) >= 2 else 0
        ans = max(ans, top1 + top2 + 1)

        return top1 + 1

    dfs(root)
    return ans
import java.util.*;

class Solution {
    String s;
    List<List<Integer>> children;
    int ans;

    int solution(String S, int[] A) {
        int n = A.length;
        if (n == 1) return 1;

        this.s = S;
        this.children = new ArrayList<>();
        for (int i = 0; i < n; i++) children.add(new ArrayList<>());

        int root = -1;
        for (int v = 0; v < n; v++) {
            if (A[v] == -1) root = v;
            else children.get(A[v]).add(v);
        }

        ans = 1;
        dfs(root);
        return ans;
    }

    // returns longest valid chain ending at u (inclusive)
    int dfs(int u) {
        List<Integer> downs = new ArrayList<>();
        for (int v : children.get(u)) {
            int childChain = dfs(v);
            if (s.charAt(v) != s.charAt(u)) {
                downs.add(childChain);
            }
        }

        downs.sort(Collections.reverseOrder());
        int top1 = downs.size() >= 1 ? downs.get(0) : 0;
        int top2 = downs.size() >= 2 ? downs.get(1) : 0;
        ans = Math.max(ans, top1 + top2 + 1);

        return top1 + 1;
    }
}
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

class Solution {
public:
    string s;
    vector<vector<int>> children;
    int ans;

    int solution(string S, vector<int>& A) {
        int n = A.size();
        if (n == 1) return 1;

        s = S;
        children.assign(n, {});
        int root = -1;
        for (int v = 0; v < n; v++) {
            if (A[v] == -1) root = v;
            else children[A[v]].push_back(v);
        }

        ans = 1;
        dfs(root);
        return ans;
    }

    // returns longest valid chain ending at u (inclusive)
    int dfs(int u) {
        vector<int> downs;
        for (int v : children[u]) {
            int childChain = dfs(v);
            if (s[v] != s[u]) downs.push_back(childChain);
        }

        sort(downs.begin(), downs.end(), greater<int>());
        int top1 = downs.size() >= 1 ? downs[0] : 0;
        int top2 = downs.size() >= 2 ? downs[1] : 0;
        ans = max(ans, top1 + top2 + 1);

        return top1 + 1;
    }
};

You are given two arrays A and B, each of length N. Build array C where for each index k, C[k] is either A[k] or B[k]. Choose values so the smallest positive integer missing from C is as small as possible — i.e. return the smallest positive integer that cannot occur in any merged C.

Example

solution([1, 2, 4, 3], [1, 3, 2, 3]) = 2
solution([3, 2, 1, 6, 5], [4, 2, 1, 3, 3]) = 3
solution([1, 2], [1, 2]) = 3

Constraints

1 ≤ N ≤ 10⁵, 1 ≤ A[i], B[i] ≤ 10⁵.

解法

建二分图:整数 v(1..N+1)连向 AB 中包含 v 的下标。按 1, 2, ... 顺序用增广路(匈牙利算法)贪心匹配到不同下标,首个无法匹配的整数即答案。最坏 O(N²),随机输入很快。

from collections import defaultdict

def solution(A: list[int], B: list[int]) -> int:
    n = len(A)
    positions = defaultdict(list)
    for k in range(n):
        positions[A[k]].append(k)
        if B[k] != A[k]:
            positions[B[k]].append(k)

    used = [None] * n
    assigned = {}

    def try_assign(v: int, visited: set) -> bool:
        for k in positions[v]:
            if k in visited:
                continue
            visited.add(k)
            if used[k] is None or try_assign(used[k], visited):
                used[k] = v
                assigned[v] = k
                return True
        return False

    for v in range(1, n + 2):
        if v not in positions:
            return v
        if not try_assign(v, set()):
            return v

    return n + 1
import java.util.*;

class Solution {
    Map<Integer, List<Integer>> positions;
    Integer[] used;

    int solution(int[] A, int[] B) {
        int n = A.length;
        positions = new HashMap<>();
        for (int k = 0; k < n; k++) {
            positions.computeIfAbsent(A[k], x -> new ArrayList<>()).add(k);
            if (B[k] != A[k]) {
                positions.computeIfAbsent(B[k], x -> new ArrayList<>()).add(k);
            }
        }

        used = new Integer[n];

        for (int v = 1; v <= n + 1; v++) {
            if (!positions.containsKey(v)) return v;
            Set<Integer> visited = new HashSet<>();
            if (!tryAssign(v, visited)) return v;
        }
        return n + 1;
    }

    boolean tryAssign(int v, Set<Integer> visited) {
        for (int k : positions.get(v)) {
            if (visited.contains(k)) continue;
            visited.add(k);
            if (used[k] == null || tryAssign(used[k], visited)) {
                used[k] = v;
                return true;
            }
        }
        return false;
    }
}
#include <vector>
#include <unordered_map>
#include <unordered_set>
using namespace std;

class Solution {
public:
    unordered_map<int, vector<int>> positions;
    vector<int> used;

    int solution(vector<int>& A, vector<int>& B) {
        int n = A.size();
        positions.clear();
        for (int k = 0; k < n; k++) {
            positions[A[k]].push_back(k);
            if (B[k] != A[k]) positions[B[k]].push_back(k);
        }

        used.assign(n, -1);

        for (int v = 1; v <= n + 1; v++) {
            if (positions.find(v) == positions.end()) return v;
            unordered_set<int> visited;
            if (!tryAssign(v, visited)) return v;
        }
        return n + 1;
    }

    bool tryAssign(int v, unordered_set<int>& visited) {
        for (int k : positions[v]) {
            if (visited.count(k)) continue;
            visited.insert(k);
            if (used[k] == -1 || tryAssign(used[k], visited)) {
                used[k] = v;
                return true;
            }
        }
        return false;
    }
};

You are given a string S. In one move you can erase any pair of identical letters from S. Find the shortest possible string achievable; among all such shortest strings, return the lexicographically smallest one.

Example

solution("CBCAAXA") = "BAX"
solution("ZYXZYZYV") = "XYZV" // length 4 cannot be shortened further with this exact spec
solution("ABCBACDDAB") = ""
solution("AKFKFNOGKFB") = "AFKMOGB"

Constraints

1 ≤ N ≤ 10⁵, S consists of uppercase letters.

解法

消除所有重复对后,偶数次出现的字母全部消失,奇数次出现的字母各保留一份。在所有合法顺序中取字典序最小:经典单调栈,从左到右扫,若栈顶大于当前字符且后面还有同样的字符就弹出。复杂度 O(N)

def solution(S: str) -> str:
    n = len(S)
    total = [0] * 26
    for c in S:
        total[ord(c) - ord('A')] += 1

    # target[ch] = 1 means this letter must be kept exactly once
    target = [t % 2 for t in total]

    seen = [0] * 26
    in_stack = [False] * 26
    stack = []

    for i, c in enumerate(S):
        idx = ord(c) - ord('A')
        seen[idx] += 1

        if target[idx] == 0:
            continue
        if in_stack[idx]:
            continue

        # pop a larger top if the same letter still appears later
        while stack and stack[-1] > c:
            top_idx = ord(stack[-1]) - ord('A')
            remaining = total[top_idx] - seen[top_idx]
            if remaining >= 1:
                stack.pop()
                in_stack[top_idx] = False
            else:
                break

        stack.append(c)
        in_stack[idx] = True

    return ''.join(stack)
class Solution {
    String solution(String S) {
        int n = S.length();
        int[] total = new int[26];
        for (char c : S.toCharArray()) total[c - 'A']++;

        int[] target = new int[26];
        for (int i = 0; i < 26; i++) target[i] = total[i] % 2;

        int[] seen = new int[26];
        boolean[] inStack = new boolean[26];
        StringBuilder stack = new StringBuilder();

        for (int i = 0; i < n; i++) {
            char c = S.charAt(i);
            int idx = c - 'A';
            seen[idx]++;

            if (target[idx] == 0) continue;
            if (inStack[idx]) continue;

            while (stack.length() > 0 && stack.charAt(stack.length() - 1) > c) {
                char top = stack.charAt(stack.length() - 1);
                int topIdx = top - 'A';
                int remaining = total[topIdx] - seen[topIdx];
                if (remaining >= 1) {
                    stack.deleteCharAt(stack.length() - 1);
                    inStack[topIdx] = false;
                } else {
                    break;
                }
            }

            stack.append(c);
            inStack[idx] = true;
        }

        return stack.toString();
    }
}
#include <string>
#include <vector>
using namespace std;

class Solution {
public:
    string solution(string S) {
        int n = S.size();
        vector<int> total(26, 0);
        for (char c : S) total[c - 'A']++;

        vector<int> target(26);
        for (int i = 0; i < 26; i++) target[i] = total[i] % 2;

        vector<int> seen(26, 0);
        vector<bool> inStack(26, false);
        string stk;

        for (int i = 0; i < n; i++) {
            char c = S[i];
            int idx = c - 'A';
            seen[idx]++;

            if (target[idx] == 0) continue;
            if (inStack[idx]) continue;

            while (!stk.empty() && stk.back() > c) {
                char top = stk.back();
                int topIdx = top - 'A';
                int remaining = total[topIdx] - seen[topIdx];
                if (remaining >= 1) {
                    stk.pop_back();
                    inStack[topIdx] = false;
                } else {
                    break;
                }
            }

            stk.push_back(c);
            inStack[idx] = true;
        }

        return stk;
    }
};
Pro 会员

解锁剩余 71 道 OA 真题

开通后立即解锁完整题面 + Python / Java / C++ 三语题解。 全站 165 家公司 · 1000+ 道 OA · 月度更新。