Skip to content

Commit a96b8fe

Browse files
committed
chore: add daily leetcode post 9021_TUT_3_25T1
1 parent b858fc9 commit a96b8fe

File tree

1 file changed

+368
-0
lines changed

1 file changed

+368
-0
lines changed
Lines changed: 368 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,368 @@
1+
---
2+
title: 9021_TUT_3_25T1.md
3+
date: 2025/3/07
4+
tags:
5+
- '9021'
6+
- lab
7+
abbrlink: 974decd3
8+
---
9+
10+
# Exercise 1
11+
12+
### Problem Description:
13+
You are given two integers, `m` and `n`, where:
14+
15+
- `m` represents the number of repeated units (patterns).
16+
- `n` represents the number of elements (underscores) within each unit.
17+
18+
The goal is to generate a string where:
19+
20+
- Each unit contains `n` underscores (_), separated by `|`.
21+
- These units are then concatenated together, separated by `*`.
22+
23+
### My Solution:
24+
25+
```python
26+
def generate_struct(n):
27+
return '|'.join(n * ['_'])
28+
29+
def f1(m, n):
30+
return ' * '.join(m * [generate_struct(n)])
31+
```
32+
33+
#### My Thought Process:
34+
35+
I think of each unit as a separate structure. So, I decompose the problem by breaking down the smallest unit, which is the structure made of underscores joined by `|`.
36+
After constructing each unit, I use `join()` to combine them together using `*`.
37+
38+
#### Helper Function generate_struct(n):
39+
40+
This function generates the basic structure.
41+
It creates a list of underscores (`_`) of length n and joins them with `|`.
42+
Example: If `n = 2`, the result will be "`_|_`".
43+
44+
### Standard Solution:
45+
46+
```python
47+
def f1(m, n):
48+
return ' * '.join('|'.join('_' for _ in range(n)) for _ in range(m))
49+
```
50+
51+
### Concise Expression:
52+
53+
The inner `join` creates a string of `n` underscores joined by `|` using a generator expression `('_' for _ in range(n))`.
54+
The outer `join` repeats this process `m` times and concatenates the units using `*`.
55+
56+
In summary, my solution focuses on modularity by breaking down the problem into smaller parts (like creating a structural unit), whereas the standard solution compresses everything into one line using list comprehensions.
57+
58+
# Exercise 2
59+
60+
61+
### Problem Description:
62+
63+
The goal is to generate a pattern based on the digits of a given number n. Specifically:
64+
65+
If a digit is odd, it should be represented by a black square (⬛).
66+
If a digit is even, it should be represented by a white square (⬜).
67+
The program takes a number n as input and prints a string of squares corresponding to the digits of n.
68+
69+
### My Solution:
70+
71+
```python
72+
def f2(n):
73+
ans = ''
74+
for i in str(n):
75+
if int(i) % 2 == 0:
76+
ans += ''
77+
else:
78+
ans += ''
79+
print(ans)
80+
```
81+
82+
#### My Thought Process:
83+
84+
1. Loop through each digit:
85+
Convert the number n to a string to iterate over each digit individually.
86+
87+
2. Check if the digit is even or odd:
88+
Convert each digit back to an integer and use the modulus operator (% 2) to check if the digit is even or odd.
89+
90+
3. Append the corresponding square:
91+
- If the digit is even, append a white square (⬜) to the result string.
92+
- If the digit is odd, append a black square (⬛).
93+
94+
4. Print the final string:
95+
After processing all the digits, print the final string containing black and white squares.
96+
97+
98+
99+
### Standard Solution:
100+
101+
```python
102+
def f2(n):
103+
print(''.join({0: '\u2b1c', 1: '\u2b1b'}[int(d) % 2] for d in str(n)))
104+
```
105+
106+
Dr.Martin's solution is:
107+
1. More compact and Pythonic.
108+
2. Uses a dictionary and list comprehension for brevity and efficiency.
109+
3. The Unicode characters for the squares are referenced directly using their escape sequences (`\u2b1c` for white, `\u2b1b` for black).
110+
111+
# Exercise 3
112+
113+
### Problem Description:
114+
115+
In this task, the number `n` is treated as a number expressed in different bases (ranging from 2 to 10), and we aim to convert it into its corresponding base 10 value for each of these bases, where the conversion is valid.
116+
117+
For n = 2143:
118+
- `2143` in base `5` is equivalent to `298` in base `10`.
119+
- `2143` in base `6` is equivalent to `495` in base `10`.
120+
- And so on.
121+
122+
The goal is to iterate over different base systems from 2 to 10, treat the input number `n` as if it is expressed in each base, and then convert it to base 10.
123+
124+
### My Solution:
125+
126+
```python
127+
def f3(n: int):
128+
for i in range(2, 11):
129+
try:
130+
# Treat n as a number in base i and convert it to base 10
131+
value = int(str(n), i)
132+
print(f'{n} is {value} in base {i}')
133+
except ValueError:
134+
pass
135+
```
136+
#### My Thought Process:
137+
1. Iterating over Bases (2 to 10):
138+
- We loop through the base values i ranging from 2 to 10.
139+
140+
2. Conversion Using `int()`:
141+
- For each base `i`, we treat the number `n` as a number in that base. To do this, we first convert `n` to a string (`str(n)`) and then use `int()` to interpret it as a base `i` number.
142+
- If the digits of `n` are valid for base `i`, this conversion succeeds, and the result is the base 10 equivalent of `n`.
143+
- If the digits of n are not valid for base i (for example, if base 2 is used and n contains digits greater than 1), a ValueError is raised, and we skip the invalid base.
144+
145+
3. Handling Errors with `try-except`:
146+
- The `try-except` block ensures that invalid bases are skipped, allowing us to handle cases where the digits in `n` are not valid for a particular base.
147+
148+
### Standard Solution:
149+
150+
```python
151+
def f3(n):
152+
n_as_string = str(n)
153+
min_base = max(2, max({int(d) for d in n_as_string}) + 1)
154+
for b in range(min_base, 11):
155+
print(f'{n} is {int(n_as_string, b)} in base {b}')
156+
```
157+
It skips the bases where the digits in n are not valid, and it uses a set comprehension to extract the unique digits from n_as_string. The maximum digit is then used to determine the minimum base to start iterating from.
158+
159+
160+
# Exercise 4
161+
162+
### Problem Description:
163+
164+
The task is to create a function `f4(n, base)` that returns a dictionary D, where:
165+
166+
Keys are integers from `0` to `n`.
167+
Values are tuples that represent the base `base` representation of each key, converted from base 10.
168+
169+
### My Solution:
170+
171+
```python
172+
def convert_to_base(n, base):
173+
if n == 0:
174+
return '0'
175+
digits = []
176+
while n:
177+
digits.append(str(n % base))
178+
n //= base
179+
return ''.join(digits[::-1])
180+
181+
def f4(n: int, base: int):
182+
D = {}
183+
for i in range(0, n + 1):
184+
D[i] = tuple(map(int, convert_to_base(i, base)))
185+
return D
186+
```
187+
188+
#### My Thought Process:
189+
190+
1. Helper Function `convert_to_base(n, base)`:
191+
- This function converts a number `n` from base 10 to the specified base.
192+
- We use a while loop to repeatedly take the modulus (`n % base`) and append the remainder to the list `digits`.
193+
- We then divide `n` by `base` `(n //= base)` to reduce it for the next iteration.
194+
- After collecting all digits, we reverse the list and return it as a string.
195+
196+
2. Main Function `f4(n, base)`:
197+
We initialize an empty dictionary `D`.
198+
For each number `i` from `0` to `n`, we convert `i` to the given base using `convert_to_base()`.
199+
The converted base digits are then mapped to integers and stored in a tuple as the value for each key `i` in the dictionary.
200+
201+
### Explanation of Why `map()` is not Pythonic:
202+
In the function f4, the use of `map(int, convert_to_base(i, base))` applies the `int` function
203+
to each element of the result from `convert_to_base`, effectively converting each character to an integer.
204+
205+
However, it's worth noting that the `map()` function, which originates from functional programming,
206+
has largely been superseded by more Pythonic constructs such as list comprehensions.
207+
208+
These comprehensions are generally considered superior for several reasons:
209+
- They are more elegant and concise.
210+
- They tend to be shorter in terms of syntax, making the code easier to read.
211+
- They are easier to understand for most people, especially those who are more familiar with Python's
212+
standard syntax rather than functional programming constructs.
213+
- In many cases, they are also more efficient in terms of performance.
214+
215+
For example, instead of using `map(int, ...)`, the same functionality could be achieved with a
216+
list comprehension, like so:
217+
218+
D[i] = tuple([int(digit) for digit in convert_to_base(i, base)])
219+
220+
This list comprehension achieves the same result but follows a more modern Pythonic style.
221+
222+
### Standard Solution:
223+
224+
```python
225+
def f4(n, base):
226+
D = {0: (0,)}
227+
for m in range(1, n + 1):
228+
digits = []
229+
p = m
230+
while p:
231+
digits.append(p % base)
232+
p //= base
233+
D[m] = tuple(reversed(digits))
234+
return D
235+
```
236+
237+
Both solutions are valid and achieve the same result. My approach uses a helper function for base conversion, which adds modularity,
238+
whereas the standard solution is more concise and directly integrates the conversion logic into the main function.
239+
240+
# Exercise 5
241+
242+
At the first, try to run this:
243+
```python
244+
print(0.1 + 0.2)
245+
```
246+
What happened? The result is not 0.3, but 0.30000000000000004. Why?
247+
248+
### Problem Description:
249+
250+
The approach we are using in this exercise is designed to expose the limitations of floating-point arithmetic in computers. Let's break down why this approach leads to precision inaccuracies and why other methods might not reveal these issues as clearly.
251+
252+
This problem can seem complex, and it's designed to highlight the subtleties of floating-point arithmetic. Let's walk through the logic using the test cases to figure out what the function does.
253+
254+
### Key Concepts:
255+
- **Floating-point numbers**: Computers store floating-point numbers using a binary format, which often introduces precision errors.
256+
- **Precision**: We’re working with two types of precision in this function—simple precision (same as the length of the fractional part) and double precision (twice that length).
257+
258+
### Solution:
259+
260+
```python
261+
def f5(integral_part, fractional_part):
262+
# Calculate the number of digits in the fractional part
263+
precision = len(str(fractional_part))
264+
265+
# Concatenate the integral and fractional parts as strings, then convert to a float
266+
a_float = float(str(integral_part) + '.' + str(fractional_part))
267+
268+
# Format the float with precision equal to the number of digits in the fractional part (simple precision)
269+
simple_precision = f'{a_float:.{precision}f}'
270+
271+
# Append a number of zeros equal to the fractional part length to the simple precision value (extended precision)
272+
extended_simple_precision = simple_precision + '0' * precision
273+
274+
# Format the float with precision equal to twice the number of fractional digits (double precision)
275+
double_precision = f'{a_float:.{precision * 2}f}'
276+
277+
# Print the first part of the output
278+
print('With', precision * 2, 'digits after the decimal point, ', end='')
279+
280+
# Compare if extended precision and double precision values are the same
281+
if extended_simple_precision == double_precision:
282+
# If they are the same, it means the float is precise and has trailing zeros
283+
print(simple_precision, 'prints out with', precision, 'trailing',
284+
precision == 1 and 'zero,' or 'zeroes,', 'namely, as',
285+
extended_simple_precision
286+
)
287+
else:
288+
# If not, there is a precision error, and no trailing zeros
289+
print(simple_precision, 'prints out as', double_precision)
290+
```
291+
292+
Our function attempts to check and display this floating point error with simple precision (`simple_precision`) and double precision (`double_precision`). The error becomes more obvious when we represent floating point numbers with higher precision (double the number of decimal places). So in this way, we show that floating point numbers are not always actually stored as we expect them to be with more precise representation.
293+
294+
# Exercise 6
295+
296+
### Problem Description:
297+
298+
In this task, we are given:
299+
300+
- A list `L`, which contains multiple sub-lists of integers, and all sub-lists have the same length `n`.
301+
- A list `fields`, which is a permutation of `{1, ..., n}`.
302+
303+
We are required to sort the list L by using a multi-key sorting mechanism, where:
304+
305+
- First, the elements in `L` are sorted based on the position given by the first element of `fields`.
306+
- If two sub-lists are equal based on the first field, we move to the second field, and so on.
307+
- Finally, if required, the sorting proceeds up to the last field in `fields`.
308+
309+
### Example of Fields Explanation:
310+
If `fields = [2, 1]`, it means:
311+
312+
1. First, sort based on the second element of each sublist.
313+
2. If there are ties (same values in the second position), sort based on the first element.
314+
315+
### My Solution:
316+
317+
```python
318+
def f6(L, fields):
319+
return sorted(L, key=lambda x: [x[i-1] for i in fields])
320+
```
321+
322+
1. Sorting with sorted():
323+
The `sorted()` function is used to sort the list `L`.
324+
The key parameter defines how the sorting will be performed.
325+
326+
2. Lambda Function:
327+
The lambda function defines how the sublists will be sorted. It generates a list of values for each sublist based on the positions specified in `fields`.
328+
For example, if `fields = [2, 1]`, the lambda function will extract the second and first elements from each sublist in that order, and sorting will be done based on this new list.
329+
330+
3. Key Structure:
331+
The key is a list of elements from each sublist, indexed by the positions specified in fields. We use `x[i - 1]` because fields is `1-based`, and list indexing in Python is `0-based`.
332+
333+
4. What is Lambda Function?
334+
335+
For example:
336+
337+
We have:
338+
```python
339+
f = lambda x: x * x
340+
```
341+
342+
This is equivalent to:
343+
```python
344+
def f(x):
345+
return x * x
346+
```
347+
348+
And lambda function in a sorted function is used to define a custom sorting key.
349+
```python
350+
L = [(1,2), (3,1), (5,0)]
351+
352+
SortedL = sorted(L, key=lambda x: x[1])
353+
354+
print(SortedL)
355+
```
356+
The result is: `[(5, 0), (3, 1), (1, 2)]`, it sorts the list based on the second element of each tuple.
357+
358+
### Standard Solution:
359+
360+
```python
361+
def f6(L, fields):
362+
return sorted(L, key=lambda x: tuple(x[i - 1] for i in fields))
363+
```
364+
365+
**Why Use a Tuple?**:
366+
367+
- Tuples are often preferred for multi-key sorting because they are immutable, and Python's built-in sorting functions can efficiently compare tuples.
368+
- Each sublist is transformed into a tuple of its elements based on the order defined by fields. The sorted() function then uses these tuples to sort the list.

0 commit comments

Comments
 (0)