Aller au contenu principal

Dart functional programming

· 3 minutes de lecture
Mr. Frugal
I'm afraid of paying full price.

Functional programming creates new forms of values using type conversion and built-in functions.

It is possible to chain the results and ultimately make the code more concise.

Usage

type casting

// List <-> Map <-> Set

// Cast in List
List<String> blackPink = ['a', 'b', 'c', 'd',];
final Map blackPinkMap = blackPink.asMap(); // {0: a, 1: b, 2: c, 3: d}
final Set blackPinkSet = blackPink.toSet(); // {a, b, c, d}

// Case in Map
final Map blackPinkAsMap = blackPink.asMap();
List<dynamic> keys = blackPinkAsMap.keys.toList(); // [0, 1, 2, 3]
List<dynamic> values = blackPinkAsMap.values.toList(); // [a, b, c, d]

// Cast in Set
Set blackPinkFronSet = Set.from(blackPink); // {a, b, c, d}
List balckSet = blackPinkFronSet.toList(); // [a, b, c, d]

map()

  • Methods of List
  • Returns a new list after changing the format of all member variables.
  • The list created by map() has a different address value even if the member variables are the same

iterable:

A collection that can be iterated over (list, array)

Use the .toList() method to convert to a list

List<String> blackPink = ['a', 'b', 'c', 'd',]

blackPink.map((item){
return 'this it $item'
});

// with arrow function
final blackPink2 = blackPink.map((item) => 'black pink $item')

mapping Map

Map<String, String> harryPotter = {
'harry potter': '해리포터',
'ron': '론',
'hermione': '헤르미온느'
};

// When mapping a map, you receive both key and value.
final result = harryPotter.map(
(key, value) => MapEntry('harry potter character $key', '해리포터 캐릭터 $value'));

void main() {
// key
print(harryPotter.keys.map((item) => 'key is $item').toList());
// value
print(harryPotter.values.map((item) => 'value is $item').toList());
}

mapping Set

Set blackPinkSet = {"rose",'jisu','jenny','lisa'};

final newSet = blackPinkSet.map((item) => 'this is $item').toSet();

where()

Purpose of filtering

List<Map<String, String>> people = [
{
'name': '제니',
'group': '블랙핑크',
},
{
'name': '로제',
'group': '블랙핑크',
},
{
'name': 'RM',
'group': 'BTS',
}
];

final result = people.where((item) => item['group'] == 'BTS').toList();

reduce()

  • Only the first values of the previous and next are entered in the first time.
  • After that, the return value of the callback function becomes the previous value of the next iteration.
  • Reduce can only return results of the same type as instance variables.
  • This problem can be solved with fold()
List<int> numbers = [1, 2, 3, 4, 5];

int resultInt = numbers.reduce((prev, next) {
return prev + next;
});

// arrow function
numbers.reduce((prev, next) => prev + next);

fold()

  • Like reduce(), it allows you to set the return data type while setting an initial value
  • The first parameter goes into prev, and the first member variable goes into next
List<int> numbers = [1, 2, 3, 4, 5];

// Specify the return type as Generic
numbers.fold<int>(0, (prev, next) => prev + next);

List<String> words = ['Hi', 'Hello'];

words.fold<String>('', (prev, next) => prev + next); // HiHello
words.fold<int>(0, (prev, next) => prev + next.length); // 7

…cascade operator

  • When combining lists
  • The member variables are unpacked and added to the new list
  • A new list is created
List<int> even = [2, 4, 6];
List<int> odd = [1, 3, 5];
List newArr = [...even, ...odd];

// `[...even]` and `even` are different.

Introduction to K-way Merge

· 4 minutes de lecture
Mr. Frugal
I'm afraid of paying full price.

About the Pattern

The K-way merge pattern is a fundamental algorithmic strategy used to merge K sorted data structures—such as arrays and linked lists—into a single sorted structure. It extends the traditional merge sort algorithm, which combines two sorted structures into one.

Note: For simplicity, the term lists will refer to both arrays and linked lists in this discussion.

The core idea behind the K-way merge algorithm is simple: repeatedly select the smallest (or largest, for descending order) element from the first elements of the K input lists and append it to a new output list. This process continues until all elements are merged into the output list, maintaining the sorted order.

How the Algorithm Works

The K-way merge algorithm has two main approaches for achieving its goal, each leading to the same result. Let's explore these approaches in detail.


Approach 1: Using a Min Heap

  1. Initialize the Heap
    Insert the first element of each list into a min heap. This heap helps efficiently track the smallest current element among the lists.

  2. Build the Output List
    Remove the smallest element from the heap (always at the top) and add it to the output list.

  3. Track Element Origins
    Keep track of which list each element in the heap originated from to determine the next element to add.

  4. Replace Elements in the Heap
    After removing the smallest element, replace it with the next element from the same list.

  5. Repeat Steps
    Repeat steps 2–4 until all elements are merged into the output list.


Approach 2: Grouping and Merging Pairs of Lists

  1. Divide into Pairs
    Divide the K sorted lists into pairs, grouping them for two-way merges.

  2. Perform Two-Way Merges
    For each pair, perform a standard two-way merge to create a single sorted list for that pair.

  3. Handle Odd Lists
    If there is an odd number of lists, leave one list unmerged for the current round.

  4. Repeat Pairing and Merging
    Continue pairing and merging the resulting lists until only one sorted list remains.


Examples of Problems Solved with K-way Merge

  1. Median of K Sorted Arrays
    Find the median of K sorted arrays.

  2. K-th Smallest Element Across Arrays
    Find the K-th smallest element among multiple sorted arrays.


Identifying Problems That Match This Pattern

A problem likely fits this pattern if:

  • Merging Sorted Structures: It involves merging multiple sorted arrays or matrices.
  • Finding K-th Smallest/Largest: It requires identifying the K-th smallest or largest element across sorted collections.

Real-World Applications

  1. Patient Records Aggregation
    Combine sorted streams of patient data (lab results, notes, reports) into a unified, chronologically ordered record for comprehensive healthcare management.

  2. Merging Financial Transaction Streams
    Merge sorted transactions (trades, payments, transfers) into a single stream for real-time analysis and fraud detection.

  3. Log File Analysis
    Merge server logs into a single, time-ordered stream for performance monitoring, user behavior analysis, or error diagnosis.


Merge Sorted Array solution:

The following example demonstrates merging two sorted arrays in place:

  1. Initialize two pointers: p1 (last element of nums1) and p2 (last element of nums2).
  2. Initialize a pointer p pointing to the last element of nums1.
  3. Compare elements:
    • If nums1[p1] > nums2[p2], set nums1[p] = nums1[p1] and decrement p1 and p.
    • Otherwise, set nums1[p] = nums2[p2] and decrement p2 and p.
  4. Repeat until all elements of nums2 are merged into nums1.

The algorithm processes the arrays in reverse order, starting from the largest elements and filling nums1 from the end. This approach prevents overwriting existing data in nums1 as it is merged in place. The merge only considers the first m elements in nums1 and the first n elements in nums2. Any extra space in nums1 beyond m + n is irrelevant for the merging process.

Introduction to Two Heaps

· 4 minutes de lecture
Mr. Frugal
I'm afraid of paying full price.

About the Pattern

The two heaps pattern is a versatile and efficient approach for solving problems involving dynamic data processing, optimization, and real-time analysis. As the name suggests, this pattern uses two heaps, which could be:

  • Two min heaps
  • Two max heaps
  • A combination of one min heap and one max heap

By exploiting the heap property, this pattern is often used to implement computationally efficient solutions.

Key Properties of Heaps

  • Insertion/Removal Complexity: O(log n), where n is the number of elements in the heap.
    • When adding a new element to the heap:
      • Insert it at the last position of the heap.
      • Restore the heap property by moving upward, comparing the element with its parent node (Heapify-Up).
  • Access Root Element: O(1).
    • Min Heap: Root stores the smallest element.
    • Max Heap: Root stores the largest element.

Common Use Case

Given a dataset, the two heaps pattern can be used to divide it into two parts and efficiently find:

  • The smallest value from one part (using a min heap).
  • The largest value from the other part (using a max heap).

Other scenarios include finding:

  • The two largest numbers from two datasets (using two max heaps).
  • The two smallest numbers from two datasets (using two min heaps).

These examples highlight the pattern's flexibility for solving various problems by enabling quick access to minima and maxima as needed.


Examples

1. Sliding Window Median

Given an array of integers and a window size k, find the median of each sliding window of size k as it moves from left to right through the array.

2. Find Median of a Number Stream

Given a continuous stream of numbers, efficiently find the median of the numbers seen so far after any insertion.

  1. Insert the new data into the Max-Heap first.
  2. If the root value of the Max-Heap is greater than the root value of the Min-Heap, move the largest value from the Max-Heap to the Min-Heap to maintain the correct order.
  3. Adjust the sizes of the two heaps to maintain balance:
  4. The size of the Max-Heap should be at most 1 greater than the size of the Min-Heap. Median Calculation: If the sizes of the two heaps are equal, return (Max-Heap root+Min-Heap root)/2 If the Max-Heap is larger, return the root of the Max-Heap.

Does Your Problem Match This Pattern?

Applicable Scenarios

The two heaps pattern applies if:

  1. Static or Streaming Data:
    • Linear Data: Input data is linear but not sorted. (If sorted, this pattern isn’t required.)
    • Stream of Data: Input is a continuous data stream.
  2. Maxima and Minima Calculation:
    • The input can be divided into two parts, requiring repeated calculations for:
      • Two maxima.
      • Two minima.
      • One maximum and one minimum.

Real-World Problems

1. Video Platforms

For demographic studies, calculate the median age of viewers efficiently as new users sign up for video streaming.

2. Gaming Matchmaking

Match players of similar skill levels for a balanced gaming experience. Use:

  • One heap for minimum skill levels.
  • One heap for maximum skill levels.

3. IPO Solution

Efficiently select projects to maximize profits with the following steps:

  1. Initialize a Min-Heap: Store the project capital requirements.
  2. Identify Feasible Projects: Find projects investable within the current capital range.
  3. Select the Most Profitable Project: Choose the project yielding the highest profit.
  4. Update Capital: Add the earned profit to the current capital.
  5. Repeat Until Target Achieved: Continue until k projects are selected.

Introduction to In-Place Manipulation of a Linked List

· 3 minutes de lecture
Mr. Frugal
I'm afraid of paying full price.

In this guide, we'll explore the In-Place Manipulation of a Linked List pattern, its real-world applications, and the problems it helps solve.

About the Pattern

The in-place manipulation of a linked list allows us to modify a linked list without using additional memory. "In-place" refers to an algorithm that processes or modifies a data structure using only existing memory space, without requiring extra memory proportional to the input size.

This pattern is especially useful for problems that involve modifying the structure of a linked list, such as changing the order of node connections. For instance, certain problems require reversing a set of nodes or even the entire linked list. Instead of creating a new linked list with reversed links, we can achieve this in place without extra memory usage.

A naive approach to reversing a linked list involves traversing it and creating a new linked list with reversed links. This method has a time complexity of O(n), but it consumes O(n) extra space.

How can we implement in-place reversal efficiently?

We iterate over the linked list while keeping track of three nodes:

  • The current node
  • The next node
  • The previous node

Tracking these three nodes allows us to efficiently reverse the links between each pair of nodes. This in-place reversal operates in O(n) time and consumes only O(1) space.

Examples

Below are some problems that can be solved using this approach:

  1. Reverse the second half of a linked list

    • Given a singly linked list, reverse only the second half.
  2. Rotate a linked list clockwise k times

    • Given a singly linked list and an integer k, rotate the linked list clockwise k times.

Does Your Problem Match This Pattern?

Yes, if the following conditions are met:

  1. Linked list restructuring

    • The input is a linked list, and the task requires modifying its structure rather than the data in individual nodes.
  2. In-place modification

    • The changes must be made in place, meaning we cannot use more than O(1) additional space.

Real-World Applications

Many real-world problems utilize the in-place manipulation of a linked list pattern. Here are some examples:

1. File System Management

  • File systems often rely on linked lists to organize directories and files.
  • Operations like rearranging files within a directory can be efficiently handled by modifying the linked list in place.

2. Memory Management

  • In low-level programming and embedded systems, dynamic memory allocation and deallocation often involve manipulating linked lists of free memory blocks.
  • Tasks such as merging adjacent free blocks or splitting large blocks can be optimized using in-place operations.

Reverse Linked List Solution

Follow these steps to reverse a linked list in place:

  1. Initialize

    • Set prev and next pointers to NULL.
    • Set the curr (current pointer) to the head node.
  2. Traverse the linked list

    • Continue until the curr pointer reaches the end.
  3. Reverse pointers

    • Set the next pointer to the next node.
    • Reverse the current node’s pointer to point to the previous node.
  4. Update pointers

    • Move prev and curr forward.
  5. Update head

    • After traversal, prev points to the last node of the original list.
    • Set the head pointer to prev.

This efficient approach allows us to reverse a linked list in O(n) time using only O(1) space.

Introduction to Merge Intervals

· 2 minutes de lecture
Mr. Frugal
I'm afraid of paying full price.

Let's explore the Merge Intervals pattern, its real-world applications, and the types of problems it helps solve.

About the Pattern

The Merge Intervals pattern addresses problems involving overlapping intervals. Each interval is defined by a start and an end time. For example, an interval [10, 20] represents a time span starting at 10 seconds and ending at 20 seconds.

This pattern is commonly used for tasks such as:

  • Merging overlapping intervals
  • Inserting new intervals into existing sets
  • Determining the minimum number of intervals required to cover a given range

Typical problems solved using this approach include event scheduling, resource allocation, and time slot consolidation.

Understanding Overlapping Intervals

The key to mastering this pattern is understanding how two intervals may overlap.

Examples

Here are some problems that can be solved using this method:

  1. Merge Intervals
    Given a sorted list of intervals, merge all overlapping ones into a single interval.

  2. Meeting Rooms
    Given an array of meeting time intervals with start and end times, determine if a person can attend all meetings.

Does Your Problem Match This Pattern?

Your problem likely fits the Merge Intervals pattern if both of these conditions apply:

  • Array of intervals: The input is an array of intervals.
  • Overlapping intervals: The problem involves finding the union, intersection, or gaps between overlapping intervals.

Real-World Applications

This pattern has many practical applications, such as:

  • Displaying a busy schedule: Show a user's busy hours without revealing individual meeting details in a calendar.
  • Scheduling a new meeting: Insert a new meeting into a schedule while ensuring no conflicts.
  • Task scheduling in operating systems (OS): Allocate tasks based on priority and available processing time slots.

Merge Intervals Solution

  1. Insert the first interval from the input list into the output list.
  2. Iterate through the remaining intervals in the input list.
  3. If the current interval overlaps with the last interval in the output list:
    • Merge them.
    • Replace the last interval in the output list with the merged interval.
  4. If the current interval does not overlap, add it to the output list.

By following this approach, we can efficiently handle problems involving merging and managing intervals.

Introduction to Sliding Window

· 3 minutes de lecture
Mr. Frugal
I'm afraid of paying full price.

Overview

The Sliding Window pattern is a powerful technique used for efficiently solving problems related to sequential data, including arrays and strings. This approach allows us to process subarrays or substrings dynamically by maintaining a window that adjusts as it slides across the data.

Understanding the Pattern

The Sliding Window technique helps in solving problems that involve sequential data by maintaining a dynamic window that moves through an array or string. Instead of recalculating values from scratch, the window adjusts by adding new elements and removing old ones as it slides.

Think of it as looking through a narrow frame while walking down a long hallway filled with paintings. As you move, new paintings come into view while others disappear. Similarly, this technique processes only a subset of the data at any time, improving efficiency.

Why is Sliding Window Efficient?

Consider a problem where we need to find k consecutive integers with the highest sum in an array. A naive approach would involve calculating the sum of all possible subarrays of size k, resulting in a time complexity of O(kn).

However, using the Sliding Window technique, instead of recalculating sums entirely, we update the sum dynamically:

  • Subtract the element that leaves the window.
  • Add the element that enters the window.
  • Update the maximum sum accordingly.

This reduces the time complexity to O(n), as each window update takes constant time O(1). The goal is to ensure that the computation per window move remains minimal, ideally in O(1) or a slow-growing function like log(n).

Example Problems

1. Maximum Sum Subarray of Size K

Given an array of integers and a positive integer k, find the maximum sum of any contiguous subarray of size k.

2. Longest Substring Without Repeating Characters

Given a string, determine the length of the longest substring that does not contain duplicate characters.

Does Your Problem Fit This Pattern?

Your problem likely benefits from the Sliding Window approach if:

  • Contiguous Data: The input is stored as a contiguous structure, such as an array or string.
  • Processing Subsets: The problem requires computations on a contiguous subset of elements that slide through the data. The window size may be fixed or dynamic.
  • Efficient Computation: The per-move calculations should be constant-time or nearly constant.

Real-World Applications

  • Telecommunications: Determine the peak number of users connected to a cellular network’s base station within a k-millisecond window.
  • Video Streaming: Compute the median buffering events over each one-minute interval in a streaming session.
  • Social Media Mining: Identify the shortest sequence of posts by one user that includes all topics mentioned by another user.

Example: Repeated DNA Sequences

Given a DNA sequence (dna) and an integer k, return all contiguous subsequences of length k that appear more than once. If no such sequence exists, return an empty set.

Solution Approach

  1. Iterate through all substrings of length k in the given string.
  2. Store the hash of each substring to track uniqueness.
  3. If a hash is found again, the substring is repeated and should be added to the output.
  4. Return the set of repeated substrings after processing the entire string.

Introduction to Fast and Slow Pointers

· 4 minutes de lecture
Mr. Frugal
I'm afraid of paying full price.

Overview

The Fast and Slow Pointers pattern is a technique used in problem-solving, particularly for detecting cycles and identifying key structural properties in data structures. This pattern finds application in real-world scenarios and various algorithmic problems.

About the Pattern

The fast and slow pointers method, similar to the two-pointers approach, involves two pointers traversing an iterable data structure at different speeds. However, unlike the two-pointers technique, which mainly focuses on comparing values, this method is used for analyzing structure and properties.

Key Concept

  • The pointers start at the same position but move at different speeds.
  • The slow pointer advances one step at a time.
  • The fast pointer moves two steps at a time.
  • Due to their differing speeds, this technique is often referred to as the Hare and Tortoise Algorithm, where the hare (fast pointer) moves faster than the tortoise (slow pointer).
  • If a cycle exists, the two pointers will eventually meet, making it useful for detecting cycles, midpoints, or intersections.

Visualization

Imagine two runners on a circular track starting from the same position. If one runs faster than the other, the faster runner will eventually overtake the slower one. This concept mirrors how cycle detection works in linked lists and arrays.

Examples

Here are some problems that can be solved using this approach:

  1. Finding the Middle of a Linked List: Given a singly linked list, return its middle node.
  2. Detecting a Cycle in an Array: Given an array of non-negative integers where elements act as indices pointing to the next element, determine if a cycle exists.

When to Use This Pattern?

Use this pattern if the following condition holds:

  • The problem involves a linear data structure such as an array, linked list, or string.

Additionally, consider this approach if either of these conditions is met:

  • Cycle or Intersection Detection: The problem involves detecting loops in linked lists or arrays or finding intersections between two linked lists or arrays.
  • Finding a Key Element in a Segment: This includes finding the middle element of a data structure, such as the second half, second tertile, or second quartile.

Real-World Applications

The fast and slow pointers technique is widely used in real-world scenarios. Below are a couple of examples:

As an IT administrator managing a large server, you may encounter symbolic links (symlinks) pointing to other files. Sometimes, a loop may form—where symlink A points to B, and B eventually links back to A.

Using fast and slow pointers:

  • The slow pointer follows links one step at a time.
  • The fast pointer jumps two steps.
  • If both pointers meet, a cycle is detected, indicating an infinite loop in the symlink structure.

2. Detecting Cyclic Dependencies in Object-Oriented Compilation

During compilation, object-oriented modules may depend on one another. If module A depends on B, and B depends on A, a cycle is formed.

By applying fast and slow pointers:

  • The slow pointer moves one module at a time.
  • The fast pointer moves two modules at a time.
  • If the pointers meet, a cyclic dependency exists, which needs to be resolved for successful compilation.

Example: Happy Number Problem

A Happy Number is a number that eventually reaches 1 when replaced by the sum of the squares of its digits. If it enters a cycle instead, it is not a happy number.

Solution Approach

  1. Initialize two pointers:

    • slow_pointer: Starts at the input number.
    • fast_pointer: Starts at the sum of squared digits of the input number.
  2. Loop until:

    • fast_pointer reaches 1 (indicating a happy number).
    • Both pointers meet, indicating a cycle.
  3. Update pointers:

    • Move slow_pointer by replacing it with the sum of the squares of its digits.
    • Move fast_pointer in the same manner, but twice.
  4. Check for happiness:

    • If fast_pointer equals 1, return TRUE (happy number).
  5. Detect a cycle:

    • If the loop exits without reaching 1, return FALSE, confirming the presence of a cycle (not a happy number).

By leveraging the Fast and Slow Pointers approach, many problems can be efficiently solved with minimal space complexity.

Introduction to Two Pointers

· 3 minutes de lecture
Mr. Frugal
I'm afraid of paying full price.

Let's explore the Two Pointers technique, its real-world applications, and the types of problems it can solve.

About the Pattern

The Two Pointers technique is a powerful approach used to efficiently traverse or manipulate sequential data structures like arrays or linked lists. As the name implies, it involves maintaining two pointers that move through the structure in a coordinated manner either starting from different positions or moving in opposite directions.

These pointers dynamically adjust based on specific conditions, enabling optimal solutions in terms of time and space complexity. Whenever a problem requires finding two elements in an array that satisfy a certain condition, the Two Pointers approach should be one of the first strategies to consider.

The pointers may traverse the data structure in one or both directions, depending on the problem. For example, to check if a string is a palindrome, one pointer can start at the beginning while the other starts at the end. At each step, their values are compared to verify the palindrome condition.

A naive approach to solving this problem would involve nested loops, resulting in a time complexity of O(n²). However, using Two Pointers moving toward the center from either end leverages the symmetry of palindromic strings. This allows for comparisons in a single loop, improving efficiency to O(n).

Examples

Below are some common problems that can be solved using this technique:

  • Reversing an array: Given an array of integers, reverse it in place.
  • Pair with a given sum in a sorted array: Given a sorted array, find a pair of numbers that sum to a target value T.

Does Your Problem Match This Pattern?

The Two Pointers technique is applicable if all the following conditions hold:

  1. Linear Data Structure: The input can be traversed sequentially, such as an array, linked list, or string.
  2. Processing Pairs: The problem requires processing elements at two different positions simultaneously.
  3. Dynamic Pointer Movement: The pointers move independently based on conditions. They may traverse the same data structure or two different ones.

Real-World Applications

Many real-world problems utilize the Two Pointers pattern. Here’s one example:

Memory Management

The Two Pointers technique plays a crucial role in memory allocation and deallocation. A memory pool typically has two pointers:

  • Start Pointer: Points to the beginning of the available memory block.
  • End Pointer: Indicates the end of the block.

When a process requests memory, the start pointer moves forward to allocate space. When memory is freed, the start pointer moves backward, marking the space as available. The end pointer remains fixed, preventing issues such as overlapping allocations.

Valid Palindrome Solution

Below are the steps to check if a string is a palindrome using the Two Pointers approach:

  1. Initialize two pointers—one at the beginning and one at the end of the string.
  2. Compare the characters at both pointers.
  3. If they do not match, return false. Otherwise, move both pointers one step toward the middle.
  4. Continue until the pointers meet.
  5. If no mismatch is found before they meet, return true.

프렌즈 시즌1 1화

· 7 minutes de lecture
Mr. Frugal
I'm afraid of paying full price.

프렌즈 시즌1 1화 주요 표현

  • Finally, I figure. I'd better answer it. # 마침내 생각해보니, 그냥 전화를 받는게 낫겠다고 판단했어

  • I feel like someone grabbed my small intestine, pulled it out of my mouth. . . and tied it around my neck. 마치 누군가 내 작은창자를 잡아당겨 입 밖으로 끄집어낸 다음, 그걸 내 목에 감아 묶은 것 같은 기분이야. - 그는 (아내인 **캐롤(Carol)**이 떠나고(레즈비언이라는 사실을 깨닫고 이혼), 엄청나게 우울한 상태에서 이렇게 표현한 거죠)

  • No, don't! Stop cleansing my aura. - 그가 이혼 후 우울해하고 있을 때, **피비(Phoebe)**가 히피 스타일답게 **"네 오라를 정화해 줄게"**라며 손을 휘젓자, 로스가 짜증 내면서 이렇게 말한다

  • Fine. Be murky. # "알겠어, 그냥 우울한 채로 있어."

  • Why does everyone keep fixating on that? # "왜 다들 그거에만 집착하는 거야?"

  • Everybody, this is Rachel, another Lincoln High survivor. # "다들, 여기 레이첼이야. 링컨 고등학교를 함께 버텨낸 또 한 명의 생존자!"

  • You want to tell us now, or are we waiting for four wet bridesmaids? # "지금 얘기할래? 아니면 흠뻑 젖은 신부 들러리 넷을 기다릴까?"

  • I was more turned on by this gravy boat than by Barry. # "...배리보다 이 그레이비 보트에 더 끌렸어."

  • And then I really freaked out, when it hit me How much Barry looks like Mr. Potato Head. # 갑자기 **"배리가 미스터 포테이토 헤드처럼 생겼다"**는 생각이 들었고, 그제야 자신이 배리를 진짜로 사랑하지 않는다는 걸 깨닫게 된 거죠

  • I didn't know where to go, and I know you and I have drifted apart. . . # "어디로 가야 할지 몰랐어. 그리고 우리 예전처럼 가깝지 않다는 것도 알아..."

  • Who wasn't asked to the wedding. # "결혼식에 초대받지 못한 사람."

  • What if I want to be a purse? # "근데 내가 핸드백이 되고 싶으면?"

  • It's a metaphor, Daddy! # "그건 비유적인 표현이야, 아빠!"

  • I guess we've established she's staying with Monica. # "이제 확실해졌네, 레이첼은 모니카랑 지내기로 했다는 게."

  • Raindrops on roses And whiskers on kittens # 장미 위의 빗방울 그리고 아기 고양이의 수염

  • Doorbells and sleigh bells And something with mittens # 초인종과 썰매 종소리 그리고 장갑과 함께하는 무언가

  • Me and Chandler live across the hall. And he's away a lot. # 나랑 챈들러는 복도 건너편에 살아. 그리고 그는 자주 집을 비워.

  • Joey, stop hitting on her! # 조이, 그녀한테 작업 좀 그만 걸어!

  • He finally asked you out? It's a ''Dear Diary'' moment. # 그가 드디어 너한테 데이트 신청했어? 이건 완전 "일기장에 써야 할 순간" 이네!

  • -Go on! It's Paul, the wine guy! # 어서 가! 폴이잖아, 와인 가이!

  • Does he sell it, drink it, or he just complains a lot? # 그 사람 와인을 파는 거야, 마시는 거야, 아니면 그냥 불평만 하는 거야?

  • Rachel, what are you up to tonight? # 레이첼, 오늘 밤에 뭐 할 거야?

  • If you start with that, we're out of here. # 그 얘기 시작하면, 우리 바로 나간다.

  • She got the furniture, the stereo, the good TV. What did you get? You guys. You got screwed. # 그녀가 가구도 가져갔고, 스테레오도 가져갔고, 좋은 TV도 가져갔잖아. 그럼 넌 뭘 가졌는데? 너희들. 완전 당했네

  • I should've caught on when she went to the dentist four and five times a week. # 난 그녀가 일주일에 네다섯 번씩 치과에 갈 때 눈치챘어야 했어.

  • How did you get through it? # 넌 어떻게 이겨냈어?

  • I shredded my old boyfriend's favorite bath towel. # ...난 내 전 남자친구가 아끼던 목욕 수건을 갈기갈기 찢어버렸어.

  • Steer clear of you! # 너한텐 가까이 가지 말아야겠다!

  • You probably think it's about making love with your socks on, but it isn't. # 넌 아마 이게 양말 신고 사랑을 나누는 얘기라고 생각하겠지만, 그게 아니야.

  • Between us, we haven't had a relationship last longer than a Mento. # 우리 사이에, 사탕 하나 녹는 시간보다 오래간 연애가 없었잖아

  • Four years of closeness and sharing. After which, she ripped your heart out. . . # 4년 동안 함께하며 가까워지고, 모든 걸 나눴지. 그리고 나서... 그녀가 네 심장을 산산조각 냈지만.

  • You wanna spell it out with noodles? # 국수로 글자라도 만들어서 설명해줄까?

  • It's more of a fifth date kind of revelation. So there's going to be a fifth date? # 이건 좀 다섯 번째 데이트쯤 에 할 얘긴데. 그럼 다섯 번째 데이트가 있는 거네?

  • Being spit on is probably not what you need right now. # 지금 침 뱉는 거 가 네가 가장 필요했던 건 아닐 텐데.

  • I'm glad you smashed her watch. # 네가 그녀의 시계를 부숴버려서 다행이야.