Skip to content

Commit

Permalink
feat: add tons of questions with script
Browse files Browse the repository at this point in the history
Change-Id: I5c3368e850718fac073687a50d4aef7569bc2b28
  • Loading branch information
franklingu committed Jan 30, 2021
1 parent 5e3dd2a commit 1b10359
Show file tree
Hide file tree
Showing 287 changed files with 15,590 additions and 0 deletions.
48 changes: 48 additions & 0 deletions questions/132-pattern/Solution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""
Given an array of n integers nums, a 132 pattern is a subsequence of three integers nums[i], nums[j] and nums[k] such that i < j < k and nums[i] < nums[k] < nums[j].
Return true if there is a 132 pattern in nums, otherwise, return false.
Follow up: The O(n^2) is trivial, could you come up with the O(n logn) or the O(n) solution?
 
Example 1:
Input: nums = [1,2,3,4]
Output: false
Explanation: There is no 132 pattern in the sequence.
Example 2:
Input: nums = [3,1,4,2]
Output: true
Explanation: There is a 132 pattern in the sequence: [1, 4, 2].
Example 3:
Input: nums = [-1,3,2,0]
Output: true
Explanation: There are three 132 patterns in the sequence: [-1, 3, 2], [-1, 3, 0] and [-1, 2, 0].
 
Constraints:
n == nums.length
1 <= n <= 104
-109 <= nums[i] <= 109
"""


class Solution:
def find132pattern(self, nums):
min_list = list(accumulate(nums, min))
stack, n = [], len(nums)

for j in range(n-1, -1, -1):
if nums[j] > min_list[j]:
while stack and stack[-1] <= min_list[j]:
stack.pop()
if stack and stack[-1] < nums[j]:
return True
stack.append(nums[j])
return False
29 changes: 29 additions & 0 deletions questions/4sum-ii/Solution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""
Given four lists A, B, C, D of integer values, compute how many tuples (i, j, k, l) there are such that A[i] + B[j] + C[k] + D[l] is zero.
To make problem a bit easier, all A, B, C, D have same length of N where 0 ≤ N ≤ 500. All integers are in the range of -228 to 228 - 1 and the result is guaranteed to be at most 231 - 1.
Example:
Input:
A = [ 1, 2]
B = [-2,-1]
C = [-1, 2]
D = [ 0, 2]
Output:
2
Explanation:
The two tuples are:
1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0
 
"""


class Solution:
def fourSumCount(self, A: List[int], B: List[int], C: List[int], D: List[int]) -> int:
AB = collections.Counter(a+b for a in A for b in B)
return sum(AB[-c-d] for c in C for d in D)
40 changes: 40 additions & 0 deletions questions/4sum/Solution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""
Given an array nums of n integers and an integer target, are there elements a, b, c, and d in nums such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
Notice that the solution set must not contain duplicate quadruplets.
 
Example 1:
Input: nums = [1,0,-1,0,-2,2], target = 0
Output: [[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
Example 2:
Input: nums = [], target = 0
Output: []
 
Constraints:
0 <= nums.length <= 200
-109 <= nums[i] <= 109
-109 <= target <= 109
"""


class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
ss = dict()
results = set()
for i, n1 in enumerate(nums):
for j, n2 in enumerate(nums):
if j <= i:
continue
s = n1 + n2
for idx1, idx2 in ss.get(target - s, set()):
if not (i != idx1 and i != idx2 and j != idx1 and j != idx2):
continue
elem = tuple(sorted((nums[idx1], nums[idx2], nums[i], nums[j])))
results.add(elem)
ss[s] = ss.get(s, []) + [(i, j)]
return [list(el) for el in results]
73 changes: 73 additions & 0 deletions questions/accounts-merge/Solution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""
Given a list accounts, each element accounts[i] is a list of strings, where the first element accounts[i][0] is a name, and the rest of the elements are emails representing emails of the account.
Now, we would like to merge these accounts. Two accounts definitely belong to the same person if there is some email that is common to both accounts. Note that even if two accounts have the same name, they may belong to different people as people could have the same name. A person can have any number of accounts initially, but all of their accounts definitely have the same name.
After merging the accounts, return the accounts in the following format: the first element of each account is the name, and the rest of the elements are emails in sorted order. The accounts themselves can be returned in any order.
Example 1:
Input:
accounts = [["John", "[email protected]", "[email protected]"], ["John", "[email protected]"], ["John", "[email protected]", "[email protected]"], ["Mary", "[email protected]"]]
Output: [["John", '[email protected]', '[email protected]', '[email protected]'], ["John", "[email protected]"], ["Mary", "[email protected]"]]
Explanation:
The first and third John's are the same person as they have the common email "[email protected]".
The second John and Mary are different people as none of their email addresses are used by other accounts.
We could return these lists in any order, for example the answer [['Mary', '[email protected]'], ['John', '[email protected]'],
['John', '[email protected]', '[email protected]', '[email protected]']] would still be accepted.
Note:
The length of accounts will be in the range [1, 1000].
The length of accounts[i] will be in the range [1, 10].
The length of accounts[i][j] will be in the range [1, 30].
"""


class Solution:
def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]:
def get_connections(accounts):
track = {}
emails = {}
for i, acc in enumerate(accounts):
if i not in track:
track[i] = []
for j, email in enumerate(acc):
if j == 0:
continue
if email not in emails:
emails[email] = []
for k in emails[email]:
if k not in track:
track[k] = []
track[k].append(i)
track[i].append(k)
emails[email].append(i)
return track

track = get_connections(accounts)
visited = set()
parts = []
for i, acc in enumerate(accounts):
if i in visited:
continue
part = []
stack = [i]
while stack:
curr = stack.pop()
if curr in visited:
continue
visited.add(curr)
part.append(curr)
for ne in track.get(curr, []):
if ne in visited:
continue
stack.append(ne)
parts.append(part)
ret = []
for part in parts:
name = accounts[part[0]][0]
acc = set()
for pp in part:
acc = acc.union(set(accounts[pp][1:]))
ret.append([name] + sorted(acc))
return ret
45 changes: 45 additions & 0 deletions questions/add-strings/Solution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""
Given two non-negative integers num1 and num2 represented as string, return the sum of num1 and num2.
Note:
The length of both num1 and num2 is < 5100.
Both num1 and num2 contains only digits 0-9.
Both num1 and num2 does not contain any leading zero.
You must not use any built-in BigInteger library or convert the inputs to integer directly.
"""


class Solution(object):
def addStrings(self, num1, num2):
"""
:type num1: str
:type num2: str
:rtype: str
"""
def to_digit(c):
if c is None:
return 0
return ord(c) - ord('0')

def to_char(d):
if d > 9:
carry = 1
d = d % 10
else:
carry = 0
return chr(ord('0') + d), carry

from itertools import izip_longest
carry = 0
ret = []
for c1, c2 in izip_longest(reversed(num1), reversed(num2)):
d1 = to_digit(c1)
d2 = to_digit(c2)
d, carry = to_char(d1 + d2 + carry)
ret.append(d)
if carry > 0:
ret.append(to_char(carry)[0])
return ''.join(reversed(ret))
26 changes: 26 additions & 0 deletions questions/alien-dictionary/Solution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""
None
"""


class Solution:
def alienOrder(self, words: List[str]) -> str:
pre, suc = collections.defaultdict(set), collections.defaultdict(set)
for pair in zip(words, words[1:]):
for a, b in zip(*pair):
if a != b:
suc[a].add(b)
pre[b].add(a)
break
chars = set(''.join(words))
free = chars - set(pre)
order = ''
while free:
a = free.pop()
order += a
for b in suc[a]:
pre[b].discard(a)
if not pre[b]:
free.add(b)
return order * (set(order) == chars)
67 changes: 67 additions & 0 deletions questions/all-nodes-distance-k-in-binary-tree/Solution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""
We are given a binary tree (with root node root), a target node, and an integer value K.
Return a list of the values of all nodes that have a distance K from the target node.  The answer can be returned in any order.
 
Example 1:
Input: root = [3,5,1,6,2,0,8,null,null,7,4], target = 5, K = 2
Output: [7,4,1]
Explanation:
The nodes that are a distance 2 from the target node (with value 5)
have values 7, 4, and 1.
Note that the inputs "root" and "target" are actually TreeNodes.
The descriptions of the inputs above are just serializations of these objects.
 
Note:
The given tree is non-empty.
Each node in the tree has unique values 0 <= node.val <= 500.
The target node is a node in the tree.
0 <= K <= 1000.
"""


# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
import collections


class Solution:
def distanceK(self, root, target, K):
"""
:type root: TreeNode
:type target: TreeNode
:type K: int
:rtype: List[int]
"""
conn = collections.defaultdict(list)
def connect(parent, child):
if parent and child:
conn[parent.val].append(child.val)
conn[child.val].append(parent.val)
if child.left: connect(child, child.left)
if child.right: connect(child, child.right)
connect(None, root)
bfs = [target.val]
seen = set(bfs)
for i in range(K):
bfs = [y for x in bfs for y in conn[x] if y not in seen]
seen |= set(bfs)
return bfs
Loading

10 comments on commit 1b10359

@marcus-aurelianus
Copy link

@marcus-aurelianus marcus-aurelianus commented on 1b10359 Feb 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The solution for Alien dictionary is well written!
But it failed for test cases like ["abc","ab"]
the correct answer should be ""
because the curremt solution does not evaluate the length of the alien dictionary so it returns "acb"

@marcus-aurelianus
Copy link

@marcus-aurelianus marcus-aurelianus commented on 1b10359 Feb 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest solution, add evaluation else in the second zip loop:

  class Solution:
        def alienOrder(self, words: List[str]) -> str:
            pre, suc = collections.defaultdict(set), collections.defaultdict(set)
            for first, second in zip(words, words[1:]):
                for a, b in zip(first, second):
                    if a != b:
                        suc[a].add(b)
                        pre[b].add(a)
                        break
                else:
                    if (len(first) > len(second)) :
                        return ''
            chars = set(''.join(words))
            free = chars - set(pre)
            order = ''
            while free:
                a = free.pop()
                order += a
                for b in suc[a]:
                    pre[b].discard(a)
                    if not pre[b]:
                        free.add(b)
            return order * (set(order) == chars)   

@franklingu
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marcus-aurelianus could u verify this solution in leetcode? I do not have premium any more... or at least u can give me the question first?

@marcus-aurelianus
Copy link

@marcus-aurelianus marcus-aurelianus commented on 1b10359 Feb 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marcus-aurelianus could u verify this solution in leetcode? I do not have premium any more... or at least u can give me the question first?

Previous suggested solution is verified.

Q:

There is a new alien language that uses the English alphabet. However, the order among letters are unknown to you.

You are given a list of strings words from the dictionary, where words are sorted lexicographically by the rules of this new language.

Derive the order of letters in this language, and return it. If the given input is invalid, return "". If there are multiple valid solutions, return any of them.

Example 1:

Input: words = ["wrt","wrf","er","ett","rftt"]
Output: "wertf"
Example 2:

Input: words = ["z","x"]
Output: "zx"
Example 3:

Input: words = ["z","x","z"]
Output: ""
Explanation: The order is invalid, so return "".

Constraints:

1 <= words.length <= 100
1 <= words[i].length <= 100
words[i] consists of only lowercase English letters.

@franklingu
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marcus-aurelianus what is the expected output for ["abc", "ab"]?

@marcus-aurelianus
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marcus-aurelianus what is the expected output for ["abc", "ab"]?

The expected answer should be "".

@franklingu
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

class Solution:
    def alienOrder(self, words):
        pre, suc = collections.defaultdict(set), collections.defaultdict(set)
        for pair in zip(words, words[1:]):
            for a, b in zip(*pair):
                if a != b:
                    suc[a].add(b)
                    pre[b].add(a)
                    break
        chars = set(suc).union(set(pre))
        free = chars - set(pre)
        order = ''
        while free:
            a = free.pop()
            order += a
            for b in suc[a]:
                pre[b].discard(a)
                if not pre[b]:
                    free.add(b)
        return order * (set(order) == chars)

check this one?

@franklingu
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marcus-aurelianus

if (len(first) > len(second)) :
                        return ''

this proposed solution is not going to work as having "abc", "ab" does not mean no order can be deduced from the input

@marcus-aurelianus
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marcus-aurelianus

if (len(first) > len(second)) :
                        return ''

this proposed solution is not going to work as having "abc", "ab" does not mean no order can be deduced from the input

Under lexicographical rules, 'abc' is greater than 'ab' so it is wrong.
https://leetcode.com/problems/verifying-an-alien-dictionary/
Example 3:
Input: words = ["apple","app"], order = "abcdefghijklmnopqrstuvwxyz"
Output: false
Explanation: The first three characters "app" match, and the second string is shorter (in size.) According to lexicographical rules "apple" > "app", because 'l' > '∅', where '∅' is defined as the blank character which is less than any other character

@marcus-aurelianus
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

class Solution:
    def alienOrder(self, words):
        pre, suc = collections.defaultdict(set), collections.defaultdict(set)
        for pair in zip(words, words[1:]):
            for a, b in zip(*pair):
                if a != b:
                    suc[a].add(b)
                    pre[b].add(a)
                    break
        chars = set(suc).union(set(pre))
        free = chars - set(pre)
        order = ''
        while free:
            a = free.pop()
            order += a
            for b in suc[a]:
                pre[b].discard(a)
                if not pre[b]:
                    free.add(b)
        return order * (set(order) == chars)

check this one?

The solution is right for all cases other than ['abc,''ac'] or ['apple','app']

Please sign in to comment.