860. Lemonade Change Easy :
class Solution:
def lemonadeChange(self, bills: List[int]) -> bool:
five = ten = 0
for v in bills:
if v == 5:
five += 1
elif v == 10:
ten += 1
five -= 1
else:
if ten:
ten -= 1
five -= 1
else:
five -= 3
if five < 0:
return False
return True
### My V
def f(a):
fives = []
tens = []
for n in a:
if n == 5:
fives.append(n)
elif n == 10:
if len(fives) > 0:
fives.pop()
tens.append(10)
else:
return False
elif n == 20:
if len(tens) > 0 and len(fives) >= 1:
tens.pop()
fives.pop()
elif len(fives) >= 3:
fives = fives[:-3]
else:
return False
return True
Task
Given an m x n picture consisting of black 'B' and white 'W' pixels, return the number of black lonely pixels.
A black lonely pixel is a character 'B' that located at a specific position where the same row and same column don't have any other black pixels.
My Note: lonely means no other B pixel on the ENTIRE row or column (do not mistake with adjacency).
["W","W","B"],
["W","B","W"],
["B","W","W"]]
Output: 3
Explanation: All the three 'B's are black lonely pixels.
["B","B","B"],
["B","B","W"],
["B","B","B"]]
Output: 0
Solution
-2 traversals
-1st: initiate arrays rows = [0,0,0], cols=[0,0,0], record +1 to that row, col if you met 'B'
-2nd trav: if 'B', is the value at that row==1, at that col==1.
def findLonelyPixel(self, picture: List[List[str]]) -> int:
w, h = len(picture), len(picture[0])
rows, cols = [0] * w, [0] * h
for x in range(w):
for y in range(h):
if picture[x][y] == 'B':
rows[x] += 1
cols[y] += 1
ans = 0
for x in range(w):
for y in range(h):
if picture[x][y] == 'B':
if rows[x] == 1:
if cols[y] == 1:
ans += 1
return ans
rows, cols = [0] * w, [0] * h
Create records for all rows and columns. Initiate rows = [0,0,0], cols=[0,0,0]
cols[y] += 1
Again, we don't check the adjacent values for an item.
If we encounter a "B", we record that on that row and on that column there is +1 of B.
Hence if the value will be 2 when we check later, then that pixel is not lonely.
### My V2
# (count(), and flip rows/columns with list(zip(*m)) )
def f(m):
w = len(m)
h = len(m[0])
lone = 0
for i in range(w):
for j in range(h):
if m[i][j] == "B":
cnt1 = m[i].count("B")
cnt2 = list(zip(*m))[i].count("B")
if cnt1 + cnt2 == 2:
lone += 1
return lone
### My V1
# Idea:
# -use count()
# -use transposed version of the matrix
def f(m):
ans = 0
transposed = list(zip(*m))
for n in m:
cnt = n.count("B")
if cnt == 1:
i = n.index("B")
if transposed[i].count("B") == 1:
ans += 1
return ans
picture = [["W", "W", "B"], ["W", "B", "W"], ["B", "W", "W"]]
print(f(picture))
picture2 = [["B", "B", "B"], ["B", "B", "W"], ["B", "B", "B"]]
print(f(picture2))
picture3 = [["W", "W", "B"], ["W", "B", "B"], ["B", "W", "W"]]
print(f(picture3))
#3
#0
#1
674. Longest Continuous Increasing Subsequence Easy :
def longest_subsequence(a):
lmax, lcur = 1, 1 # length max and current
for i in range(1, len(a)):
if a[i] > a[i - 1]:
lcur += 1
else:
lmax = max(lmax, lcur)
lcur = 1
return max(lmax, lcur)
nums = [1, 3, 5, 4, 7]
print(longest_subsequence(nums)) #3
Note: we calculate max length "lmax" only when we encounter a value that breaks the sequence. So if there are several sequences, and the longest is the last one, we never calculate max for it, so we do that in the return statement.
128. Longest Consecutive Sequence Medium :
### Solution (my v).
def f(a):
d = {}
ans = 0
for n in a:
d[n] = True
for k in d:
if k + 1 not in d:
cnt = 0
while k in d:
k -= 1
cnt += 1
ans = max(ans, cnt)
return ans
### V2
def sequence(a):
d = {}
ans = 0
for n in a:
d[n] = True
for n in a:
if n - 1 not in d:
seq = []
while n in d:
seq.append(n)
n += 1
ans = max(ans, len(seq))
return ans
nums = [100, 4, 200, 1, 3, 2]
nums2 = [0, 3, 7, 2, 5, 8, 4, 6, 0, 1]
print(f(nums)) # 4
print(f(nums2)) # 9
if k + 1 not in d:
Start building sequence only starting from the topmost number. E.g. a=[2,3,100, 2,99, 4], do not start building sequence from 2, because there is 2+1=3 in a. Start only from 4.
Even though we are building the efficient way, for greatest n in sequence. There might be different unrelated sequences, like in a=[2,3,100, 2,99, 4]. So we build an inner count "cnt" for each sequence, and choose max.
229. Majority Element II Medium :
import collections
def majority_element(a):
times = len(a) / 3
cnt = collections.Counter(a)
return [x for x in cnt if cnt[x] > times]
#OR
def maj_elem(a):
return [
x for x in collections.Counter(a) if collections.Counter(a)[x] > (len(a) / 3)
]
nums = [3, 2, 3]
nums2 = [1]
print(majority_element(nums)) # [3]
print(majority_element(nums2)) # [1]
643. Maximum Average Subarray I Easy :
### Solution 1
# (more of a sliding window technique)
class Solution:
def findMaxAverage(self, nums: List[int], k: int) -> float:
s = sum(nums[:k])
ans = s
for i in range(k, len(nums)):
s += nums[i] - nums[i - k]
ans = max(ans, s)
return ans / k
s += nums[i] - nums[i - k]
nums[i] adds 1 item to the right of initial slice nums[:k]
But we also should take care to take away 1 item to the left of initial slice,
to preserve len of slice s = k,
this is exactly what "- nums[i-k]" does.
E.g. if k=4, first i=4, then [i-k]=4-4=0, so we subtract item at index [0].
This achieves a sliding window effect.
### My V2
# (Classic sliding window.)
def f(a, k):
lp = 0
ans = 0
for rp in range(len(a)):
if rp - lp + 1 == k:
res = sum(a[lp : rp + 1]) / k
ans = max(ans, res)
lp += 1
return "{:.5f}".format(ans)
### My V
# (More of a Python slicing technique.)
def f(a, k):
ans = 0
for i in range(len(a) - (k - 1)):
avg = sum(a[i : i + k]) / k
ans = max(ans, avg)
return ans
You are given m arrays, where each array is sorted in ascending order.
You can pick up two integers from two different arrays (each array picks one) and calculate the distance. We define the distance between two integers a and b to be their absolute difference |a - b|.
Return the maximum distance.
Example 1: Input: arrays = [[1,2,3],[4,5],[1,2,3]] Output: 4 Explanation: One way to reach the maximum distance 4 is to pick 1 in the first or third array and pick 5 in the second array.
# Solution 1
class Solution:
def maxDistance(self, arrays: List[List[int]]) -> int:
ans = 0
mi, mx = arrays[0][0], arrays[0][-1] #**1
for arr in arrays[1:]:
a, b = abs(arr[0] - mx), abs(arr[-1] - mi) #**2
ans = max(ans, a, b)
mi = min(mi, arr[0])
mx = max(mx, arr[-1])
return ans
#**
1)Work with the fact that we are given SORTED arrays.
2)Make sure each time we pick min and max from two <different arrays>.
# Solution 2
class Solution:
def maxDistance(self, arrays):
"""
:type arrays: List[List[int]]
:rtype: int
"""
res, curMin, curMax = 0, 10000, -10000
for a in arrays :
res = max(res, max(a[-1]-curMin, curMax-a[0]))
curMin, curMax = min(curMin, a[0]), max(curMax, a[-1])
return res
670. Maximum Swap Medium :
### Solution 2 No tools. (LC accepted 73,35%, Time and Space O(log m))
class Solution:
def maximumSwap(self, num: int) -> int:
s = list(str(num))
n = len(s)
d = list(range(n))
for i in reversed(range(n-1)):
if s[i] <= s[d[i + 1]]:
d[i] = d[i + 1]
for i, j in enumerate(d):
if s[i] < s[j]:
s[i], s[j] = s[j], s[i]
break
return int(''.join(s))
-two traversals:
1)right to left; array d to record index of max value to the right of current
2)left to right traverse d, if index<value, swap
E.g. num = 98368 -> 98863
-convert num to s=['9', '8', '3', '6', '8']
-n=len(s)=5
-d=[0,1,2,3,4]
---Traverse right to left: for i 3,2,1,0:
s=['9', '8', '3', '6', '8']
d=[0,1,2,3,4]
If s[i]<=max at right (max at right is stored in d)
if s[i] <= s[d[i + 1]]:
6 < 8
d=[0,1,2,4,4]
If s at index d index < s at index d value: swap
0 1 2
d=[0,1,<4>,4,4]
Here value at index 2 < value at index 4.
### My V (LC accepted: 50,90%)
def swap(n):
s = str(n)
L = [int(n) for n in s]
L2 = sorted(L)
for i, num in enumerate(L):
max_val = L2.pop()
if num < max_val:
ind = s.rindex(str(max_val))
L[i], L[ind] = L[ind], L[i]
break
L3 = map(str, L)
return int("".join(L3))
print(swap(937)) # 973
print(swap(2736)) # 7236
print(swap(90979)) # 99970
print(swap(93774)) # 97374 after using str.rindex(max_val) 97734
1)we swap not the first integer (here at i=2)
2)there are several occurrences of the max_value 7.
We have to look for the rightmost index of the occurrence of max_value.
So that after the swap the number is bigger.
[Credit: https://stackoverflow.com/questions/6890170/how-to-find-the-last-occurrence-of-an-item-in-a-python-list ]
For the more general case you could use list.index on the reversed list:
>>> len(li) - 1 - li[::-1].index('a') 6
The slicing here creates a copy of the entire list. That's fine for short lists, but for the case where li is very large, efficiency can be better with a lazy approach:
def list_rindex(li, x):
for i in reversed(range(len(li))):
if li[i] == x:
return i
raise ValueError("{} is not in list".format(x))
# One-liner version:
next(i for i in reversed(range(len(li))) if li[i] == 'a')
4. Median of Two Sorted Arrays Hard
The thing here is that the task asks for a solution o(log(n+m)). It is easier to find solutions O(n+m). Several listed below. While O(log(n+m) is more complicated, uses binary search.
### Solution 1
# (Merging, i.e. here nums1+nums2 is O(n+m).
# Despite that, submitting to Leetcode gives a pretty good acceptance statistics -
# Time beats 99.28% of users with Python3. Memory beats 61%.)
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
concat = sorted(nums1+nums2)
if len(concat)%2 == 1:
med = concat[int(len(concat)/2)]
else:
tot_len = int(len(concat)/2)
med = (concat[tot_len-1]+concat[tot_len]) / 2
return med
### Solution 2 (less efficient according to Leetcode)
import statistics
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
nums3 = nums1 + nums2
nums3 = sorted(nums3)
return statistics.median(nums3)
#OR (Runtime Beats80.53%of users with Python3, Memory Beats86.27%of users with Python3)
import statistics
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
return statistics.median(sorted(nums1+nums2))
### Solution 3 (Leetcode editorial, O(n+m))
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
m, n = len(nums1), len(nums2)
p1, p2 = 0, 0
# Get the smaller value between nums1[p1] and nums2[p2].
def get_min():
nonlocal p1, p2
if p1 < m and p2 < n:
if nums1[p1] < nums2[p2]:
ans = nums1[p1] #**1
p1 += 1
else:
ans = nums2[p2]
p2 += 1
elif p2 == n:
ans = nums1[p1]
p1 += 1
else:
ans = nums2[p2]
p2 += 1
return ans
if (m + n) % 2 == 0:
for _ in range((m + n) // 2 - 1):
_ = get_min()
return (get_min() + get_min()) / 2
else:
for _ in range((m + n) // 2): #**2
_ = get_min()
return get_min()
2# These loops
for _ in range((m + n) // 2 - 1)
Iterate that many times before the actual answer that we need.
E.g. [1,2], [3]
total len=3, mid =1
for _ in range(1) -> iterates once.
return get_min() -> iterates once the 2nd time
So we get ans at p1=1 which nums1[p1]=value 2.
### Solution 3, My V (Leetcode checked, beets 75% of Py3 solutions both T&M.)
class Solution:
def findMedianSortedArrays(self, a1: List[int], a2: List[int]) -> float:
n = len(a1)
m = len(a2)
total_len = m + n
mid_index = total_len // 2
p1, p2 = 0, 0
# returns CURRENT min values at p1 or p2, then moves +1 p1 or p2
def get_min():
nonlocal p1, p2
if p1 == n:
ans = a2[p2]
p2 += 1
elif p2 == m:
ans = a1[p1]
p1 += 1
else: # both p1 and p2 are within array lens
if a1[p1] < a2[p2]:
ans = a1[p1]
p1 += 1
else:
ans = a2[p2]
p2 += 1
return ans
if total_len & 1: # odd
for _ in range(mid_index):
_ = get_min()
return get_min()
else: # even
for _ in range(mid_index - 1):
_ = get_min()
return (get_min() + get_min()) / 2
921. Minimum Add to Make Parentheses Valid Medium
NOTE: The simplistic examples of the task hide the fact that you should account for cases like ')('. So it is not enough to count parentheses. We should keep track of them in order. (i.e. use stack). :
class Solution(object):
def minAddToMakeValid(self, s):
"""
:type S: str
:rtype: int
"""
# left is length of stack
left = right = 0
for char in s:
if char == '(':
left += 1
else:
if left:
left -= 1
else:
right += 1
return left + right
class Solution:
def minAddToMakeValid(self, s: str) -> int:
stk = []
for c in s:
if c == ')' and stk and stk[-1] == '(':
stk.pop()
else:
stk.append(c)
return len(stk)
### My V (LC accepted)
def make_valid(s):
stack = [] # for '('
cnt = 0 # for ')' without pair
for c in s:
if c == "(":
stack.append(c)
else:
if len(stack) > 0:
stack.pop()
else:
cnt += 1
return cnt + len(stack)