Compare commits

...

7 Commits

16 changed files with 366 additions and 0 deletions

View File

@ -0,0 +1,49 @@
Determine if a `9 x 9` Sudoku board is valid. Only the filled cells need to be validated **according to the following rules**:
1. Each row must contain the digits `1-9` without repetition.
2. Each column must contain the digits `1-9` without repetition.
3. Each of the nine `3 x 3` sub-boxes of the grid must contain the digits `1-9` without repetition.
**Note:**
* A Sudoku board (partially filled) could be valid but is not necessarily solvable.
* Only the filled cells need to be validated according to the mentioned rules.
**Example 1:**
![](https://upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Sudoku-by-L2G-20050714.svg/250px-Sudoku-by-L2G-20050714.svg.png)
Input: board =
[["5","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
Output: true
**Example 2:**
Input: board =
[["8","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
Output: false
Explanation: Same as Example 1, except with the 5 in the top left corner being modified to 8. Since there are two 8's in the top left 3x3 sub-box, it is invalid.
**Constraints:**
* `board.length == 9`
* `board[i].length == 9`
* `board[i][j]` is a digit `1-9` or `'.'`.

View File

@ -0,0 +1,54 @@
class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
#
# NOTE: **READ THE PROBLEM DESCRIPTION ALWAYS!!**
#
# Even though it mentions Sudoku, it doesn't mean the
# rules are the same as the real world. Which is the case
# here — we need to only look at the filled cell and the rules
# provided.
size = len(board)
# 1. Check if rows and cols are valid
#
# We can iterate both rows and cols at the same time since
# the sudoku board has 9 rows and 9 cols
for i in range(size):
row = set()
col = set()
for j in range(size):
# ith row check
if board[i][j] != '.':
if board[i][j] in row:
return False
row.add(board[i][j])
# ith col check
if board[j][i] != '.':
if board[j][i] in col:
return False
col.add(board[j][i])
# 2. Check if squares are valid
#
# We can do normal row * col iteration and use `// 3` to figure
# out which square a cell belongs to
squares = [[set(), set(), set()] for _ in range(3)]
for i in range(size):
for j in range(size):
cell = board[i][j]
if cell == '.':
continue
square = squares[i // 3][j // 3]
if cell in square:
return False
square.add(cell)
return True

View File

@ -0,0 +1,27 @@
Given an array of strings `strs`, group **the anagrams** together. You can return the answer in **any order**.
An **Anagram** is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.
**Example 1:**
Input: strs = ["eat","tea","tan","ate","nat","bat"]
Output: [["bat"],["nat","tan"],["ate","eat","tea"]]
**Example 2:**
Input: strs = [""]
Output: [[""]]
**Example 3:**
Input: strs = ["a"]
Output: [["a"]]
**Constraints:**
* `1 <= strs.length <= 104`
* `0 <= strs[i].length <= 100`
* `strs[i]` consists of lowercase English letters.

View File

@ -0,0 +1,13 @@
# Time: O(N * MlogM) where N is len(strs) and M is num of chars in a string
# Space: O(N)
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
groups = {}
for s in strs:
s_sorted = ''.join(sorted(s))
groups[s_sorted] = groups.get(s_sorted, []) + [s]
return list(groups.values())

View File

@ -0,0 +1,24 @@
# Time: O(N · M)
# Space: O(N)
from collections import Counter, defaultdict
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
# If key doesn't exist, creates empty list using `list`
# factory/ctor function
groups = defaultdict(list)
for s in strs:
# Keep counter for num of times each letter appeared
counts = [0] * 26
for c in s:
i = ord(c) - ord('a')
counts[i] += 1
# Lists aren't hashable, so we need to convert the counts
# to tuple so that we can key them
groups[tuple(counts)].append(s)
return list(groups.values())

View File

@ -0,0 +1,24 @@
Given an integer array `nums`, return `true` if any value appears **at least twice** in the array, and return `false` if every element is distinct.
**Example 1:**
Input: nums = [1,2,3,1]
Output: true
**Example 2:**
Input: nums = [1,2,3,4]
Output: false
**Example 3:**
Input: nums = [1,1,1,3,3,4,3,2,4,2]
Output: true
**Constraints:**
* `1 <= nums.length <= 105`
* `-109 <= nums[i] <= 109`

View File

@ -0,0 +1,11 @@
class Solution:
def containsDuplicate(self, nums: List[int]) -> bool:
counts = {}
for num in nums:
counts[num] = counts.get(num, 0) + 1
if counts[num] > 1:
return True
return False

View File

@ -0,0 +1,8 @@
## What if we were allowed to use division?
Well, one might think that you can then find product(nums) and divide by nums[i] in the loop. But the problem with this approach is when there are 0s in the array. That causes the entire product to become zero.
So, we probably need to keep track of zero count and the first zero index.
1. If there are >1 zeroes, then the result would be all zeroes so.
2. If there's only 1 zero, then we need to keep product excluding the zero to be kept. Then fill the result with all zeroes except for the 0 element's index which would equal the product.

View File

@ -0,0 +1,25 @@
Given an integer array `nums`, return _an array_ `answer` _such that_ `answer[i]` _is equal to the product of all the elements of_ `nums` _except_ `nums[i]`.
The product of any prefix or suffix of `nums` is **guaranteed** to fit in a **32-bit** integer.
You must write an algorithm that runs in `O(n)` time and without using the division operation.
**Example 1:**
Input: nums = [1,2,3,4]
Output: [24,12,8,6]
**Example 2:**
Input: nums = [-1,1,0,-3,3]
Output: [0,0,9,0,0]
**Constraints:**
* `2 <= nums.length <= 105`
* `-30 <= nums[i] <= 30`
* The product of any prefix or suffix of `nums` is **guaranteed** to fit in a **32-bit** integer.
**Follow up:** Can you solve the problem in `O(1)` extra space complexity? (The output array **does not** count as extra space for space complexity analysis.)

View File

@ -0,0 +1,25 @@
from functools import reduce
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
# We can divide this problem by finding the prefix and
# postfix products of a given element and then multiplying
# them together
result = [0] * len(nums)
# Find prefix products, i.e, for ith element, store
# product of 0 to a[i - 1]
prefix = 1
for i, num in enumerate(nums):
result[i] = prefix
prefix *= num
# Find suffix products by iterating from the last, and
# combine them with prefix in the same step to reduce cost
suffix = 1
for i in range(len(nums) - 1, -1, -1):
result[i] *= suffix
suffix *= nums[i]
return result

View File

@ -0,0 +1,22 @@
Given two strings `s` and `t`, return `true` _if_ `t` _is an anagram of_ `s`_, and_ `false` _otherwise_.
An **Anagram** is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.
**Example 1:**
Input: s = "anagram", t = "nagaram"
Output: true
**Example 2:**
Input: s = "rat", t = "car"
Output: false
**Constraints:**
* `1 <= s.length, t.length <= 5 * 104`
* `s` and `t` consist of lowercase English letters.
**Follow up:** What if the inputs contain Unicode characters? How would you adapt your solution to such a case?

View File

@ -0,0 +1,13 @@
# Time: O(NlogN)
# Space: O(1)
from collections import Counter
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
slen, tlen = len(s), len(t)
if slen != tlen:
return False
return sorted(s) == sorted(t)

View File

@ -0,0 +1,8 @@
# Time: O(N)
# Space: O(N)
from collections import Counter
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
return Counter(s) == Counter(t)

View File

@ -0,0 +1,21 @@
# Time: O(N) where N is num of chars in string
# Space: O(N) where N is num of chars in string
from collections import Counter
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
slen, tlen = len(s), len(t)
if slen != tlen:
return False
scounts, tcounts = {}, {}
for i in range(slen):
sc, tc = s[i], t[i]
scounts[sc] = scounts.get(sc, 0) + 1
tcounts[tc] = tcounts.get(tc, 0) + 1
return scounts == tcounts

View File

@ -0,0 +1,41 @@
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
'''
Approach using bucket sort
'''
c = Counter(nums)
# Idea here is that the list indices will represent
# the actual counts and we store elements matching thise
# counts under the index. If size n list is provided, max
# count possible is n but lists are 0-indexed so we set
# num_bucket to have n+1 size.
num_bucket = [[] for _ in range(len(nums) + 1)]
# Later down, we will iterate in reverse through `num_bucket` and
# instead of iterating through the entire list, we can take note
# of the max count we observe and start from there instead.
max_count_seen = -1
for num, count in c.items():
num_bucket[count].append(num)
max_count_seen = max(max_count_seen, count)
result = []
j = max_count_seen
# Iterate reverse through num_bucket (note the max_count_seen
# optimization) and fill the result array until k elements are
# added
while j >= 0:
for num in num_bucket[j]:
result.append(num)
# Possible that we filled k elements already in this inner
# loop, so get out
if len(result) == k:
return result
j -= 1

View File

@ -1,3 +1,4 @@
from collections import Counter
from heapq import heapify, heappop
class Solution: