Skip to content

Commit 9e584b1

Browse files
chore: add LeetCode daily solution
1 parent 0927107 commit 9e584b1

5 files changed

Lines changed: 145 additions & 0 deletions

File tree

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Pyramid Transition Matrix (Medium)
2+
3+
**Problem ID:** 756
4+
**Date:** 2025-12-29
5+
**Link:** https://leetcode.com/problems/pyramid-transition-matrix/
6+
7+
## Approach
8+
9+
To solve the Pyramid Transition Matrix problem, we can use a depth-first search (DFS) approach combined with memoization to efficiently explore the possible configurations of the pyramid.
10+
11+
### Approach:
12+
13+
1. **Understanding the Structure**:
14+
- The pyramid is constructed from a base row of blocks, where each block can be represented by a character. Each pair of adjacent blocks in the current row can form a new block in the row above it based on the allowed triangular patterns.
15+
16+
2. **Data Structures**:
17+
- Use a set to store the allowed patterns for quick lookup.
18+
- Utilize a recursive function to explore the possible configurations of the pyramid. This function will take the current row of blocks as input and attempt to build the row above it.
19+
20+
3. **Recursive Function**:
21+
- The recursive function will check pairs of adjacent blocks in the current row. For each pair, it will look for all valid top blocks that can be formed using the allowed patterns.
22+
- For each valid top block found, the function will recursively call itself with the new row (which includes the newly formed top block) until reaching the top of the pyramid (when the row has only one block).
23+
24+
4. **Base Case**:
25+
- The recursion stops when the row length is 1, indicating that the pyramid has been successfully built.
26+
27+
5. **Memoization**:
28+
- To optimize the function, store results of previously computed states (current row) to avoid redundant calculations. This can be done using a dictionary where keys are the current row strings and values indicate whether that configuration can lead to a valid pyramid.
29+
30+
6. **Complexity**:
31+
- The time complexity is primarily influenced by the number of states explored and the number of allowed patterns. Given the constraints, the worst-case scenario involves exploring multiple configurations, but memoization drastically reduces the number of unique states. The space complexity is also O(n) due to the storage of the memoization dictionary.
32+
33+
### Summary:
34+
By leveraging DFS and memoization, we can efficiently explore all possible configurations of the pyramid, checking against the allowed patterns to determine if a valid pyramid can be formed from the given base row. This approach ensures that we systematically build the pyramid while avoiding unnecessary recalculations, making it feasible within the problem’s constraints.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import java.util.HashMap;
2+
import java.util.HashSet;
3+
import java.util.List;
4+
import java.util.Map;
5+
6+
public class Solution {
7+
private Map<String, HashSet<Character>> allowedMap;
8+
9+
public boolean pyramidTransition(String bottom, List<String> allowed) {
10+
allowedMap = new HashMap<>();
11+
for (String pattern : allowed) {
12+
allowedMap.computeIfAbsent(pattern.substring(0, 2), k -> new HashSet<>()).add(pattern.charAt(2));
13+
}
14+
return canBuildPyramid(bottom);
15+
}
16+
17+
private boolean canBuildPyramid(String bottom) {
18+
if (bottom.length() == 1) {
19+
return true;
20+
}
21+
int n = bottom.length();
22+
StringBuilder nextRow = new StringBuilder();
23+
boolean canBuild = false;
24+
25+
for (int i = 0; i < n - 1; i++) {
26+
String key = bottom.substring(i, i + 2);
27+
if (!allowedMap.containsKey(key)) {
28+
return false;
29+
}
30+
for (char topBlock : allowedMap.get(key)) {
31+
nextRow.append(topBlock);
32+
if (canBuildPyramid(nextRow.toString())) {
33+
canBuild = true;
34+
}
35+
nextRow.setLength(nextRow.length() - 1); // backtrack
36+
}
37+
}
38+
return canBuild;
39+
}
40+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
var pyramidTransition = function(bottom, allowed) {
2+
const allowedMap = new Map();
3+
for (const pattern of allowed) {
4+
const [left, right, top] = pattern;
5+
if (!allowedMap.has(left + right)) {
6+
allowedMap.set(left + right, []);
7+
}
8+
allowedMap.get(left + right).push(top);
9+
}
10+
11+
const canBuild = (currentRow) => {
12+
if (currentRow.length === 1) return true;
13+
const nextRow = [];
14+
for (let i = 0; i < currentRow.length - 1; i++) {
15+
const left = currentRow[i];
16+
const right = currentRow[i + 1];
17+
const key = left + right;
18+
if (!allowedMap.has(key)) return false;
19+
nextRow.push(allowedMap.get(key));
20+
}
21+
const buildNextRow = (index) => {
22+
if (index === nextRow.length) return canBuild(nextRow);
23+
for (const top of nextRow[index]) {
24+
if (buildNextRow(index + 1, top)) return true;
25+
}
26+
return false;
27+
};
28+
return buildNextRow(0);
29+
};
30+
31+
return canBuild(bottom);
32+
};
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
class Solution:
2+
def pyramidTransition(self, bottom: str, allowed: List[str]) -> bool:
3+
from collections import defaultdict
4+
5+
# Create a mapping from pairs of blocks to the possible top blocks
6+
transitions = defaultdict(set)
7+
for pattern in allowed:
8+
transitions[pattern[:2]].add(pattern[2])
9+
10+
def canBuild(current_row):
11+
if len(current_row) == 1:
12+
return True
13+
14+
next_row = []
15+
for i in range(len(current_row) - 1):
16+
pair = current_row[i:i+2]
17+
if pair not in transitions:
18+
return False
19+
next_row.append(transitions[pair])
20+
21+
# Use backtracking to explore all combinations of the next row
22+
return self.backtrack(next_row, 0, "")
23+
24+
return canBuild(bottom)
25+
26+
def backtrack(self, next_row, index, current):
27+
if index == len(next_row):
28+
return self.backtrack(next_row, 0, "")
29+
30+
for block in next_row[index]:
31+
if index == len(next_row) - 1:
32+
if self.backtrack(next_row, index + 1, current + block):
33+
return True
34+
else:
35+
if self.backtrack(next_row, index + 1, current + block):
36+
return True
37+
38+
return False

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,4 @@ Through completing the Blind 75 and NeetCode 150, you will have mastered:
319319
- 2025-12-26 — [Minimum Penalty for a Shop](https://leetcode.com/problems/minimum-penalty-for-a-shop/) (Medium) → `Medium/2025-12-26-2483-Minimum-Penalty-for-a-Shop`
320320
- 2025-12-27 — [Meeting Rooms III](https://leetcode.com/problems/meeting-rooms-iii/) (Hard) → `Hard/2025-12-27-2402-Meeting-Rooms-III`
321321
- 2025-12-28 — [Count Negative Numbers in a Sorted Matrix](https://leetcode.com/problems/count-negative-numbers-in-a-sorted-matrix/) (Easy) → `Easy/2025-12-28-1351-Count-Negative-Numbers-in-a-Sorted-Matrix`
322+
- 2025-12-29 — [Pyramid Transition Matrix](https://leetcode.com/problems/pyramid-transition-matrix/) (Medium) → `Medium/2025-12-29-756-Pyramid-Transition-Matrix`

0 commit comments

Comments
 (0)