217. Contains Duplicate | Easy
class Solution:
def containDuplicate(self, nums):
from collections import defaultdict
hash = defaultdict(int)
for num in nums:
hash[num] += 1
if hash[num] == 2:
return True
return False
def containDuplicate2(self, nums):
hash = set()
for num in nums:
if num in hash:
return True
hash.add(num)
return False
242. Valid Anagram | Easy
- 试了两版解决dict的key为空的情况,效果差不多
defaultdict(int)
get(key, 0)
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
from collections import defaultdict
hash = defaultdict(int)
if len(s) != len(t):
return False
for index in range(len(s)):
hash[s[index]] += 1
hash[t[index]] -= 1
for key in hash:
if hash[key] != 0:
return False
return True
def isAnagram2(self, s: str, t: str) -> bool:
hash = {}
if len(s) != len(t):
return False
for index in range(len(s)):
hash[s[index]] = hash.get(s[index], 0) + 1
hash[t[index]] = hash.get(t[index], 0) - 1
for key in hash:
if hash[key] != 0:
return False
return True
1. Two Sum
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
hash = {}
for index in range(len(nums)):
if nums[index] in hash.keys():
return [hash[nums[index]], index]
hash[target - nums[index]] = index
return []
49. Group Anagrams | Medium
Version1
- 一个非常直接的想法就是维护一个hashtable,key就是每个split的char,value就是对应的Item list;
- Version1:记录一下错误
- list是Unhash type | 解决:sort()之后转tuple
class Solution:
def groupAnagrams(self, strs: List[str]):
hash = {}
for item in strs:
char_ls = []
for char in item:
char_ls.append(char)
char_ls.sort()
char_ls = tuple(char_ls)
if char_ls not in hash:
hash[char_ls] = []
hash[char_ls].append(item)
ans = []
for key in hash:
ans.append(hash[key])
return ans
Version2
- 看了一眼别人的代码2333,优化点记录!()
- 首先是
sorted()
和sort()
的区别- sort() function is very similar to sorted() but unlike sorted it returns nothing and makes changes to the original sequence. Moreover, sort() is a method of list class and can only be used with lists.
- sorted() method sorts the given sequence as well as set and dictionary(which is not a sequence) either in ascending order or in descending order(does unicode comparison for string char by char) and always return the a sorted list. This method doesnot effect the original sequence.
- 其次是dic的value的返回不需要再用一层for循环得到!!
- 首先是
- 记号: m为strs的长度,n为str中item的平均长度
- 时间复杂度: O ( m n l o g n ) O(mnlogn) O(mnlogn)(ps:排序的 O ( n l o g n ) O(nlogn) O(nlogn),做了 m m m次)
class Solution:
def groupAnagrams(self, strs: List[str]):
hash = {}
for item in strs:
key = ''.join(sorted(s)) # 1. sorted返回list 要join拼接
if key not in hash:
dic[key] = []
dic[key].append(item)
return list(dic.values()) # 2.
Version3
- 参考neetcode滴!
- 时间复杂度 O ( m n ) O(mn) O(mn)
- 想法:大体思路是一样的都是维护一个hashmap,但是在key那做了优化;version2是对每个item sort之后存入key,version3则是维护一个长度为26的list,对应a,…,z(关键在于这个长度是26哈哈哈for一遍item还是可控的,实际上也是一种程度的有序了);
- trick here:
- 只会输入26个小写字母,考虑key为tuple(array),其中array维护word的char统计信息,array的index表示26字母的位置,value就是次数;
- 为什么key用tuple?因为list不可以报错
TypeError: unhashable type: 'list'
- 几个可以学习的点:
defaultdict()
- 获取相对位置!
ord
函数的运用; - 同样的list unhashable的问题,转tuple;
dict.values()
import collections
class Solution:
def groupAnagrams(self, strs: List[str]):
ans = collections.defaultdict(list)
for item in strs:
count = [0] * 26 # a,...,z
for char in item:
count[ord(char) - ord("a")] += 1
ans[tuple(count)].append(item)
return list(ans.values())
347. Top K Frequent Elements
Version1 | 失败
- 总体思路:统计nums的各num的出现频次(hash dict保存);利用对value进行排序,取最大的k个,返回对应的key;
- 失败的关键点在于在返回对应的key时,做了一个key-value的反转,但是没有考虑到value通常并不是唯一的,即多个key对应一个value无法进行正确的反转;如何返回对应的key呢?
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
ans = []
hash = {}
for num in nums:
if num not in hash:
hash[num] = 0
hash[num] += 1
re_hash = {}
for key in hash:
re_hash[hash[key]] = key
tmp = sorted(list(hash.values()), reverse=True)
print(re_hash, tmp)
for i in tmp[:k]:
ans.append(re_hash[i])
return ans
Version2
- 这里就是把
利用对value进行排序,取最大的k个,返回对应的key
这一步实现综合起来,打包成hash.items()
- 回过头来再看一遍有个注意点:
dict.values()
要转list!!
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
hash = {}
for num in nums:
if num not in hash:
hash[num] = 0
hash[num] += 1
tmp = sorted(list(hash.values()), reverse=True)
return [key for key, val in hash.items() if val in tmp[: k]]
Version3
- 还是neetcode!
- 时间复杂度 O ( n ) O(n) O(n)(空间复杂度 O ( n ) O(n) O(n))
- 看了一下他的思路,他的时间复杂度降下来是建立在不用排序的基础上的,重新开辟了个freq的list存储,index表示出现的频次,freq[index]存放出现Index次的nums,最后再从后往前找到k个就可以了;
- 可以学习的点
dict.get(key, default)
: 在 key(键)不在字典中时,可以返回默认值 None 或者设置的默认值;
def topKFrequent2(self, nums: List[int], k: int) -> List[int]:
# bucket sort
hash = {}
for n in nums:
hash[n] = 1 + hash.get(n, 0)
freq = [[] for _ in range(len(nums) + 1)]
for key, val in hash.items():
freq[val].append(key)
res = []
for i in range(len(freq) - 1, 0, -1):
for n in freq[i]:
res.append(n)
if len(res) == k:
return res
238. Product of Array Except Self
奇怪了!!ver2明明是按ver3(nc)的思路来的,为什么跑出来时空性能差距这么大…?明天来看;
class Solution:
def productExceptSelf(self, nums):
from collections import defaultdict
hash = defaultdict(int)
res = []
for num in nums:
hash[num] += 1
for num in nums:
tmp = 1
for k, v in hash.items():
if k == num:
tmp = tmp * k ** (v - 1)
if k != num:
tmp = tmp * k ** v
res.append(tmp)
return res
def productExceptSelf2(self, nums):
pre = [1]
post = [1]
for i in range(1, len(nums)):
pre.append(pre[i - 1] * nums[i - 1])
post.insert(0, post[0] * nums[len(nums) - i])
return [pre[i] * post[i] for i in range(len(nums))]
def productExceptSelf3(self, nums):
res = [1] * (len(nums))
prefix = 1
for i in range(len(nums)):
res[i] = prefix
prefix *= nums[i]
postfix = 1
for i in range(len(nums) - 1, -1, -1):
res[i] *= postfix
postfix *= nums[i]
return res
36. Valid Sudoku
今天先自己过一遍,明天再把nc的顺一遍从238开始;
- 这道题主要是行列,小九宫格的处理
- 二维不好切片列:
[j[i] for j in board]
用它取列了; - 小九宫格应该也可以去做简化的;
- 二维不好切片列:
class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
def isValidSudoku2(self, board: List[List[str]]) -> bool:
from collections import defaultdict
def check(array):
count = defaultdict(int)
for i in range(9):
if array[i] == '.':
continue
count[array[i]] += 1
if count[array[i]] > 1:
return False
return True
for i in range(9):
if not check(board[i]) or not check([j[i] for j in board]):
return False
for r in range(3):
for c in range(3):
tmp = []
tmp.extend(board[3 * r][3 * c: 3 * c + 3])
tmp.extend(board[3 * r + 1][3 * c: 3 * c + 3])
tmp.extend(board[3 * r + 2][3 * c: 3 * c + 3])
if not check(tmp):
return False
return True
128. Longest Consecutive Sequence
- 找起始的元素,去计算这个其实元素的连续串的长度,更新longest;
- 不是起始元素continue掉;
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
nums = set(nums)
longest = 0
for num in nums:
if num - 1 in nums:
continue
lenth = 1
while num + lenth in nums:
lenth += 1
longest = max(lenth, longest)
return longest
271. Encode and Decode Strings
我楞是没看懂啥意思哈哈哈哈正常进来正常出来orz…
虽然我知道不能用split写哈哈哈哈哈哈哈哈哈,没有但是但是就是下面还是用split写了;
- split这玩意要取[-1],他是相当于一双手,把分隔符
:;
两边拨开,所以最后出来一个空串需要删掉;
class Solution:
def encode(self, strs):
res = ''
for str in strs:
if str == ':':
res = res + str + '::;'
continue
res = res + str + ':;'
return res
def decode(self, str):
res = str.split(":;")[:-1]
for i in range(len(res)):
if res[i] == '::':
res[i] = ':'
return res