Quick Overview

Resolve each node's permission in an inheritance DAG where any reachable deny overrides an allow and nodes without an inherited decision are denied by default.

Resolve Inherited Allow and Deny Permissions in a DAG

Company: Snowflake

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Technical Screen

## Problem You are given a directed acyclic graph of inheritance edges `parent -> child`, an allow list, and a deny list. A node inherits every explicit decision reachable from its ancestors, including itself. Resolve one Boolean permission for every node using these rules: - If the node or any ancestor is in the deny list, the final permission is denied. - Otherwise, if the node or any ancestor is in the allow list, the final permission is allowed. - Otherwise, the final permission is denied by default. Return results in the same order as the input node list. ### Function Contract Implement `resolveInheritedPermission(nodes, edges, allow, deny)` and return a Boolean array. ### Constraints & Assumptions - `1 <= len(nodes) <= 200,000` and node names are unique nonempty ASCII strings. - Every edge endpoint and every ACL entry names an input node. - The graph is acyclic but may have multiple roots and multiple parents per node. - Deny overrides allow regardless of inheritance distance. - Duplicate edges and duplicate ACL entries do not change the result. ### Clarifying Questions to Ask - Which direction does permission flow? From parent to child. - Does a nearer allow override a farther deny? No; any inherited deny wins. - What is the default when no decision is inherited? Deny. - Can a node have several parents? Yes. ```hint Propagate two independent facts In topological order, each node needs only `hasInheritedAllow` and `hasInheritedDeny`. OR those facts into every child, then apply deny precedence. ``` ### Example ```text nodes = ["root","teamA","teamB","service"] edges = [["root","teamA"], ["root","teamB"], ["teamA","service"], ["teamB","service"]] allow = ["root"] deny = ["teamB"] result = [true, true, false, false] ``` ### Evaluation Focus - Handles multiple inheritance paths and deny precedence. - Includes a node's own explicit entries. - Processes every component, including isolated nodes. - Uses topological traversal in `O(V + E)` time. ### Extensions to Discuss 1. How would you report invalid cyclic input? 2. What changes if a closer explicit rule overrides a farther one? 3. How would you update only affected descendants after one ACL change?

Quick Answer: Resolve each node's permission in an inheritance DAG where any reachable deny overrides an allow and nodes without an inherited decision are denied by default.

Resolve one Boolean per node in original input order for a parent-to-child DAG. A node inherits allow and deny decisions from itself and all ancestors; any deny wins, otherwise any allow grants, and no decision defaults to denied.

Constraints

  • There are 1 through 200000 unique nonempty ASCII node names.
  • All edges form a DAG and every endpoint and ACL entry names an input node.
  • Multiple parents, roots, disconnected components, duplicate edges, and duplicate ACL entries are allowed.
  • Any inherited deny overrides every allow; no inherited decision defaults to denied.

Examples

Input: (['root','teamA','teamB','service'],[['root','teamA'],['root','teamB'],['teamA','service'],['teamB','service']],['root'],['teamB'])

Expected Output: [True, True, False, False]

Explanation: The source diamond inherits root's allow, but teamB's deny overrides it for teamB and service.

Input: (['project','reader','blocked'],[['project','reader'],['project','blocked']],['project','reader'],['blocked'])

Expected Output: [True, True, False]

Explanation: An inherited grant, redundant local grant, and local denial are resolved independently.

Hints

  1. Propagate allow and deny as separate Boolean facts.
  2. Topological order ensures all parents contribute before a child is finalized.

Loading coding console...