Chapter 2: Data Structures & Built-ins - Interview Preparation Notes
Table of Contents
- Advanced List Operations
- Tuple Deep Dive
- Set Operations & Methods
- Dictionary Mastery
- String Methods & Manipulation
- Important Built-in Functions
- Data Structure Comparison
- Common Interview Questions
- Practice Problems
Advanced List Operations
List Methods Deep Dive
# Creating lists
numbers = [1, 2, 3, 4, 5]
fruits = ["apple", "banana", "cherry"]
mixed = [1, "hello", 3.14, [1, 2, 3]]
# Adding elements
fruits.append("orange") # Add single element to end
fruits.extend(["grape", "kiwi"]) # Add multiple elements
fruits.insert(1, "mango") # Insert at specific index
fruits += ["pear"] # Concatenation
# Removing elements
fruits.remove("banana") # Remove first occurrence
fruits.pop() # Remove and return last element
fruits.pop(0) # Remove and return element at index
del fruits[1] # Delete element at index
fruits.clear() # Remove all elements
# Finding elements
fruits = ["apple", "banana", "cherry", "apple"]
print(fruits.index("apple")) # 0 (first occurrence)
print(fruits.count("apple")) # 2 (count occurrences)
print("banana" in fruits) # True (membership test)
# Sorting and reversing
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
numbers.sort() # In-place sorting
print(numbers) # [1, 1, 2, 3, 4, 5, 6, 9]
numbers.sort(reverse=True) # Descending order
print(numbers) # [9, 6, 5, 4, 3, 2, 1, 1]
# Create new sorted list without modifying original
original = [3, 1, 4, 1, 5]
sorted_list = sorted(original) # [1, 1, 3, 4, 5]
print(original) # [3, 1, 4, 1, 5] (unchanged)
# Reversing
numbers = [1, 2, 3, 4, 5]
numbers.reverse() # In-place reverse
print(numbers) # [5, 4, 3, 2, 1]
reversed_list = list(reversed(numbers)) # Create new reversed listAdvanced List Slicing
# Basic slicing: list[start:stop:step]
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Basic slicing
print(numbers[2:5]) # [2, 3, 4]
print(numbers[:3]) # [0, 1, 2]
print(numbers[3:]) # [3, 4, 5, 6, 7, 8, 9]
print(numbers[:]) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (copy)
# Step slicing
print(numbers[::2]) # [0, 2, 4, 6, 8] (every 2nd element)
print(numbers[1::2]) # [1, 3, 5, 7, 9] (every 2nd starting from index 1)
print(numbers[::3]) # [0, 3, 6, 9] (every 3rd element)
# Negative indexing
print(numbers[-1]) # 9 (last element)
print(numbers[-3:]) # [7, 8, 9] (last 3 elements)
print(numbers[:-2]) # [0, 1, 2, 3, 4, 5, 6, 7] (all except last 2)
# Reverse slicing
print(numbers[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] (reverse)
print(numbers[5:2:-1]) # [5, 4, 3] (reverse from index 5 to 2)
# Modifying slices
numbers[2:5] = [10, 20, 30] # Replace slice
print(numbers) # [0, 1, 10, 20, 30, 5, 6, 7, 8, 9]
numbers[::2] = [100, 200, 300, 400, 500] # Replace every 2nd element
print(numbers) # [100, 1, 200, 20, 300, 5, 400, 7, 500, 9]List Comprehensions (Preview - Detailed in Chapter 3)
# Basic list comprehension
squares = [x**2 for x in range(5)]
print(squares) # [0, 1, 4, 9, 16]
# With condition
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares) # [0, 4, 16, 36, 64]
# Nested list comprehension
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row]
print(flattened) # [1, 2, 3, 4, 5, 6, 7, 8, 9]Tuple Deep Dive
Tuple Immutability
# Tuples are immutable
coordinates = (10, 20)
# coordinates[0] = 15 # TypeError: 'tuple' object does not support item assignment
# But if tuple contains mutable objects, those can be modified
nested = ([1, 2, 3], "hello")
nested[0].append(4) # This works!
print(nested) # ([1, 2, 3, 4], 'hello')Tuple Packing and Unpacking
# Tuple packing
person = "John", 25, "Engineer" # Parentheses optional
print(person) # ('John', 25, 'Engineer')
# Tuple unpacking
name, age, job = person
print(f"Name: {name}, Age: {age}, Job: {job}")
# Multiple assignment (tuple unpacking)
a, b = 10, 20
print(f"a = {a}, b = {b}") # a = 10, b = 20
# Swapping variables (common interview question)
a, b = b, a
print(f"a = {a}, b = {b}") # a = 20, b = 10
# Unpacking with * (Python 3.5+)
numbers = (1, 2, 3, 4, 5)
first, *middle, last = numbers
print(f"First: {first}, Middle: {middle}, Last: {last}")
# First: 1, Middle: [2, 3, 4], Last: 5
# Unpacking in function calls
def add_three(a, b, c):
return a + b + c
values = (1, 2, 3)
result = add_three(*values) # Unpack tuple as arguments
print(result) # 6Tuple Methods
# Tuple methods (limited compared to lists)
numbers = (1, 2, 3, 2, 4, 2)
print(numbers.count(2)) # 3 (count occurrences)
print(numbers.index(3)) # 2 (index of first occurrence)
# Tuple concatenation
tuple1 = (1, 2, 3)
tuple2 = (4, 5, 6)
combined = tuple1 + tuple2
print(combined) # (1, 2, 3, 4, 5, 6)
# Tuple repetition
repeated = (1, 2) * 3
print(repeated) # (1, 2, 1, 2, 1, 2)When to Use Tuples vs Lists
# Use tuples when:
# 1. Data shouldn't change (coordinates, database records)
coordinates = (10, 20)
person_info = ("John", 25, "Engineer")
# 2. As dictionary keys (tuples are hashable, lists are not)
locations = {
(0, 0): "origin",
(1, 1): "diagonal",
(2, 2): "another diagonal"
}
# 3. Function return values
def get_name_and_age():
return "John", 25
name, age = get_name_and_age()
# Use lists when:
# 1. Data needs to be modified
shopping_list = ["milk", "bread", "eggs"]
shopping_list.append("butter")
# 2. Order matters and might change
scores = [85, 92, 78, 96]
scores.sort()Set Operations & Methods
Set Creation and Basic Operations
# Creating sets
fruits = {"apple", "banana", "cherry"}
numbers = set([1, 2, 3, 4, 5])
empty_set = set() # Not {} (that's a dict)
# Adding elements
fruits.add("orange")
fruits.update(["grape", "kiwi"]) # Add multiple elements
fruits.update({"mango", "pear"}) # Add from another set
# Removing elements
fruits.remove("banana") # Raises KeyError if not found
fruits.discard("apple") # No error if not found
fruits.pop() # Remove and return arbitrary element
fruits.clear() # Remove all elements
print(fruits) # {'grape', 'kiwi', 'mango', 'pear'}Set Mathematical Operations
# Set operations
set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}
# Union
union1 = set1.union(set2)
union2 = set1 | set2
print(union1) # {1, 2, 3, 4, 5, 6, 7, 8}
# Intersection
intersection1 = set1.intersection(set2)
intersection2 = set1 & set2
print(intersection1) # {4, 5}
# Difference
diff1 = set1.difference(set2)
diff2 = set1 - set2
print(diff1) # {1, 2, 3}
# Symmetric difference (elements in either set, but not both)
sym_diff1 = set1.symmetric_difference(set2)
sym_diff2 = set1 ^ set2
print(sym_diff1) # {1, 2, 3, 6, 7, 8}
# Subset and superset
set3 = {1, 2, 3}
print(set3.issubset(set1)) # True
print(set1.issuperset(set3)) # True
print(set1.isdisjoint(set2)) # False (they share elements)Set Methods
# Set methods
fruits = {"apple", "banana", "cherry"}
# Check membership
print("apple" in fruits) # True
print("orange" not in fruits) # True
# Length
print(len(fruits)) # 3
# Copy
fruits_copy = fruits.copy()
print(fruits_copy) # {'apple', 'banana', 'cherry'}
# Frozen sets (immutable sets)
frozen = frozenset([1, 2, 3, 4])
# frozen.add(5) # AttributeError: 'frozenset' object has no attribute 'add'Dictionary Mastery
Dictionary Creation and Access
# Creating dictionaries
person = {
"name": "John",
"age": 25,
"city": "New York"
}
# Alternative creation methods
person2 = dict(name="Jane", age=30, city="Boston")
person3 = dict([("name", "Bob"), ("age", 35), ("city", "Chicago")])
# Accessing values
print(person["name"]) # John
print(person.get("age")) # 25
print(person.get("phone", "N/A")) # N/A (default value)
# Check if key exists
print("name" in person) # True
print("phone" in person) # FalseDictionary Methods
# Dictionary methods
person = {"name": "John", "age": 25, "city": "New York"}
# Keys, values, items
print(person.keys()) # dict_keys(['name', 'age', 'city'])
print(person.values()) # dict_values(['John', 25, 'New York'])
print(person.items()) # dict_items([('name', 'John'), ('age', 25), ('city', 'New York')])
# Update dictionary
person.update({"phone": "123-456-7890", "age": 26})
print(person) # {'name': 'John', 'age': 26, 'city': 'New York', 'phone': '123-456-7890'}
# Remove items
del person["city"] # Remove key-value pair
phone = person.pop("phone") # Remove and return value
print(phone) # 123-456-7890
# Pop with default
email = person.pop("email", "No email") # Return default if key doesn't exist
print(email) # No email
# Clear dictionary
person.clear()
print(person) # {}Dictionary Iteration Patterns
# Different ways to iterate over dictionaries
scores = {"Alice": 85, "Bob": 92, "Charlie": 78, "Diana": 96}
# Iterate over keys
for name in scores:
print(f"{name}: {scores[name]}")
# Iterate over keys explicitly
for name in scores.keys():
print(f"{name}: {scores[name]}")
# Iterate over values
for score in scores.values():
print(f"Score: {score}")
# Iterate over key-value pairs
for name, score in scores.items():
print(f"{name}: {score}")
# Dictionary comprehension
squared_scores = {name: score**2 for name, score in scores.items()}
print(squared_scores) # {'Alice': 7225, 'Bob': 8464, 'Charlie': 6084, 'Diana': 9216}Advanced Dictionary Operations
# Nested dictionaries
students = {
"Alice": {"age": 20, "grade": "A", "subjects": ["Math", "Physics"]},
"Bob": {"age": 19, "grade": "B", "subjects": ["Chemistry", "Biology"]}
}
# Accessing nested values
print(students["Alice"]["age"]) # 20
print(students["Alice"]["subjects"][0]) # Math
# Adding to nested dictionary
students["Alice"]["subjects"].append("Computer Science")
# Dictionary from two lists
names = ["Alice", "Bob", "Charlie"]
ages = [20, 19, 21]
name_age_dict = dict(zip(names, ages))
print(name_age_dict) # {'Alice': 20, 'Bob': 19, 'Charlie': 21}
# Dictionary with default values
from collections import defaultdict
# Default dictionary
dd = defaultdict(list)
dd["fruits"].append("apple")
dd["fruits"].append("banana")
print(dd["fruits"]) # ['apple', 'banana']
print(dd["vegetables"]) # [] (empty list, not KeyError)
# Counter (from collections)
from collections import Counter
text = "hello world"
letter_count = Counter(text)
print(letter_count) # Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})String Methods & Manipulation
Essential String Methods
# String creation and basic info
text = " Hello World "
print(len(text)) # 15
print(text[0]) # ' ' (space)
# Case methods
print(text.upper()) # " HELLO WORLD "
print(text.lower()) # " hello world "
print(text.title()) # " Hello World "
print(text.capitalize()) # " hello world "
print(text.swapcase()) # " hELLO wORLD "
# Whitespace methods
print(text.strip()) # "Hello World"
print(text.lstrip()) # "Hello World "
print(text.rstrip()) # " Hello World"
# Search methods
text = "Hello World"
print(text.startswith("Hello")) # True
print(text.endswith("World")) # True
print(text.find("World")) # 6 (index of first occurrence)
print(text.find("Python")) # -1 (not found)
print(text.index("World")) # 6 (raises ValueError if not found)
print(text.count("l")) # 3 (count occurrences)String Splitting and Joining
# Splitting strings
sentence = "apple,banana,cherry,date"
fruits = sentence.split(",")
print(fruits) # ['apple', 'banana', 'cherry', 'date']
# Split with max splits
text = "one two three four five"
words = text.split(" ", 2) # Split into max 3 parts
print(words) # ['one', 'two', 'three four five']
# Split lines
multiline = "Line 1\nLine 2\nLine 3"
lines = multiline.splitlines()
print(lines) # ['Line 1', 'Line 2', 'Line 3']
# Joining strings
fruits = ["apple", "banana", "cherry"]
sentence = ", ".join(fruits)
print(sentence) # apple, banana, cherry
# Join with different separators
words = ["Hello", "World"]
print(" ".join(words)) # Hello World
print("-".join(words)) # Hello-World
print("".join(words)) # HelloWorldString Replacement and Formatting
# String replacement
text = "Hello World"
new_text = text.replace("World", "Python")
print(new_text) # Hello Python
# Replace with count limit
text = "apple apple apple"
new_text = text.replace("apple", "orange", 2)
print(new_text) # orange orange apple
# String formatting (multiple methods)
name = "John"
age = 25
# f-strings (Python 3.6+, preferred)
message = f"Hello, {name}! You are {age} years old."
print(message)
# .format() method
message = "Hello, {}! You are {} years old.".format(name, age)
print(message)
message = "Hello, {name}! You are {age} years old.".format(name=name, age=age)
print(message)
# % formatting (older style)
message = "Hello, %s! You are %d years old." % (name, age)
print(message)
# String alignment and padding
text = "Hello"
print(text.ljust(10)) # "Hello " (left align, pad to 10)
print(text.rjust(10)) # " Hello" (right align, pad to 10)
print(text.center(10)) # " Hello " (center align, pad to 10)
print(text.center(10, "*")) # "**Hello***" (center with custom padding)String Validation Methods
# String validation methods
text1 = "Hello123"
text2 = "123"
text3 = "Hello"
text4 = "hello"
text5 = "HELLO"
text6 = "Hello World"
text7 = " "
print(text1.isalnum()) # True (alphanumeric)
print(text2.isdigit()) # True (digits only)
print(text3.isalpha()) # True (letters only)
print(text4.islower()) # True (lowercase)
print(text5.isupper()) # True (uppercase)
print(text6.istitle()) # True (title case)
print(text7.isspace()) # True (whitespace only)Important Built-in Functions
Map, Filter, and Reduce
# Map function
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, numbers))
print(squared) # [1, 4, 9, 16, 25]
# Map with multiple iterables
list1 = [1, 2, 3]
list2 = [4, 5, 6]
sums = list(map(lambda x, y: x + y, list1, list2))
print(sums) # [5, 7, 9]
# Filter function
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # [2, 4, 6, 8, 10]
# Reduce function (from functools)
from functools import reduce
numbers = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x * y, numbers)
print(product) # 120
# Sum of numbers
total = reduce(lambda x, y: x + y, numbers)
print(total) # 15Enumerate and Zip
# Enumerate function
fruits = ["apple", "banana", "cherry"]
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")
# 0: apple
# 1: banana
# 2: cherry
# Enumerate with start value
for index, fruit in enumerate(fruits, 1):
print(f"{index}: {fruit}")
# 1: apple
# 2: banana
# 3: cherry
# Zip function
names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
cities = ["NYC", "LA", "Chicago"]
# Zip two lists
for name, age in zip(names, ages):
print(f"{name} is {age} years old")
# Zip multiple lists
for name, age, city in zip(names, ages, cities):
print(f"{name}, {age}, lives in {city}")
# Unzip (reverse of zip)
pairs = [("Alice", 25), ("Bob", 30), ("Charlie", 35)]
names, ages = zip(*pairs)
print(names) # ('Alice', 'Bob', 'Charlie')
print(ages) # (25, 30, 35)Other Important Built-in Functions
# Range function
print(list(range(5))) # [0, 1, 2, 3, 4]
print(list(range(1, 6))) # [1, 2, 3, 4, 5]
print(list(range(0, 10, 2))) # [0, 2, 4, 6, 8]
# Len function
print(len("Hello")) # 5
print(len([1, 2, 3, 4])) # 4
print(len({"a": 1, "b": 2})) # 2
# Min and Max
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
print(min(numbers)) # 1
print(max(numbers)) # 9
print(min("hello")) # 'e' (lexicographically smallest)
# Sum function
print(sum([1, 2, 3, 4, 5])) # 15
print(sum([1, 2, 3, 4, 5], 10)) # 25 (start with 10)
# Sorted function
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
print(sorted(numbers)) # [1, 1, 2, 3, 4, 5, 6, 9]
print(sorted(numbers, reverse=True)) # [9, 6, 5, 4, 3, 2, 1, 1]
# Any and All
numbers = [1, 2, 3, 4, 5]
print(any(x > 3 for x in numbers)) # True (at least one > 3)
print(all(x > 3 for x in numbers)) # False (not all > 3)
# Reversed function
numbers = [1, 2, 3, 4, 5]
reversed_numbers = list(reversed(numbers))
print(reversed_numbers) # [5, 4, 3, 2, 1]Data Structure Comparison
When to Use Each Data Structure
| Data Structure | Mutable | Ordered | Duplicates | Use Cases |
|---|---|---|---|---|
| List | ✅ | ✅ | ✅ | Dynamic collections, stacks, queues |
| Tuple | ❌ | ✅ | ✅ | Fixed data, coordinates, function returns |
| Set | ✅ | ❌ | ❌ | Unique elements, membership testing |
| Dictionary | ✅ | ✅ (Python 3.7+) | ❌ (keys) | Key-value pairs, lookup tables |
Performance Comparison
import time
# List vs Set for membership testing
large_list = list(range(1000000))
large_set = set(range(1000000))
# Test membership in list (O(n))
start = time.time()
999999 in large_list
list_time = time.time() - start
# Test membership in set (O(1))
start = time.time()
999999 in large_set
set_time = time.time() - start
print(f"List lookup time: {list_time:.6f}s")
print(f"Set lookup time: {set_time:.6f}s")
# Set is significantly faster for membership testingCommon Interview Questions
1. What’s the difference between a list and a tuple?
Answer:
- Lists are mutable, tuples are immutable
- Lists use
[], tuples use() - Lists have more methods (append, remove, etc.)
- Tuples are faster and use less memory
- Tuples can be used as dictionary keys, lists cannot
2. How do you remove duplicates from a list?
Answer:
# Method 1: Using set (loses order)
original = [1, 2, 2, 3, 4, 4, 5]
unique = list(set(original))
print(unique) # [1, 2, 3, 4, 5] (order may vary)
# Method 2: Preserving order
unique_ordered = []
for item in original:
if item not in unique_ordered:
unique_ordered.append(item)
print(unique_ordered) # [1, 2, 3, 4, 5] (preserves order)
# Method 3: Using dict.fromkeys() (Python 3.7+)
unique_ordered = list(dict.fromkeys(original))
print(unique_ordered) # [1, 2, 3, 4, 5] (preserves order)3. How do you merge two dictionaries?
Answer:
# Method 1: Using update() (modifies first dict)
dict1 = {"a": 1, "b": 2}
dict2 = {"c": 3, "d": 4}
dict1.update(dict2)
print(dict1) # {'a': 1, 'b': 2, 'c': 3, 'd': 4}
# Method 2: Using ** unpacking (Python 3.5+)
dict1 = {"a": 1, "b": 2}
dict2 = {"c": 3, "d": 4}
merged = {**dict1, **dict2}
print(merged) # {'a': 1, 'b': 2, 'c': 3, 'd': 4}
# Method 3: Using | operator (Python 3.9+)
dict1 = {"a": 1, "b": 2}
dict2 = {"c": 3, "d": 4}
merged = dict1 | dict2
print(merged) # {'a': 1, 'b': 2, 'c': 3, 'd': 4}4. What’s the difference between append() and extend()?
Answer:
append()adds a single element to the endextend()adds all elements from an iterable to the end
list1 = [1, 2, 3]
list2 = [1, 2, 3]
list1.append([4, 5]) # [1, 2, 3, [4, 5]]
list2.extend([4, 5]) # [1, 2, 3, 4, 5]5. How do you sort a dictionary by value?
Answer:
scores = {"Alice": 85, "Bob": 92, "Charlie": 78, "Diana": 96}
# Method 1: Using sorted() with key parameter
sorted_scores = dict(sorted(scores.items(), key=lambda x: x[1]))
print(sorted_scores) # {'Charlie': 78, 'Alice': 85, 'Bob': 92, 'Diana': 96}
# Method 2: Using sorted() with operator.itemgetter
from operator import itemgetter
sorted_scores = dict(sorted(scores.items(), key=itemgetter(1)))
print(sorted_scores) # {'Charlie': 78, 'Alice': 85, 'Bob': 92, 'Diana': 96}
# Method 3: Sort in descending order
sorted_scores = dict(sorted(scores.items(), key=lambda x: x[1], reverse=True))
print(sorted_scores) # {'Diana': 96, 'Bob': 92, 'Alice': 85, 'Charlie': 78}Practice Problems
Easy Level
- Count Frequency of Characters
def count_characters(text):
char_count = {}
for char in text:
char_count[char] = char_count.get(char, 0) + 1
return char_count
# Test
text = "hello world"
result = count_characters(text)
print(result) # {'h': 1, 'e': 1, 'l': 3, 'o': 2, ' ': 1, 'w': 1, 'r': 1, 'd': 1}- Find Common Elements in Two Lists
def find_common(list1, list2):
set1 = set(list1)
set2 = set(list2)
return list(set1.intersection(set2))
# Test
list1 = [1, 2, 3, 4, 5]
list2 = [4, 5, 6, 7, 8]
common = find_common(list1, list2)
print(common) # [4, 5]- Group Anagrams
def group_anagrams(words):
groups = {}
for word in words:
# Sort characters to create key
key = ''.join(sorted(word))
if key not in groups:
groups[key] = []
groups[key].append(word)
return list(groups.values())
# Test
words = ["eat", "tea", "tan", "ate", "nat", "bat"]
result = group_anagrams(words)
print(result) # [['eat', 'tea', 'ate'], ['tan', 'nat'], ['bat']]Medium Level
- Two Sum Problem
def two_sum(nums, target):
num_map = {}
for i, num in enumerate(nums):
complement = target - num
if complement in num_map:
return [num_map[complement], i]
num_map[num] = i
return []
# Test
nums = [2, 7, 11, 15]
target = 9
result = two_sum(nums, target)
print(result) # [0, 1] (indices of 2 and 7)- Valid Parentheses
def is_valid_parentheses(s):
stack = []
mapping = {')': '(', '}': '{', ']': '['}
for char in s:
if char in mapping:
if not stack or stack.pop() != mapping[char]:
return False
else:
stack.append(char)
return not stack
# Test
print(is_valid_parentheses("()[]{}")) # True
print(is_valid_parentheses("([)]")) # False- Merge Two Sorted Lists
def merge_sorted_lists(list1, list2):
merged = []
i = j = 0
while i < len(list1) and j < len(list2):
if list1[i] <= list2[j]:
merged.append(list1[i])
i += 1
else:
merged.append(list2[j])
j += 1
# Add remaining elements
merged.extend(list1[i:])
merged.extend(list2[j:])
return merged
# Test
list1 = [1, 3, 5, 7]
list2 = [2, 4, 6, 8]
result = merge_sorted_lists(list1, list2)
print(result) # [1, 2, 3, 4, 5, 6, 7, 8]Advanced Level
- Implement a Stack using Lists
class Stack:
def __init__(self):
self.items = []
def push(self, item):
self.items.append(item)
def pop(self):
if self.is_empty():
raise IndexError("Stack is empty")
return self.items.pop()
def peek(self):
if self.is_empty():
raise IndexError("Stack is empty")
return self.items[-1]
def is_empty(self):
return len(self.items) == 0
def size(self):
return len(self.items)
# Test
stack = Stack()
stack.push(1)
stack.push(2)
stack.push(3)
print(stack.pop()) # 3
print(stack.peek()) # 2
print(stack.size()) # 2- Find First Non-Repeating Character
def first_non_repeating_char(s):
char_count = {}
# Count frequency
for char in s:
char_count[char] = char_count.get(char, 0) + 1
# Find first non-repeating
for char in s:
if char_count[char] == 1:
return char
return None
# Test
print(first_non_repeating_char("leetcode")) # 'l'
print(first_non_repeating_char("loveleetcode")) # 'v'Key Takeaways for Interviews
-
Know when to use each data structure - Lists for ordered, mutable data; tuples for fixed data; sets for unique elements; dicts for key-value pairs
-
Understand time complexity - Set/dict lookups are O(1), list lookups are O(n)
-
Master slicing and indexing - Very common in interviews
-
Practice with built-in functions - map, filter, reduce, enumerate, zip are frequently used
-
Know string methods - String manipulation is common in interviews
-
Understand immutability - Know what can and cannot be modified
Next Steps
After mastering these data structures and built-ins, move on to:
- Chapter 3: Intermediate Python (List comprehensions, Lambda functions, File handling, Exception handling)
- Chapter 4: Object-Oriented Programming
- Chapter 5: Important Libraries
- Chapter 6: Problem-Solving (DSA)
Remember: Practice implementing these data structures from scratch and solving problems using them!