0% found this document useful (0 votes)
21 views

Arrays - Lists and Matrices

Here are 3 approaches to swap two elements in a list: 1. Use a temporary variable: - Store one element in a temporary variable - Overwrite one element with the other - Overwrite the other element with the temporary variable 2. Slice assignment: - Assign a slice of the list with the elements in reversed order - Example: list[i], list[j] = list[j], list[i] 3. XOR swap: - Use XOR (exclusive or) to swap elements without a temporary variable - Example: list[i] ^= list[j]; list[j] ^= list[i]; list[i] ^= list[j]

Uploaded by

ahagy9934
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views

Arrays - Lists and Matrices

Here are 3 approaches to swap two elements in a list: 1. Use a temporary variable: - Store one element in a temporary variable - Overwrite one element with the other - Overwrite the other element with the temporary variable 2. Slice assignment: - Assign a slice of the list with the elements in reversed order - Example: list[i], list[j] = list[j], list[i] 3. XOR swap: - Use XOR (exclusive or) to swap elements without a temporary variable - Example: list[i] ^= list[j]; list[j] ^= list[i]; list[i] ^= list[j]

Uploaded by

ahagy9934
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 86

Array/Lists

And
Matrices
Pre-requisites
● Basic Python Knowledge
● Time and Space Complexity
● Willingness to learn
What are Data Structures?
Data Structures
● Particular way of organizing, and storing the data
● Tools to build efficient algorithms
● The right one depends on the task
● Common Data Structures:

○ Arrays ○ Trees
○ Linked Lists ○ Maps(dictionaries)
○ Stacks ○ Sets
○ Queues ○ Tries, etc…
Arrays
Arrays
● Collection of items stored at contiguous memory locations.
● Storing multiple items of the same type together.
● Easier to calculate the position of each element by simply adding an
offset to a base value.

Array members x[0] x[1] x[2] x[3] x[4] x[5]

19 10 8 17 9 15
Array indices 0 1 2 3 4 5
Static Arrays
Static Arrays

● A type of array in which the size or length is determined when the array is
created and/or allocated.

7 3 6
*0 *4 *8
Static Arrays
Value 1 3 5
1 3 5
Address *0 *4 *8

Value a b c
a b c
Address *0 *1 *2
Static Arrays - Reading
● Reading is Very fast : O(1)
● Why?

print(my_array[4])
Static Arrays - Reading
First Index 4th element

0 1 2 3 4 5 6 7 8 9

Array Length is 10

Each integer occupies 4 bytes, so let us say the 0th index is


at memory location 1400

1400 + (3 * 4) = 1412
Static Arrays - Writing
● Writing is an instant operation
5

1 3 Value 1 3 0
Address *0 *4 *8

5
Static Arrays - Writing
4
● Overwriting is an instant operation

1 3 5 Value 1 3 5
Address *0 *4 *8
4
Static Arrays - Writing
● What happens when we want to add an element to our
array but don’t have any empty spots?

1 3 5 Value 1 3 5
Address *0 *4 *8
7
Static Arrays - Writing
● The operating system might be using this part of the
memory for some other purpose.
● So we are not necessarily allowed to put our seven there.

1 3 5 Value 1 3 5
Address *0 *4 *8
7
Static Arrays - Summary
Operation Big-O Time

Read i-th Element O(1)

Write i-th Element O(1)


Dynamic Arrays
Dynamic Arrays
● A Dynamic array has the ability to resize itself
automatically when an element is inserted or deleted.

● Double the size when it reaches capacity, cut by half


when it’s down to quarter
Does Python list allow the storage
of different types ?
Dynamic Arrays
● No way to find out arr[3] without traversing the full list

arr = [3, 0.5, ‘a’, “1”]

Value 3 0.5 a “1”


Address *0 *4 *12 *13
Dynamic Arrays
● A list in Python is implemented as an array of references.

● That is that you are actually creating an array of


references like so:

0 1 2 3
[0xa3d25342, 0x635423fa, 0xff243546, 0x2545fade]
Dynamic Arrays
● Each element is a reference that "points" to the
respective objects in memory

*0 *1 *2 *3

Reference *10 *14 *22 *23

Value 3 0.5 a “1”


Dynamic Arrays
● This works because the all references are of the same
size unlike the actual values they point to.

*0 *1 *2 *3

Reference *10 *14 *22 *23

Value 3 0.5 a “1”


Common Terminologies
● Pushing/Appending : inserting an element at the next
empty spot

● Popping: removing the element from the end of the list


Pushing
● Whenever we reach our array’s capacity, our interpreter
allocates another memory which is double our original
capacity and copies over all the old elements with now more
space.

● Isn’t this operation costly?


Pushing
● It takes amortized O(1) time! Let’s see why
Pushing
● Our goal is to push 8 elements to a dynamic array.
● Assumption: Our initial capacity is of size one.

5 6 7 8 9 1 2 3
Pushing
● After pushing 5, no place for 6

5 6 7 8 9 1 2 3

5
Operation count: 1
Pushing
● Copy the original array ([5]) to the new allocated memory which
is double the old size and push 6 onto it

6 7 8 9 1 2 3

5 6
Operation count: 1 + 2
Pushing
● Allocate a new array of size 4 and copy over all the old elements
and then we append 7

7 8 9 1 2 3

5 6 7
Operation count: 1 + 2 + 3
Pushing
● Push 8 onto the array. Now we have run out of space for the next
elements.

8 9 1 2 3

5 6 7 8
Operation count: 1 + 2 + 4
Pushing
● Allocate a new array of size 8 and copy over all the old elements
and then we append the element 9

9 1 2 3

5 6 7 8 9
Operation count: 1 + 2 + 4 + 5
Pushing
● Push/append 1 into the array

1 2 3

5 6 7 8 9 1
Operation count: 1 + 2 + 4 + 6
Pushing
● Push/append 2 into the array

2 3

5 6 7 8 9 1 2
Operation count: 1 + 2 + 4 + 7
Pushing
● Push/append 3 into the array

5 6 7 8 9 1 2 3
Operation count: 1 + 2 + 4 + 8
Pushing- Power Series
● For a length of 8, it took us 1 + 2 + 4 + 8 operations.
● The last summand always dominates the sum.

= +

= + +

≥ + + +
Pushing - Power Series
● For a length of 8, it took us 1 + 2 + 4 + 8 operations.
● The last summand always dominates the sum.
2≥1
4≥1+2
8≥1+2+4
.
.
.
2*N ≥ 1 + 2 + 4 + 8 + … + N
● Thus to push N elements, it will take us no more than 2N operations,
making the time complexity O(N).
Pushing - Power Series

● This means, to push a single element onto an array, on average, we


say it is an instant - O(1) - operation.
● Because after a while, the copying operation becomes very
infrequent.

● Hence, pushing an element onto an array is Amortized O(1) operation.


Dynamic Arrays - Insertion
● Inserting an element in an arbitrary position is, in the worst case,
an O(n) operation.

1 3 7
Value 1 3 7

5 Address *0 *4 *8 *12
Dynamic Arrays - Insertion
● We need to shift all elements to the right of the new element, to
not lose data, and create the empty space needed.

1 3 7
Value 1 3 7

5 Address *0 *4 *8 *12
Dynamic Arrays - Insertion
● The shifting is what costs us time.

Value 5 1 3 7
5 1 3 7
Address *0 *4 *8 *12
Dynamic Arrays - Removal
● What about removing an element?

Value 5 1 3 7
5 1 3 7
Address *0 *4 *8 *12
Dynamic Arrays - Removal
● It is O(n) at worst.

Value 1 3 7
1 3 7
Address *0 *4 *8
Checkpoint
Traversing Lists
Traversing Lists - Reverse Traversal
Approach Implementation
● Start from the last index for index in range(len(array)-1, -1, -1):
print(array[index])
● Decrement by 1 until -1
Traversing Lists - Even/Odd Indices Traversal

Approach Implementation
● Start from the first step = 2 # incremental value
even/odd index # even indices traversal
● Increment by 2 size = len(array)
for index in range(0, size, step):
print(array[index])
Traversing Lists - Circular Traversal
Approach Implementation
● Start from first index to size = len(array)
size*2 for index in range(0, 2 * size):
● Incrementally go 1 step value = array[index % size]
but modulo index by size print(value)
Pair Programming
Find the winner of the circular
game
Swapping Elements
Swapping Elements
Approach Implementation
● Approach 1
# approach 1
● Store first element in a
variable temp = arr[i]
arr[i] = arr[j]
● Change first element
with second element arr[j] = temp

● Change second element


with stored value # approach 2
arr[i], arr[j] = arr[j], arr[i]
● Approach 2 : Use tuple
unpacking to swap
Pair Programming
Reverse string
Storing letter and Numbers
Storing - Using Arrays as Dictionaries
● For Letters
○ Character’s ASCII value can be the index by correcting the
offset by 65 (‘A’) for uppercase letters and 97 (‘a’) for lower
case letters
● For Numbers
○ The number itself is the key
● Note: the advantage of this approach is that you can use built in
functions like sum, sort, max, min on the frequency list whereas
maps don’t give you this flexibilities.
Storing - Implementation
word = "abceabce"
arrayDictionary = [0]*26
offset = ord('a') # 'a' has ASCII value of 97
for char in word:
ascii = ord(char)
arrayDictionary[ascii - offset] += 1

print(arrayDictionary)
# [2, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# a b c d e f g h i j k l m n, o p q r s t u v w x y z
Read and Write Indices
Read and Write and Indices
Approach Implementation
(Question Link)
● Set your read index def moveZeroes(self, nums: List[int])
accordingly to your need write = 0
read = 0
● Set your write index
accordingly to your need while read < len(nums):
if nums[read] != 0:
● Your read should always temp = nums[read]
move nums[read] = nums[write]
nums[write] = temp
● Your write only moves after
write operation
write = write + 1

read = read + 1
Pair Programming
Apply operations to an array
Matrices
Matrices
● Two-dimensional arrays can be defined as arrays within an array.
● 2D arrays erected as matrices, which is a collection of rows and columns.
columns

rows
Matrices
● You should think two dimensional arrays as matrices.
● In reality, they are arrays holding references to other arrays

*0 *1
1 2 3

4 5 6
1 2 3 4 5 6
Common Approaches
Traversing Matrices
Traversing - from Top-left to Bottom-right
Approach Implementation
● Start from (0, 0) for row_idx in range(len(matrix)):
for col_idx in range(len(matrix[0])):
● Increment column index by
one for each row you visit print(matrix[row_idx][col_idx])
Traversing - From Bottom-right to Top-left
Approach Implementation
● Start from (last_row - 1,
last_col - 1) for row_idx in range(len(matrix) - 1, -1, -1):
for col_idx in range(len(matrix[0]) - 1, -1, -1):
● Decrement column index by print(matrix[row_idx][col_idx])
one for each row you visit.
Enumerating Cells/ 2D - 1D
Mapping
Enumerating Cells - Approach

0 1 2 3

0 0 1 2 3

1 4 5 6 7

2 8 9 10 11
Enumerating Cells - Approach
Consecutive elements in a column differ by the number of columns

0 1 2 3

0 0 1 2 3

1 4 5 6 7

2 8 9 10 11
Enumerating Cells - Approach
Consecutive elements in a row differ by 1

0 1 2 3

0 0 1 2 3

1 4 5 6 7

2 8 9 10 11
Enumerating Cells - Approach
Therefore the 1D number of a cell is row_number*n_columns + column_number

0 1 2 3

0 0 1 2 3

1 4 5 6 7

2 8 9 10 11
Enumerating Cells - Remainder Theorem

cell_number = row_number*n_columns + column_number

row_number = cell_number // n_columns

column_number = cell_number % n_columns


Diagonal Keys
Diagonal Keys
What is common about the highlighted column and row numbers?

0 1 2 3

0 0 1 2 3

1 4 5 6 7

2 8 9 10 11
Diagonal Keys
What is common about the highlighted column and row numbers?

0 1 2 3

0 0 1 2 3

1 4 5 6 7

2 8 9 10 11
Common Pitfalls
Common Pitfalls - Index Out of Bound
● Trying to access elements using indices that are greater (or equal to)
than the size of our array will result in this exception.
Common Pitfalls - Negative Indexing
● Because we may use negative indices in Python, it is a typical
problem to use negative indices accidently, which can result in a
highly troublesome misunderstanding if no exception is triggered.

Negative indices: -4 -3 -2 -1
Positive indices: 0 1 2 3
Values: [1, 2, 3, 4]
Common Pitfalls - Copying lists
● A list is a reference. Take care when you want to you want to pass
only the content of the list.

nums[::]
nums.copy()
Common Pitfalls - Initializing with *
● The * operator can be used as [object]*n where n is the number
of elements in the array.
● In the case of 2D arrays, this will result in shallow lists
● Hence using list comprehensions is a safer way to create 2D lists.

row = len(matrix)
col = len(matrix[0])

transposed = [[0]*rows for _ in range(cols)]


Common Pitfalls - Using insert , pop and in
● insert - inserts a given element at a given index
○ insert(i, value) : O(N)
● pop - returns the value at a given index and removes it from the
list where the default is the last index
○ pop : O(1)
○ pop(i) : O(n)

● The in operator is returns a boolean denoting whether an element


is present in the iterable data structure we use it on.
● Lists O(N)
● Map, Set O(1)T
Common Pitfalls - Mistaking Row Iterators with
Column iterators
● It is pretty common to mistake your i and j’s representing rows
and columns. And sometimes, especially when the matrix is a
square one, it does not throw an exception but hours of confusion

for col_idx in range(len(matrix[0])):


for row_idx in range(len(matrix)):
print(matrix[col_idx][row_idx])
Checkpoint
Practice Question
Image smoother
Practice Questions
Reverse string
Count Equal and Divisible Pairs in an..
All Divisions With the Highest Score..
Transpose matrix
Diagonal traverse
Rotate image
Resources
● https://neetcode.io/courses/dsa-for-beginners/0: useful on laying out the
fundamentals
● https://www.geeksforgeeks.org/python-arrays/: covers large range of topics
for python
● Python List pop() Method - GeeksforGeeks: good examples
● Python List insert() Method With Examples - GeeksforGeeks: good
examples
● Python | Which is faster to initialize lists? - GeeksforGeeks: good article on
list initialization
Quote of the Day

If you want to enjoy the rainbow,


be prepared to endure the storm

Warren W. Wiersbe

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy