Skip to content

Commit b665542

Browse files
Chris WuChris Wu
Chris Wu
authored and
Chris Wu
committed
no message
1 parent 585debd commit b665542

6 files changed

+278
-18
lines changed

lru-cache.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
"""
2+
I learned this answer from @tusizi; rewrote it.
3+
4+
Let's analyze the problem
5+
If we need get() to be O(1),
6+
we must definitely use a hashmap(dictionary) to store the key value.
7+
8+
put() is not a problem, since we are only setting value.
9+
The problem is when we excceed the capacity.
10+
How do we find the least-used key and remove it from the hashmap?
11+
We need something for us to sort from most-frequent-used to least-used.
12+
13+
So what else common data structure do we know?
14+
Array? no, we will need to iterate to the whole array to find what we need. and it is not easy to add or remove.
15+
Tree? not likely.
16+
Min-heap? even though we can get the least-used, but it need O(LogN) to set the most-frequent-used.
17+
Link list? Bingo!
18+
19+
We also need it to be a double link list, so we can remove the tail.
20+
We also need the node to store the key when we remove the tail, we can also remove it in the hashmap
21+
We also need the node to store the val when we get().
22+
23+
It would be like:
24+
head<->node1<->node2<->node3 ... nodeN<->tail
25+
(most-frequent-used to least-used)
26+
27+
So the main idea now is to use hashmap to store the key:Node pair [0]
28+
If we put or get any key-value pair, we move its node to the front of the line (I call this promote()) [1]
29+
The front of the line means we put it just after head.
30+
If we excced the capacity, we remove the node at the end of the line [2]
31+
The end of the line means the node just before tail.
32+
33+
The head and tail is just a dummy, [3]
34+
for us to keep track of the first and the last of the linklist
35+
and don't have worry about the edge case.
36+
"""
37+
class Node(object):
38+
def __init__(self, key, val):
39+
self.key = key
40+
self.val = val
41+
self.next = None
42+
self.prev = None
43+
44+
class LRUCache(object):
45+
def __init__(self, capacity):
46+
self.capacity = capacity
47+
self.dic = {} #[0]
48+
self.head = Node(0, 0) #[3]
49+
self.tail = Node(0, 0) #[3]
50+
self.head.next = self.tail
51+
self.tail.prev = self.head
52+
53+
def remove(self, node):
54+
node.prev.next = node.next
55+
node.next.prev = node.prev
56+
57+
def promote(self, node): #[1]
58+
#set the node next to head
59+
temp = self.head.next
60+
node.next = temp
61+
temp.prev = node
62+
self.head.next = node
63+
node.prev = self.head
64+
65+
def get(self, key):
66+
if key in self.dic:
67+
node = self.dic[key]
68+
self.remove(node)
69+
self.promote(node)
70+
return node.val
71+
return -1
72+
73+
def put(self, key, value):
74+
if key in self.dic:
75+
self.remove(self.dic[key])
76+
node = Node(key, value)
77+
self.promote(node)
78+
self.dic[key] = node
79+
80+
if len(self.dic)>self.capacity: #[2]
81+
del self.dic[self.tail.prev.key]
82+
self.remove(self.tail.prev)
83+
84+
#using OrderedDict()
85+
class LRUCache(object):
86+
def __init__(self, capacity):
87+
self.dic = collections.OrderedDict()
88+
self.remain = capacity
89+
90+
def get(self, key):
91+
if key not in self.dic:
92+
return -1
93+
v = self.dic.pop(key)
94+
self.dic[key] = v # set key as the newest one
95+
return v
96+
97+
def set(self, key, value):
98+
if key in self.dic:
99+
self.dic.pop(key)
100+
else:
101+
if self.remain > 0:
102+
self.remain -= 1
103+
else: # self.dic is full
104+
self.dic.popitem(last=False)
105+
self.dic[key] = value

maximum-product-of-three-numbers.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""
2+
if we sort the array, the max would be the product 3 numbers on the right.
3+
but if there are negative numbers, it could also be possible that
4+
two negative numbers lying at the left extreme end could also contribute to lead to a larger product.
5+
thus, after sorting, either
6+
7+
max1 * max2 * max3
8+
max1 * min1 * min2
9+
10+
so our gaol will be to find the max 3 numbers and min 2 numbers in the array
11+
"""
12+
class Solution(object):
13+
def maximumProduct(self, nums):
14+
min1 = float('inf') #smallest
15+
min2 = float('inf') #second smallest
16+
17+
max1 = float('-inf') #largest
18+
max2 = float('-inf') #second largest
19+
max3 = float('-inf') #third largest
20+
21+
for n in nums:
22+
if n<=min1:
23+
min2 = min1
24+
min1 = n
25+
elif n<=min2:
26+
min2 = n
27+
28+
if n>=max1:
29+
max3 = max2
30+
max2 = max1
31+
max1 = n
32+
elif n>=max2:
33+
max3 = max2
34+
max2 = n
35+
elif n>=max3:
36+
max3 = n
37+
38+
return max(min1*min2*max1, max1*max2*max3)

minimum-path-sum.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""
2+
let's reset the array by it's min value start out from (0,0)
3+
in another words, after reset
4+
grid[i][j]'s value will be the min value start out from (0,0)
5+
6+
if we are at (i,j), we will be either from (i-1,j) or (i,j-1)
7+
we call them s1 and s2, let's assume they are both in range
8+
grid[i][j] will be grid[i][j]+min(s1, s2)
9+
10+
we will start out from (0,0) and reset the entire grid.
11+
"""
12+
class Solution(object):
13+
def minPathSum(self, grid):
14+
n = len(grid)
15+
m = len(grid[0])
16+
for i in xrange(n):
17+
for j in xrange(m):
18+
s1 = s2 = float('inf')
19+
if i-1>=0:
20+
s1 = grid[i-1][j]
21+
if j-1>=0:
22+
s2 = grid[i][j-1]
23+
24+
if s1==float('inf') and s2==float('inf'): continue #both source out of range
25+
grid[i][j]+=min(s1, s2)
26+
27+
return grid[-1][-1]

sliding-window-maximum.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
class Solution(object):
2+
def maxSlidingWindow(self, nums, k):
3+
opt = []
4+
q = collections.deque()
5+
for i in xrange(len(nums)):
6+
n = nums[i]
7+
8+
#move the window
9+
if q and q[0]<=i-k: q.popleft()
10+
11+
#pop the right if the element in queue is not greater than the in-coming one
12+
#by doing this, we can always keep the max in the current window at left most
13+
while q and nums[q[-1]]<=n: q.pop()
14+
15+
q.append(i)
16+
17+
#add the max to the output array after the first kth element
18+
if 1+i>=k: opt.append(nums[q[0]])
19+
return opt

two-sum.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
11
#https://leetcode.com/problems/two-sum/
22
"""
3-
I really take time to explain my solution, because I wanted to help people understand.
4-
If you like my answer, a star on GitHub I will really appreciated.
5-
https://github.com/wuduhren/leetcode-python
3+
when we iterate through the nums
4+
we don't know if the counter part exist
5+
so we store the counter part we want in the 'wanted' with the index now
6+
so inside the wanted is {the_counter_part_we_want:index_now} [0]
7+
8+
later on if we found the num is in 'wanted'
9+
we return the index_now and the index_now we previously stored in the 'wanted' [1]
610
"""
711
class Solution(object):
812
def twoSum(self, nums, target):
9-
for idx, val in enumerate(nums):
10-
for idx2 in range(idx+1, len(nums)):
11-
val2 = nums[idx2]
12-
if ((val+val2)==target):
13-
return [idx, idx2]
13+
wanted = {}
14+
for i in xrange(len(nums)):
15+
n = nums[i]
16+
if n in wanted: #[1]
17+
return [wanted[n], i]
18+
else:
19+
wanted[target-n] = i #[0]
20+
return []
21+
22+
"""
23+
I really take time to explain my solution, because I wanted to help people understand.
24+
If you like my answer, a star on GitHub I will really appreciated.
25+
https://github.com/wuduhren/leetcode-python
26+
"""

unique-email-addres.py

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,74 @@
11
#https://leetcode.com/problems/unique-email-addresses/
2-
import re
2+
"""
3+
[0]
4+
First we use set to store the processed email
5+
set is implement in hashmap, so it takes O(1) to store unique value.
6+
7+
[1]
8+
Split the email by '@' to local_name and domain_name
9+
10+
[2]
11+
we find the first '+' and remove the char after it.
12+
13+
[3]
14+
we remove the '.' in the string.
15+
16+
we iterate the local_name part 3 times
17+
first time we are finding the first '@'
18+
second time we are finding the first '+'
19+
third time we are finding all the '.'
20+
21+
isn't faster to just iterate once?
22+
so I come up with the second solution which only iterate once to process the email
23+
but it is slower, I guess Python really do a good job on the string function
24+
because they are implemented by C.
25+
in other language, the second solution might be faster.
26+
27+
both solution are O(N)
28+
"""
329
class Solution(object):
430
def numUniqueEmails(self, emails):
5-
rs_list = []
31+
book = set() #[0]
632
for s in emails:
7-
local_name = s[:s.index('@')]
8-
domain_name = s[s.index('@'):]
33+
at = s.find('@') #[1]
34+
local_name = s[:at]
35+
domain_name = s[at:]
936

10-
local_name = local_name[:local_name.index('+')]
11-
local_name = local_name.replace('.', '')
12-
r = local_name+domain_name
37+
plus = local_name.find('+') #[2]
38+
if plus!=-1: local_name = local_name[:plus]
39+
40+
local_name = local_name.replace('.', '') #[3]
41+
42+
r = local_name+domain_name #[0]
43+
book.add(r)
1344

14-
if r not in rs_list:
15-
rs_list.append(r)
16-
return len(rs_list)
45+
return len(book)
46+
47+
48+
class Solution(object):
49+
def numUniqueEmails(self, emails):
50+
book = set()
51+
for email in emails:
52+
r = ''
53+
ignore = False
54+
for i, c in enumerate(email):
55+
if c=='@':
56+
r+=email[i:]
57+
break
58+
59+
if ignore: continue
60+
61+
if c=='.':
62+
continue
63+
elif c=='+':
64+
ignore = True
65+
else:
66+
r+=c
67+
book.add(r)
68+
return len(book)
69+
70+
"""
71+
I really take time to make the best solution, because I wanted to help people understand.
72+
If you like my answer, a star on GitHub I will really appreciated.
73+
https://github.com/wuduhren/leetcode-python
74+
"""

0 commit comments

Comments
 (0)