Longest+Increasing+Subsequence
Longest+Increasing+Subsequence
increasing
subsequenc
e
|𝑎𝑟𝑟|≥ 1
Given an array arr,
find the length of the
longest subsequence
where elements are
strictly increasing
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7]
output: 5
explanation: A possible longest
increasing subsequence is [2, 3, 5 4, 5,
12]
1
7 5 2 4 7 2 3 6 4 5 1 7
2
Subset
sum
subsets(k, i)
subsets
(k-arr[i], i+1)
subsets(k, i+1)
def subsets(arr, k, i=0):
if k == 0:
return 1
elif i == len(arr) or k < 0:
return 0
else:
return subsets(arr, k-arr[i], i+1)
+ subsets(arr, k, i+1)
9
8
7
6
5
4
3
2
1
0
9
8
7
6
5
4
3
2
1
0
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1, i prev
7]
lis(0, )
lis(1, 7) lis(1, )
𝑜𝑡h𝑒𝑟𝑤𝑖𝑠𝑒
def lis(arr, i=0, prev=float("-inf")):
if i == len(arr):
return 0
elif arr[i] <= prev:
return lis(arr, i+1, prev)
else:
return max(1+lis(arr, i+1, arr[i]),
lis(arr, i+1, prev))
0 𝑖𝑓 𝑖=¿ 𝑎𝑟𝑟 ∨¿
𝑜𝑡h𝑒𝑟𝑤𝑖𝑠𝑒
def lis(arr, i=0, prev=float("-inf")):
if i == len(arr):
return 0
elif arr[i] <= prev:
return lis(arr, i+1, prev)
else:
return max(1+lis(arr, i+1, arr[i]),
lis(arr, i+1, prev))
0 𝑖𝑓 𝑖=¿ 𝑎𝑟𝑟 ∨¿
𝑜𝑡h𝑒𝑟𝑤𝑖𝑠𝑒
def lis(arr, i=0, prev=float("-inf")):
if i == len(arr):
return 0
elif arr[i] <= prev:
return lis(arr, i+1, prev)
else:
return max(1+lis(arr, i+1, arr[i]),
lis(arr, i+1, prev))
𝑛
𝑇 ( 𝑛 )=𝑂 (2 )
lis(n,prev)
.
.
.
lis(1,prev)
lis(0,prev)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
rec(0)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
rec(0)
rec(10)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
rec(0)
1
rec(10)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
2
rec(0)
1
rec(10)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
2
rec(0) rec(1)
1
rec(10)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
2
rec(0) rec(1)
1
rec(10) rec(4)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
2
rec(0) rec(1)
1
rec(10) rec(4)
rec(10)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
2
rec(0) rec(1)
1
rec(10) rec(4)
1
rec(10)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
2
rec(0) rec(1)
1 2
rec(10) rec(4)
1
rec(10)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
2
rec(0) rec(1)
1 2
rec(10) rec(4) rec(7)
1
rec(10)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
2
rec(0) rec(1)
1 2
rec(10) rec(4) rec(7)
1
rec(10) rec(10)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
2
rec(0) rec(1)
1 2
rec(10) rec(4) rec(7)
1 1
rec(10) rec(10)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
2
rec(0) rec(1)
1 2
rec(10) rec(4) rec(7)
1 1
rec(10) rec(10) rec(12)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
2
rec(0) rec(1)
1 2
rec(10) rec(4) rec(7)
1 1 1
rec(10) rec(10) rec(12)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
2
rec(0) rec(1)
1 2 2
rec(10) rec(4) rec(7)
1 1 1
rec(10) rec(10) rec(12)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
2
rec(0) rec(1)
1 2 2
rec(10) rec(4) rec(7) rec(10)
1 1 1
rec(10) rec(10) rec(12)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
2
rec(0) rec(1)
1 2 2 1
rec(10) rec(4) rec(7) rec(10)
1 1 1
rec(10) rec(10) rec(12)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
2
rec(0) rec(1)
1 2 2 1
rec(10) rec(4) rec(7) rec(10) rec(12)
1 1 1
rec(10) rec(10) rec(12)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
2
rec(0) rec(1)
1 2 2 1 1
rec(10) rec(4) rec(7) rec(10) rec(12)
1 1 1
rec(10) rec(10) rec(12)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
2 3
rec(0) rec(1)
1 2 2 1 1
rec(10) rec(4) rec(7) rec(10) rec(12)
1 1 1
rec(10) rec(10) rec(12)
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, lis(arr)
12, 1,0 7]1 2 3 4 5 6 7 8 9 10 11 12
... ...
rec(0) rec(1)
𝑇(𝑛)=2(2𝑇(𝑛−2)+𝑂(1) +𝑂(1)
𝑛
𝑇 ( 𝑛 )=𝑂 (2 )
rec()
: lis()
𝑛
𝑇 ( 𝑛 )=𝑂 (2 )
rec()
: lis()
𝑛
𝑇 ( 𝑛 )=𝑂 (2 )
𝑛− 1
𝑇 2 ( 𝑛 )=∑ 2 𝑛−𝑘
𝑘=0
rec()
: lis()
𝑛
𝑇 ( 𝑛 )=𝑂 (2 )
𝑛− 1
𝑇 2 ( 𝑛 )=∑ 2 𝑛−𝑘
𝑘=0
𝑇 2 𝑛 =2 ∗ 2 − 2= 𝑂 2 )
( ) 𝑛
( 𝑛
rec()
: lis()
lis(n)
.
.
.
lis(1)
lis(0)
First solution:
def lis(arr, i=0, prev=float("-inf")):
if i == len(arr):
return 0
elif arr[i] <= prev:
return lis(arr, i+1, prev)
else:
return max(1+lis(arr, i+1, arr[i]),
lis(arr, i+1, prev))
Second solution:
def lis(arr):
def rec(arr, i):
maxlen = 0
for j in range(i+1, len(arr)):
if arr[j] > arr[i]:
maxlen = max(maxlen, rec(arr, j))
return 1+maxlen
return max([rec(arr, i) for i in range(len(arr))])
Second solution:
def lis(arr):
def rec(arr, i):
maxlen = 0
for j in range(i+1, len(arr)):
if arr[j] > arr[i]:
maxlen = max(maxlen, rec(arr, j))
return 1+maxlen
return max([rec(arr, i) for i in range(len(arr))])
rec
(0)
rec
(1)
rec
(2)
rec
(3)
rec
(4)
rec
(5)
rec
(6)
rec
(7)
rec
(8)
rec
(9)
rec
(10)
rec
(11)
rec
(12)
rec
(0)
rec
(1)
rec
(2)
rec
(3)
rec
(4)
rec
(5)
rec
(6)
rec
(7)
rec
(8)
rec
(9)
rec
(10)
rec
(11)
rec
(12)
def lis(arr): 1
def rec(arr, i, lookup=None):
if i in lookup:
3 return lookup[i]
max_len = 0
for j in range(i+1, len(arr)):
if arr[j] > arr[i]:
max_len = max(max_len, rec(arr, j, lookup))
lookup[i] = 1+max_len
4
return lookup[i]
lookup
2 = {}
return max([rec(arr, i, lookup) for i in range(len(arr))])
def lis(arr):
def rec(arr, i, lookup=None):
if i in lookup:
𝑖 ∈{0 , 1 , … ,𝑛 − 1}
return lookup[i]
max_len = 0
𝑛
for j − 𝑖 − 1len(arr)):
in range(i+1, 𝑛
if arr[j] > arr[i]:
max_len = max(max_len, rec(arr, j, lookup))
lookup[i] = 1+max_len
return lookup[i]
lookup = {}
return max([rec(arr, i, lookup) for i in range(len(arr))])
def lis(arr):
def rec(arr, i, lookup=None):
if i in lookup:
𝑖 ∈{0 , 1 , … ,𝑛 − 1}
return lookup[i]
max_len = 0
𝑛
for j − 𝑖 − 1len(arr)):
in range(i+1, 𝑛
if arr[j] > arr[i]:
max_len = max(max_len, rec(arr, j, lookup))
lookup[i] = 1+max_len
return lookup[i]
lookup = {}
return max([rec(arr, i, lookup) for i in range(len(arr))])
𝑇 (𝑛 )=(𝑛−1)+(𝑛 −2)+…+1
𝑆 ( 𝑛 )=𝑂 ( 𝑛 ) +𝑂 (𝑛)=𝑂 (𝑛)
call stack lookup
size table
size
𝑖 ∈{0 , 1 , … ,𝑛 − 1}
𝑛
dp
𝑛
dp
dp[n-1] represents
the length of the
LIS that ends at
the element at
index n-1
dp
dp[i] represents
the length of the
LIS that ends at
the element at
index i
dp
1
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2
4
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2
4
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2 3
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2 2
4 4
7
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2 3
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2 2
4 4
7
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2 3 1
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2 2 2
4 4
7
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2 3 1
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2 2 2
4 4
7
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2 3 1 2
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2 2 2 2
4 4 3
7
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2 3 1 2
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2 2 2 2
4 4 3
7
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2 3 1 2 3
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2 2 2 2 2
4 4 3 4
7 6
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2 3 1 2 3
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2 2 2 2 2
4 4 3 4
7 6
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2 3 1 2 3 3
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2 2 2 2 2 2
4 4 3 4 3
7 6 4
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2 3 1 2 3 3
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2 2 2 2 2 2
4 4 3 4 3
7 6 4
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2 3 1 2 3 3 4
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2 2 2 2 2 2 2
4 4 3 4 3 3
7 6 4 4
5
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2 3 1 2 3 3 4
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2 2 2 2 2 2 2
4 4 3 4 3 3
7 6 4 4
5
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2 3 1 2 3 3 4 5
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2 2 2 2 2 2 2 2
4 4 3 4 3 3 3
7 6 4 4 4
5 5
12
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2 3 1 2 3 3 4 5
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2 2 2 2 2 2 2 2
4 4 3 4 3 3 3
7 6 4 4 4
5 5
12
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2 3 1 2 3 3 4 5 1
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2 2 2 2 2 2 2 2 1
4 4 3 4 3 3 3
7 6 4 4 4
5 5
12
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2 3 1 2 3 3 4 5 1
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2 2 2 2 2 2 2 2 1
4 4 3 4 3 3 3
7 6 4 4 4
5 5
12
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2 3 1 2 3 3 4 5 1 5
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2 2 2 2 2 2 2 2 1 2
4 4 3 4 3 3 3 3
7 6 4 4 4 4
5 5 5
12 7
input:
arr = [7, 5, 2, 4, 7, 2, 3, 6, 4, 5, 12, 1,
7] 0 1 2 3 4 5 6 7 8 9 10 11 12
dp
1 1 1 2 3 1 2 3 3 4 5 1 5
0 1 2 3 4 5 6 7 8 9 10 11 12
LIS that
ends at
index i:
7 5 2 2 2 2 2 2 2 2 2 1 2
4 4 3 4 3 3 3 3
7 6 4 4 4 4
5 5 5
12 7
def lis(arr):
n = len(arr)
dp = [0]*n
dp[0] = 1
for i in range(1, n):
maxlen = 0
for j in range(i):
if arr[j] < arr[i] and dp[j] > maxlen:
maxlen = dp[j]
dp[i] = 1+maxlen
return max(dp)
rec
(0) rec
(1) rec
(2) rec
(3) rec
(4) rec
(5) rec
(6) rec
(7) rec
(8) rec
(9) rec
(10) rec
(11)
rec
(12)
rec
(0) rec
(1) rec
(2) rec
(3) rec
(4) rec
(5) rec
(6) rec
(7) rec
(8) rec
(9) rec
(10) rec
(11)
rec
(12)
dp
1 1 1 2 3 1 2 3 3 4
0 1 2 3 4 5 6 7 8 9 10 11 12
rec(i)
rec(i+1
)
rec(i+2
)
rec(i)
rec(i+3
)
rec(i+4
)
rec(i+1
)
rec(i+2
)
rec(i) dp[i]
rec(i+3
)
rec(i+4
)
rec(i+1
dp[i-1]
)
rec(i+2
dp[i-2]
)
rec(i) dp[i]
rec(i+3
dp[i-3]
)
rec(i+4
dp[i-4]
)
def lis(arr):
n = len(arr)
dp = [0]*n
dp[0] = 1
𝑛 − 1
for i in range(1, n):
maxlen = 0
𝑖
for j in range(i):
𝑂 (1 )
if arr[j] < arr[i] and dp[j] > maxlen:
maxlen = dp[j]
dp[i] = 1+maxlen
return max(dp)
def lis(arr):
n = len(arr)
dp = [0]*n
dp[0] = 1
𝑛 − 1
for i in range(1, n):
maxlen = 0
𝑖
for j in range(i):
𝑂 (1 )
if arr[j] < arr[i] and dp[j] > maxlen:
maxlen = dp[j]
dp[i] = 1+maxlen
return max(dp)
𝑛 ( 𝑛−1 )
𝑇 ( 𝑛 )=1+2+3+…+( 𝑛−1 )=
2
def lis(arr):
n = len(arr)
dp𝑛= [0]*n
dp[0] = 1
for i in range(1, n):
maxlen = 0
for j in range(i):
if arr[j] < arr[i] and dp[j] > maxlen:
maxlen = dp[j]
dp[i] = 1+maxlen
return max(dp)
𝑆 ( 𝑛 )=𝑛=𝑂 (𝑛)
Longest
increasing
subsequenc
e