data-structures

3 posts

kakao

2026 Kakao Group New Crew Recruitment Coding Test Round 1 Problem Explanations (opens in new tab)

The post explains the first-round coding test for Kakao Group’s 2026 new-crew recruitment, covering seven problems of gradually increasing difficulty; the provided text details the first five. The solutions rely on string processing, simulation, graph traversal, and structural optimization. The main lesson is to exploit each problem’s constraints and identify the right representation before implementing. ## Problem 1: Preventing Spoilers in Important Words - Split the message into space-separated words and record each word’s character interval. - Classify words as spoiler-protected if their interval overlaps any spoiler range. - Store non-spoiler words in a set or hash map to detect duplicates. - Scan protected words from left to right: - Reject words appearing outside spoiler ranges. - Reject words duplicating an already revealed important word. - Count and record valid words. - Later test groups add overlapping spoiler ranges and duplicate words, requiring both types of deduplication. ## Problem 2: Yellow Traffic Lights - Each light repeats a cycle of green, red, and yellow durations. - The task is to find the first time when every light is yellow. - Since cycles repeat, simulation only needs to continue through the least common multiple of all cycle lengths. - Because each duration is at most 20, a bounded simulation is also feasible. - Possible implementations include: - Updating each light’s state every second. - Precomputing states up to the termination time. - Checking directly whether time `t` lies in each light’s yellow interval. - If no simultaneous yellow period occurs within a full combined cycle, the answer does not exist. ## Problem 3: Maximizing the Number of Leaf Nodes - A split of degree `k` consumes one unit of distribution budget and increases the leaf count by `k - 1`. - Since split degrees are limited to 2 and 3, every path product has the form `2^p × 3^q` and must remain within `split_limit`. - Two structural properties simplify the optimization: - Partial splitting can be rearranged so it occurs at only one depth within a consecutive block of equal split degrees. - Blocks of degree-2 splits should be placed above degree-3 blocks because they use less budget for the same eventual frontier size. - Therefore, an optimal tree consists of: - Consecutive layers of 2-way splits. - Followed by consecutive layers of 3-way splits. - At most one partially split layer. - Enumerate feasible pairs `(i, j)` satisfying `2^i × 3^j ≤ split_limit`. - Fully process each layer while budget allows; at the first insufficient layer, perform as many partial splits as possible and calculate the resulting leaf count. ## Problem 4: Virus Pipes - The tree’s edges use one of three pipe types: A, B, or C. - Opening a pipe type infects every currently reachable organism through connected pipes of that type. - Infection is permanent, and reopening the same type consecutively has no effect. - For each possible pipe-opening sequence: - Start a DFS or BFS from all infected organisms. - Traverse only edges of the selected type. - Mark newly reached organisms as infected. - Exhaustive search is practical because the number of pipe openings is at most 10, yielding at most `3^10 = 59,049` sequences. ## Problem 5: Organizing Kakao Apps - Apps are represented by square blocks on a grid. - Pushing one app by one cell can push blocking apps in the same direction. - Apps leaving one edge wrap around to the opposite side, potentially causing further collisions. - Process each command by: - Using the initially pushed app as a BFS seed. - Finding all apps that must move together. - Moving them one cell simultaneously. - Treating clipped apps that cross the boundary as new seeds. - Repeating until no new seeds remain. - Blocks may be larger than one cell, so collisions can propagate across multiple rows and columns. - With grid dimensions and block sizes bounded by 10, direct simulation is sufficiently efficient and terminates because the state space is finite. Overall, the recommended approach is to model each problem according to its mechanics: sets for duplicate word handling, periodicity for traffic lights, structural exchange arguments for tree optimization, exhaustive DFS/BFS for pipe sequences, and layered BFS simulation for grid movement.

datadog

How Go 1.24's Swiss Tables saved us hundreds of gigabytes | Datadog (opens in new tab)

Datadog’s article explains how Swiss Tables provide a faster and more memory-efficient hash-table design for Go. The approach replaces traditional bucket-based lookup with compact control metadata and group probing, allowing the runtime to reject non-matching entries quickly. The article concludes that Swiss Tables can improve map performance and memory usage, while requiring careful attention to compatibility, implementation complexity, and workload-specific benchmarking. ## Why Traditional Go Maps Have Limitations - Conventional hash tables organize entries into buckets and may require several memory accesses during lookup. - As maps grow, collisions and overflow buckets can increase lookup costs. - Pointer-heavy layouts also add memory overhead and reduce cache locality. - These costs matter for Datadog workloads that maintain large numbers of maps containing metrics, tags, and other high-cardinality data. ## How Swiss Tables Work - Swiss Tables store compact metadata alongside groups of key-value slots. - Each entry’s hash is divided into: - A portion used to select the initial table location. - A short fingerprint stored in control metadata. - Lookups compare fingerprints across multiple slots before examining full keys. - Empty and deleted markers in the metadata make it possible to skip large portions of the table quickly. - Group-oriented probing improves cache locality and reduces the number of key comparisons. ## Adapting the Design to Go - A Go implementation must account for Go-specific features such as: - Garbage collection. - Generic types. - Interface and pointer representations. - Map growth and deletion semantics. - The implementation needs to preserve expected Go map behavior while changing the underlying storage strategy. - Careful handling of memory layout is essential because metadata, keys, values, and garbage-collector scanning all affect performance. ## Performance and Memory Trade-offs - Swiss Tables can reduce memory overhead by storing compact fingerprints instead of repeatedly examining full keys. - Better locality can improve lookup and insertion speed, particularly for large maps. - Results depend on factors such as: - Map size. - Key and value types. - Read/write ratios. - Collision rates. - Frequency of growth and deletion. - Benchmarks are therefore necessary before replacing an existing map implementation in production. ## Practical Lessons - Data-structure improvements should be evaluated against real application workloads, not only synthetic benchmarks. - Memory layout and garbage-collector behavior can be as important as algorithmic complexity. - Swiss Tables are a promising foundation for efficient Go maps, but their advantages must be balanced against implementation complexity and compatibility requirements. Datadog’s recommendation is to use Swiss Table techniques where map performance or memory usage is a meaningful bottleneck, and to validate the change with representative benchmarks and production measurements.

figma

Supporting Faster File Load Times with Memory Optimizations in Rust | Figma Blog (opens in new tab)

Figma improved server-side file loading by reducing the memory overhead of its Rust data structures. Replacing per-node `BTreeMap`s with compact sorted vectors made deserialization faster and cut memory usage for large files by nearly 25%, despite worse theoretical operation complexity. The team also explored packing field IDs into unused pointer bits, potentially storing the same information in fewer bytes. ## Smaller, Memory-Efficient Maps - Figma files consist of nodes, each represented by properties such as type, parent, position, and dimensions. - Nodes were stored as `BTreeMap<u16, u64 pointer>` structures because ordered iteration was required for serialization. - Profiling showed these maps consumed more than 60% of a file’s memory, even though they stored metadata rather than large data payloads. - The schema contains fewer than 200 possible fields, and nodes typically contain only a subset of them—about 60 properties on average. - Figma replaced each `BTreeMap` with a sorted flat vector of `(field ID, pointer)` pairs. - Although vectors have theoretically slower insertion, lookup, and editing, their compact linear layout is more cache-friendly and faster during deserialization. - The deployed change reduced memory usage by nearly 25% for large files and improved file-loading performance. ## Saving More Memory with Bit Stuffing - The team also investigated storing the field ID inside the pointer itself. - While pointers are nominally 64 bits, x86 systems currently use only the lower 48 bits for memory addresses, leaving 16 bits available. - Figma’s field IDs require exactly 16 bits, allowing a single `u64` to contain both: - A 16-bit field ID - A 48-bit memory pointer - This representation could eliminate the separate field-ID storage and further reduce memory overhead. - The approach had not yet been productionized because relying on unused pointer bits is architecture-dependent and could change in the future. Figma’s results demonstrate that practical memory layout and CPU cache behavior can outweigh Big O complexity. For compact, bounded data structures, flat vectors—and carefully considered bit packing—can deliver substantial improvements in both memory efficiency and load speed.