questions C
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
title: Check Array Formation Through Concatenation
|
||||
slug: check-array-formation-through-concatenation
|
||||
difficulty: easy
|
||||
leetcode_id: 1640
|
||||
leetcode_url: https://leetcode.com/problems/check-array-formation-through-concatenation/
|
||||
categories:
|
||||
- arrays
|
||||
- hash-tables
|
||||
patterns:
|
||||
- greedy
|
||||
|
||||
description: |
|
||||
You are given an array of **distinct** integers `arr` and an array of integer arrays `pieces`, where the integers in `pieces` are **distinct**. Your goal is to form `arr` by concatenating the arrays in `pieces` **in any order**. However, you are **not** allowed to reorder the integers in each array `pieces[i]`.
|
||||
|
||||
Return `true` *if it is possible to form the array* `arr` *from* `pieces`. Otherwise, return `false`.
|
||||
|
||||
constraints: |
|
||||
- `1 <= pieces.length <= arr.length <= 100`
|
||||
- `sum(pieces[i].length) == arr.length`
|
||||
- `1 <= pieces[i].length <= arr.length`
|
||||
- `1 <= arr[i], pieces[i][j] <= 100`
|
||||
- The integers in `arr` are **distinct**
|
||||
- The integers in `pieces` are **distinct** (if we flatten `pieces` into a 1D array, all integers are distinct)
|
||||
|
||||
examples:
|
||||
- input: "arr = [15,88], pieces = [[88],[15]]"
|
||||
output: "true"
|
||||
explanation: "Concatenate [15] then [88] to form [15, 88]."
|
||||
- input: "arr = [49,18,16], pieces = [[16,18,49]]"
|
||||
output: "false"
|
||||
explanation: "Even though the numbers match, we cannot reorder pieces[0]. The piece [16,18,49] would place 16 first, but arr requires 49 first."
|
||||
- input: "arr = [91,4,64,78], pieces = [[78],[4,64],[91]]"
|
||||
output: "true"
|
||||
explanation: "Concatenate [91] then [4,64] then [78] to form [91, 4, 64, 78]."
|
||||
|
||||
explanation:
|
||||
intuition: |
|
||||
Think of this problem like assembling a jigsaw puzzle where each piece has a fixed internal structure. You have pre-formed "chunks" of numbers that cannot be rearranged internally, but you can choose which chunk to place next.
|
||||
|
||||
The key insight is that **each number is distinct**, which means every number in `arr` appears in exactly one piece. This is powerful because it means we can uniquely identify which piece should come next by looking at the **first element** of each piece.
|
||||
|
||||
Imagine walking through `arr` from left to right. At each position, we ask: "Which piece starts with this number?" If we find such a piece, we verify that its subsequent elements match the next positions in `arr`. If they do, we've successfully placed that piece and can move forward. If no piece starts with the current number, or if the piece's elements don't match, it's impossible to form `arr`.
|
||||
|
||||
The distinctness constraint transforms this from a complex permutation problem into a simple greedy matching problem.
|
||||
|
||||
approach: |
|
||||
We solve this using a **Hash Map + Greedy Matching** approach:
|
||||
|
||||
**Step 1: Build a lookup map**
|
||||
|
||||
- Create a hash map that maps the **first element** of each piece to the entire piece
|
||||
- Since all integers are distinct, each first element uniquely identifies its piece
|
||||
- This allows O(1) lookup to find which piece should be placed next
|
||||
|
||||
|
||||
|
||||
**Step 2: Iterate through arr greedily**
|
||||
|
||||
- Start at index `i = 0` in `arr`
|
||||
- Look up `arr[i]` in our hash map to find the piece that should start here
|
||||
- If no piece starts with `arr[i]`, return `false` — we can't form `arr`
|
||||
- If we find a piece, verify that **all elements** in that piece match the corresponding positions in `arr`
|
||||
- If any element doesn't match, return `false`
|
||||
- If all elements match, advance `i` by the length of the piece we just placed
|
||||
|
||||
|
||||
|
||||
**Step 3: Return the result**
|
||||
|
||||
- If we successfully process all of `arr` (i.e., `i` reaches `len(arr)`), return `true`
|
||||
- The constraint `sum(pieces[i].length) == arr.length` ensures we'll use all pieces exactly once if successful
|
||||
|
||||
common_pitfalls:
|
||||
- title: Trying to Reorder Pieces Internally
|
||||
description: |
|
||||
A common misunderstanding is thinking you can rearrange elements within a piece. The problem explicitly states that you **cannot** reorder integers within each `pieces[i]`.
|
||||
|
||||
For example, with `arr = [49, 18, 16]` and `pieces = [[16, 18, 49]]`, you cannot rearrange the piece to `[49, 18, 16]`. The piece must be used as-is.
|
||||
wrong_approach: "Treating pieces as unordered sets"
|
||||
correct_approach: "Use pieces as fixed-order arrays that must match contiguously"
|
||||
|
||||
- title: Linear Search for Each Element
|
||||
description: |
|
||||
Without a hash map, you might search through all pieces for each position in `arr`, resulting in O(n × m) complexity where m is the number of pieces.
|
||||
|
||||
While this would still pass given the small constraints (`n <= 100`), using a hash map reduces lookups to O(1) and makes the solution cleaner and more scalable.
|
||||
wrong_approach: "Nested loops searching all pieces"
|
||||
correct_approach: "Hash map keyed by first element for O(1) lookup"
|
||||
|
||||
- title: Not Validating the Entire Piece
|
||||
description: |
|
||||
It's tempting to only check if the first element matches, but you must verify that **all subsequent elements** in the piece match the corresponding positions in `arr`.
|
||||
|
||||
For example, if `arr = [1, 3, 2]` and a piece is `[1, 2, 3]`, the first element `1` matches, but the rest doesn't. You must check the entire piece.
|
||||
wrong_approach: "Only checking the first element of each piece"
|
||||
correct_approach: "Verify all elements in the piece match contiguously in arr"
|
||||
|
||||
key_takeaways:
|
||||
- "**Distinctness enables unique identification**: When elements are distinct, the first element of each piece uniquely identifies that piece"
|
||||
- "**Hash maps for fast lookup**: Mapping first elements to pieces allows O(1) identification of which piece belongs at each position"
|
||||
- "**Greedy works when there's no choice**: Since each position in `arr` can only match one piece, greedy matching finds the solution if one exists"
|
||||
- "**Constraint exploitation**: The `sum(pieces[i].length) == arr.length` constraint guarantees we'll use all pieces if successful"
|
||||
|
||||
time_complexity: "O(n). We iterate through `arr` once and perform O(1) lookups. Each element in `pieces` is also checked exactly once during verification."
|
||||
space_complexity: "O(n). We store all pieces in a hash map, where n is the total number of elements across all pieces (which equals `arr.length`)."
|
||||
|
||||
solutions:
|
||||
- approach_name: Hash Map Lookup
|
||||
is_optimal: true
|
||||
code: |
|
||||
def can_form_array(arr: list[int], pieces: list[list[int]]) -> bool:
|
||||
# Map first element of each piece to the entire piece
|
||||
piece_map = {piece[0]: piece for piece in pieces}
|
||||
|
||||
i = 0
|
||||
while i < len(arr):
|
||||
# Find the piece that should start at position i
|
||||
if arr[i] not in piece_map:
|
||||
# No piece starts with this element
|
||||
return False
|
||||
|
||||
piece = piece_map[arr[i]]
|
||||
|
||||
# Verify all elements in this piece match arr
|
||||
for val in piece:
|
||||
if i >= len(arr) or arr[i] != val:
|
||||
return False
|
||||
i += 1
|
||||
|
||||
return True
|
||||
explanation: |
|
||||
**Time Complexity:** O(n) — Each element in `arr` is visited exactly once.
|
||||
|
||||
**Space Complexity:** O(n) — The hash map stores all pieces.
|
||||
|
||||
We build a hash map keyed by the first element of each piece, then greedily match pieces to positions in `arr`. The distinctness constraint ensures each lookup is unambiguous.
|
||||
|
||||
- approach_name: Brute Force with Linear Search
|
||||
is_optimal: false
|
||||
code: |
|
||||
def can_form_array(arr: list[int], pieces: list[list[int]]) -> bool:
|
||||
i = 0
|
||||
while i < len(arr):
|
||||
# Find a piece that starts with arr[i]
|
||||
found = False
|
||||
for piece in pieces:
|
||||
if piece[0] == arr[i]:
|
||||
# Check if this piece matches
|
||||
for val in piece:
|
||||
if i >= len(arr) or arr[i] != val:
|
||||
return False
|
||||
i += 1
|
||||
found = True
|
||||
break
|
||||
|
||||
if not found:
|
||||
return False
|
||||
|
||||
return True
|
||||
explanation: |
|
||||
**Time Complexity:** O(n × m) — For each position in `arr`, we potentially search all `m` pieces.
|
||||
|
||||
**Space Complexity:** O(1) — No additional data structures used.
|
||||
|
||||
This approach searches through all pieces to find one that starts with the current element. While correct, it's less efficient than the hash map approach. Given the small constraints (`n, m <= 100`), both solutions pass.
|
||||
Reference in New Issue
Block a user