字符串
1.https://leetcode.com/problems/palindrome-number/
class Solution:
def isPalindrome(self, x: int) -> bool:
"""
Determine whether an integer is a palindrome.
An integer is a palindrome when it reads the same backward as forward.
:param x:
:return:
>>> solution = Solution()
>>> solution.isPalindrome(121)
True
>>> solution.isPalindrome(-121)
False
>>> solution.isPalindrome(10)
False
"""
if x < 0:
return False
res, t = 0, x
while t > 0:
t, low_num = t // 10, t % 10
res = res*10 + low_num
return res == x
2.https://leetcode.com/problems/count-and-say/
class Solution:
def countAndSay(self, n: int) -> str:
"""
The count-and-say sequence is the sequence of integers with the first five terms as following:
1. 1
2. 11
3. 21
4. 1211
5. 111221
1 is read off as "one 1" or 11.
11 is read off as "two 1s" or 21.
21 is read off as "one 2, then one 1" or 1211.
Given an integer n where 1 ≤ n ≤ 30, generate the nth term of the count-and-say sequence. You can do so recursively, in other words from the previous member read off the digits, counting the number of digits in groups of the same digit.
Note: Each term of the sequence of integers will be represented as a string.
:param n:
:return:
>>> solution = Solution()
>>> solution.countAndSay(1)
'1'
>>> solution.countAndSay(4)
'1211'
"""
res = "1"
import itertools
for _ in range(n-1):
res = ''.join((str(len(list(g))) + digit for digit, g in itertools.groupby(res)))
return res
3.https://leetcode.com/problems/implement-strstr/
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
"""
Implement strStr().
Return the index of the first occurrence of needle in haystack,
or -1 if needle is not part of haystack.
:param haystack:
:param needle:
:return:
>>> solution = Solution()
>>> solution.strStr("hello", "ll")
2
>>> solution.strStr("aaaaa", "bba")
-1
>>> solution.strStr("a", "a")
0
"""
if needle == "":
return 0
length = len(needle)
for i in range(len(haystack)):
if haystack[i: i+length] == needle:
return i
return -1
4.https://leetcode.com/problems/valid-anagram/
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
"""
Given two strings s and t , write a function to determine if t is an anagram of s.
:param s:
:param t:
:return:
>>> solution = Solution()
>>> solution.isAnagram("anagram", "nagaram")
True
>>> solution.isAnagram("rat", "car")
False
"""
s_hash, t_hash = [0] * 26, [0]*26
for c in s:
s_hash[ord(c)-ord('a')] += 1
for c in t:
t_hash[ord(c)-ord('a')] += 1
return s_hash == t_hash
5.https://leetcode.com/problems/simplify-path/
class Solution:
def simplifyPath(self, path: str) -> str:
"""
Given an absolute path for a file (Unix-style), simplify it.
Or in other words, convert it to the canonical path.
In a UNIX-style file system, a period . refers to the current directory.
Furthermore, a double period .. moves the directory up a level.
For more information, see: Absolute path vs relative path in Linux/Unix
Note that the returned canonical path must always begin with a slash /,
and there must be only a single slash / between two directory names.
The last directory name (if it exists) must not end with a trailing /.
Also, the canonical path must be the shortest string representing the absolute path.
:param path:
:return:
>>> solution = Solution()
>>> solution.simplifyPath('/home/')
'/home'
>>> solution.simplifyPath('/../')
'/'
>>> solution.simplifyPath('/home//foo/')
'/home/foo'
>>> solution.simplifyPath('/a/./b/../../c/')
'/c'
>>> solution.simplifyPath('/a/../../b/../c//.//')
'/c'
>>> solution.simplifyPath('/a//b////c/d//././/..')
'/a/b/c'
"""
stack = []
for p in path.split('/'):
if p == '..':
if stack:
stack.pop()
elif p and p != '.':
stack.append(p)
return '/' + '/'.join(stack)
6.https://leetcode.com/problems/multiply-strings/
class Solution:
def multiply(self, num1: str, num2: str) -> str:
"""
Given two non-negative integers num1 and num2 represented as strings,
return the product of num1 and num2, also represented as a string.
Note:
The length of both num1 and num2 is < 110.
Both num1 and num2 contain only digits 0-9.
Both num1 and num2 do not contain any leading zero, except the number 0 itself.
You must not use any built-in BigInteger library or convert the inputs to integer directly.
:param num1:
:param num2:
:return:
>>> solution = Solution()
>>> solution.multiply('2', '3')
'6'
>>> solution.multiply('123', '456')
'56088'
"""
if num1 == '0' or num2 == '0':
return '0'
num1 = [ord(c) - ord('0') for c in num1][::-1]
num2 = [ord(c) - ord('0') for c in num2][::-1]
ans = [0]*(len(num1)+len(num2))
for i, n1 in enumerate(num1):
for j, n2 in enumerate(num2):
div, mod = divmod(ans[i+j] + n1*n2, 10)
ans[i+j] = mod
ans[i+j+1] += div
pt = 0
ans = ans[::-1]
while pt < len(ans) and ans[pt] == 0:
pt += 1
return ''.join(map(str, ans[pt:]))
7.https://leetcode.com/problems/regular-expression-matching/
思路:
用2维布尔数组,dp[i][j]的含义是s[0:i+1] 与 s[0:j+1]是否匹配。
1.p[j] == s[i] : dp[i][j] = dp[i-1][j-1]
2.if p[j] == ‘.’ : dp[i][j] = dp[i-1][j-1];
3.if p[j] == ‘*’: 存在如下两种情况:
if p[j-1] != s[i] : dp[i][j] = dp[i][j-2] // 此种情况,a*算作空字符串
if p[j-1] == s.[i] or p[i-1] == '.':
dp[i][j] = dp[i-1][j] // a* 算作多个a
dp[i][j] = dp[i][j-1] // a* 算作一个a
dp[i][j] = dp[i][j-2] // a* 算作空字符串
代码:
class Solution:
def isMatch(self, s: str, p: str) -> bool:
"""
Given an input string (s) and a pattern (p),
implement regular expression matching with support for '.' and '*'.
'.' Matches any single character.
'*' Matches zero or more of the preceding element.
The matching should cover the entire input string (not partial).
Note:
s could be empty and contains only lowercase letters a-z.
p could be empty and contains only lowercase letters a-z, and characters like . or *.
:param s:
:param p:
:return:
>>> solution = Solution()
>>> solution.isMatch('aa', 'a')
False
>>> solution.isMatch('aa', 'a*')
True
>>> solution.isMatch('aab', 'c*a*b')
True
>>> solution.isMatch('mississippi', 'mis*is*p*.')
False
>>> solution.isMatch('mississippi', 'mis*is*ip*.')
True
>>> solution.isMatch('ab', '.*c')
False
>>> solution.isMatch('aasdfasdfasdfasdfas', 'aasdf.*asdf.*asdf.*asdf.*s')
True
"""
dp = [[False for _ in range(len(p)+1)] for _ in range(len(s)+1)]
dp[0][0] = True
for j in range(1, len(p)+1):
if j > 1 and p[j-1] == '*' and dp[0][j-2]:
dp[0][j] = True
for i in range(1, len(s)+1):
for j in range(1, len(p)+1):
if s[i-1] == p[j-1] or p[j-1] == '.':
dp[i][j] = dp[i-1][j-1]
elif p[j-1] == '*':
if p[j-2] != s[i-1] and p[j-2] != '.':
dp[i][j] = dp[i][j-2]
elif p[j-2] == s[i-1] or p[j-2] == '.':
dp[i][j] = dp[i][j-1] or dp[i-1][j] or dp[i][j-2]
return dp[-1][-1]
if __name__ == '__main__':
import doctest
doctest.testmod()
8.https://leetcode.com/problems/wildcard-matching/
思路: 有限状态机
代码:
class Solution:
def isMatch(self, s: str, p: str) -> bool:
"""
Given an input string (s) and a pattern (p),
implement wildcard pattern matching with support for '?' and '*'.
'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence).
The matching should cover the entire input string (not partial).
:param s:
:param p:
:return:
>>> solution = Solution()
>>> solution.isMatch('aa', 'a')
False
>>> solution.isMatch('aa', '*')
True
>>> solution.isMatch('cb', '?a')
False
>>> solution.isMatch('adceb', '*a*b')
True
>>> solution.isMatch('acdcb', 'a*c?b')
False
"""
transfer = {}
state = 0
for c in p:
if c == '*':
transfer[state, c] = state
else:
transfer[state, c] = state + 1
state += 1
accept = state
state = set([0])
for c in s:
state = set([transfer.get((at, token)) for at in state
for token in [c, '*', '?']])
return accept in state
9.https://leetcode.com/problems/longest-palindrome/
class Solution:
def longestPalindrome(self, s: str) -> int:
"""
Given a string which consists of lowercase or uppercase letters, find the length of the longest palindromes that can be built with those letters.
This is case sensitive, for example "Aa" is not considered a palindrome here.
Note:
Assume the length of given string will not exceed 1,010.
:param s:
:return:
>>> solution = Solution()
>>> solution.longestPalindrome('abccccdd')
7
>>> solution.longestPalindrome('civilwartestingwhetherthatnaptionoranynartionsoconceivedandsontofthepeoplebythepeopleforthepeopleshallnotperishfromtheearth')
115
"""
d = {}
for c in s:
d[c] = d.setdefault(c, 0) + 1
max_odd = 0
longest_num = 0
for v in d.values():
if v % 2 == 0:
longest_num += v
else:
longest_num += v - 1
max_odd = 1
return longest_num + max_odd
10.https://leetcode.com/problems/longest-palindromic-substring/
思路1:中心扩展法
中心扩展法的思路是,遍历到数组的某一个元素时,以这个元素为中心,向两边进行扩展。 如果两边的元素相同则继续扩展,否则停止扩展。如下,当遍历s=’babad’到下标s[2]=b时
b | a | b | a | d | |
1.以b中心左右扩展
b | a | b | a | d | |
2.b两边的元素扩展
b | a | b | a | d | |
3.扩展到两边元素不等时停止
这种算法,时间复杂度O(n^2),空间复杂度为O(1)。
b | a | a | b |
s=’baab’是一个回文串,然而找不到对称中心,这样以一个元素为中心向两边扩展就不好用了。 这里有一种比较方便的处理方式,就是对s=’baab’进行填充,比如说用#进行填充如下:
# | b | # | a | # | a | # | b | # |
这时s=’#b#a#a#b#’,长度就成为奇数了,就方便中心扩展法进行处理了。
代码1:
class Solution:
def longestPalindrome(self, s: str) -> str:
"""
Given a string s, find the longest palindromic substring in s.
You may assume that the maximum length of s is 1000.
:param s:
:return:
>>> solution = Solution()
>>> solution.longestPalindrome('babad')
'bab'
>>> solution.longestPalindrome('cbbd')
'bb'
"""
max_s = ''
t = '#'+'#'.join(s)+'#'
for i, c in enumerate(t):
low, high = i, i
while 0 <= low-1 and high + 1 < len(t) and t[low-1] == t[high+1]:
low = low - 1
high = high + 1
if len(t[low:high+1]) > len(max_s):
max_s = t[low:high+1]
return ''.join(max_s.split('#'))
思路2:动态规划方法
如果用f[i][j]保存子串从i 到j是否是回文子串。 那么在求f[i][j]的时候,如果j-i>=2时,如果 f[i][j] 为回文,那么f[i+1][j-1],也一定为回文。 否则f[i][j]不为回文。如下s=’abba’:
a | b | b | a |
f[0][3] (‘abba’) 为True,那么f[1][2] (’bb’)一定为True
a | b | a | a |
f[1][2] (’ba’) 为False,那么f[0][3] (‘abaa’) 一定为False
这样递推公式为:
- 如果 i == j, f[i][j] = True
- 如果 j == i+1, f[i][j] = (s[i] == s[j])
- 如果 j > i+1, f[i][j] = (s[i] == s[j] and f[i+1][j-1])
时间复杂度O(n^2),空间复杂度O(n^2)。
class Solution:
def longestPalindromeV02(self, s: str) -> str:
length = len(s)
max_s = ''
dp = [[True for _ in range(length)] for _ in range(length)]
for i in range(length):
for j in range(length-i):
if i + j < length:
if i+j == j+1 and s[j] != s[j+i]:
dp[j][j+i] = False
elif i+j > j+1 and not(dp[j+1][j+i-1] and s[j] == s[j+i]):
dp[j][j+i] = False
if dp[j][j+i] and i+1 > len(max_s):
max_s = s[j:j+i+1]
return max_s
思路3:Manacher算法
https://segmentfault.com/a/1190000003914228#comment-area
https://en.wikipedia.org/wiki/Longest_palindromic_substring
class Solution:
def longestPalindrome(self, in_s: str) -> str:
s = '#' + '#'.join(in_s) + '#'
s_len = len(s)
r = [0 for _ in range(s_len)]
pos = 0
max_right = 0
max_s = ''
for i, c in enumerate(s):
if i < max_right:
r[i] = min(max_right-i, r[2*pos-i])
else:
r[i] = 1
while i-r[i] >= 0 and r[i]+i < s_len and s[i-r[i]] == s[i+r[i]]:
r[i] += 1
if r[i]+i-1 > max_right:
max_right = r[i]+i-1
pos = i
if len(s[i-r[i]+1:i+r[i]]) > len(max_s):
max_s = s[i-r[i]+1:i+r[i]]
return ''.join(max_s.split('#'))
11.https://leetcode.com/problems/zigzag-conversion/
class Solution:
def convert(self, s: str, numRows: int) -> str:
"""
The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)
P A H N
A P L S I I G
Y I R
And then read line by line: "PAHNAPLSIIGYIR"
Write the code that will take a string and make this conversion given a number of rows:
string convert(string s, int numRows);
:param s:
:param numRows:
:return:
>>> solution = Solution()
>>> solution.convert('PAYPALISHIRING', 3)
'PAHNAPLSIIGYIR'
>>> solution.convert('PAYPALISHIRING', 4)
'PINALSIGYAHRPI'
>>> solution.convert('', 1)
''
>>> solution.convert('A', 1)
'A'
"""
if numRows == 1 or numRows >= len(s):
return s
L = [''] * numRows
index, step = 0, 1
for x in s:
L[index] += x
if index == 0:
step = 1
elif index == numRows - 1:
step = -1
index += step
return ''.join(L)
12.https://leetcode.com/problems/length-of-last-word/
class Solution:
def lengthOfLastWord(self, s: str) -> int:
res = s.split()
if not res:
return 0
return len(res[-1])
13.https://leetcode.com/problems/valid-palindrome/
class Solution:
def isPalindrome(self, s: str) -> bool:
"""
Determine whether an integer is a palindrome.
An integer is a palindrome when it reads the same backward as forward.
:param s:
:return:
>>> solution = Solution()
>>> solution.isPalindrome('A man, a plan, a canal: Panama')
True
>>> solution.isPalindrome('race a car')
False
"""
r = ''.join(e for e in s if e.isalnum()).lower()
return r == r[::-1]
if __name__ == '__main__':
import doctest
doctest.testmod()
14.https://leetcode.com/problems/isomorphic-strings/
class Solution:
def isIsomorphic(self, s: str, t: str) -> bool:
"""
Given two strings s and t, determine if they are isomorphic.
Two strings are isomorphic if the characters in s can be replaced to get t.
All occurrences of a character must be replaced with another character
while preserving the order of characters. No two characters may map to
the same character but a character may map to itself.
:param s:
:param t:
:return:
>>> solution = Solution()
>>> solution.isIsomorphic('egg', 'add')
True
>>> solution.isIsomorphic('foo', 'bar')
False
>>> solution.isIsomorphic('paper', 'title')
True
"""
return len(set(zip(s, t))) == len(set(s)) == len(set(t))
15.https://leetcode.com/problems/palindromic-substrings/
class Solution:
def countSubstrings(self, s: str) -> int:
"""
Given a string, your task is to count how many palindromic substrings in this string.
The substrings with different start indexes or end indexes are counted as different
substrings even they consist of same characters.
:param s:
:return:
>>> solution = Solution()
>>> solution.countSubstrings('abc')
3
>>> solution.countSubstrings('aaa')
6
"""
length = len(s)
dp = [[False for _ in range(length)] for _ in range(length)]
cnt = 0
for i in range(0, length):
for j in range(length-i):
if j == j+i:
dp[j][j+i] = True
cnt += 1
elif j+i == j+1 and s[j] == s[j+i]:
dp[j][j+i] = True
cnt += 1
elif j+1 <= length and j+i-1 >= 0 and s[j] == s[j+i]:
dp[j][j+i] = dp[j+1][j+i-1]
if dp[j][j+i]:
cnt += 1
return cnt
16.https://leetcode.com/problems/count-binary-substrings/
class Solution:
def countBinarySubstrings(self, s: str) -> int:
"""
Give a string s, count the number of non-empty (contiguous) substrings
that have the same number of 0's and 1's, and all the 0's and all the 1's
in these substrings are grouped consecutively.
Substrings that occur multiple times are counted the number of times they occur.
:param s:
:return:
>>> solution = Solution()
>>> solution.countBinarySubstrings('00110011')
6
>>> solution.countBinarySubstrings('10101')
4
>>> solution.countBinarySubstrings('00110')
3
"""
s = list(map(len, s.replace('01', '0 1').replace('10', '1 0').split()))
return sum(min(a, b) for a, b in zip(s, s[1:]))
17.https://leetcode.com/problems/text-justification/
18.https://leetcode.com/problems/concatenated-words/
19.https://leetcode.com/problems/shortest-palindrome/
20.https://leetcode.com/problems/palindrome-pairs/
21.https://leetcode.com/problems/longest-palindromic-subsequence/
22.https://leetcode.com/problems/string-to-integer-atoi/
23.https://leetcode.com/problems/valid-palindrome-ii/
24.https://leetcode.com/problems/palindrome-linked-list/
https://leetcode-cn.com/problemset/top/
https://leetcode-cn.com/problemset/50/
位操作
基础知识
异或操作
x ^ 0 = x
x ^ 1s = ~x // 1s = ~0
x ^ (~x) = 1s
x ^ x = 0
a ^ b = c -> a ^c = b, b ^ c = a
a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c
常用操作
-
x&1 == 1 or == 0 判断奇偶
-
x=x&(x-1) 清零最低位1
-
x&-x 得到最低位的1
复杂操作
- 将x最右边n位清零 x&(~0«n)
- 获取x的第n位值 (x»n)&1
- 获取x的第n位幂值 x&(1«(n-1))
-
仅将第n位置位1 x (1«n) - 仅将第n位置位0 x&(~(1«n))
- 将x最高位至第n位清零 x&((1«n)-1)
- 将第n位至第0位清零 x&(~((1«(n+1))-1))
题目
分类链接
https://leetcode.com/tag/bit-manipulation/
必做题目
https://leetcode.com/problems/single-number/
class Solution:
def singleNumber(self, nums: List[int]) -> int:
res = 0
for n in nums:
res ^=n
return res
def singleNumber(self, nums: List[int]) -> int:
from functools import reduce
return reduce(operator.xor, nums)
func singleNumber(nums []int) int {
res := 0
for _, v := range nums {
res ^= v
}
return res
}
https://leetcode.com/problems/reverse-bits
class Solution:
def reverseBits(self, n: int) -> int:
return int(bin(n)[2:].zfill(32)[::-1], 2)
def reverseBits01(self, n: int) -> int:
for i in range(16):
if (n>>i & 1) != (n >> (31-i) & 1):
n ^= ((1<<i) | (1<<(31-i)))
return n
def reverseBits02(self, n: int) -> int:
return int("{:032b}".format(n)[::-1], 2)
func reverseBits(num uint32) uint32 {
var res uint32
for i := 0; i < 32; i++ {
res = (res << 1) + (num & 1)
num = num >> 1
}
return res
}
func reverseBitsV01(num uint32) uint32 {
var res uint32
for i := 0; i < 32; i++ {
res = res*2 + num%2
num = num / 2
}
return res
}
func reverseBitsV02(num uint32) uint32 {
num = (num >> 16) | (num << 16)
num = ((num & 0xff00ff00) >> 8) | ((num & 0x00ff00ff) << 8)
num = ((num & 0xf0f0f0f0) >> 4) | ((num & 0x0f0f0f0f) << 4)
num = ((num & 0xcccccccc) >> 2) | ((num & 0x33333333) << 2)
num = ((num & 0xaaaaaaaa) >> 1) | ((num & 0x55555555) << 1)
return num
}
https://leetcode.com/problems/number-of-1-bits/
class Solution(object):
def hammingWeight(self, n):
"""
:type n: int
:rtype: int
"""
res = 0
while n != 0:
n &= n-1
res += 1
return res
func hammingWeight(num uint32) int {
res := 0
for num > 0 {
num &= num - 1
res++
}
return res
}
https://leetcode.com/problems/power-of-four
class Solution:
def isPowerOfFour(self, num: int) -> bool:
return num >0 and num&(num-1)==0 and len(bin(num)[3:])%2 == 0
func isPowerOfFour(num int) bool {
return num > 0 && (num & (num -1) ==0) && (num-1) % 3 == 0
}
https://leetcode.com/problems/sum-of-two-integers
class Solution:
def getSum(self, a: int, b: int) -> int:
MASK = 0xFFFFFFFF
MAX = 0x7FFFFFFF
while b != 0:
a, b = (a ^ b) & MASK, ((a & b) << 1) & MASK
return a if a <= MAX else ~(a^MASK)
func getSum(a int, b int) int {
for b != 0 {
a, b = a ^ b, ((a & b) << 1)
}
return a
}
https://leetcode.com/problems/convert-a-number-to-hexadecimal
class Solution:
def toHex(self, num: int) -> str:
if num == 0:
return '0'
res = ''
for i in range(8):
res = '0123456789abcdef'[num&15] + res
num >>= 4
return res.lstrip('0')
func toHex(num int) string {
const (
hexStr = "0123456789abcdef"
mask = 0xf
)
var res = make([]byte, 8)
var nonZeroIndex = 7
for i := 7; i >= 0; i-- {
val := num & mask
if val > 0 {
nonZeroIndex = i
}
res[i] = hexStr[val]
num >>= 4
}
return string(res[nonZeroIndex:])
}
https://leetcode.com/problems/subsets/
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
nums_len = len(nums)
max_num = 2**nums_len
res = list()
for i in range(max_num):
b = '0'*(nums_len-len(bin(i)[2:])) + bin(i)[2:]
t = list()
for j, v in enumerate(b):
if v == '1':
t.append(nums[j])
res.append(t)
return res
func subsets(nums []int) [][]int {
res := make([][]int, 1)
for _, num := range nums {
for _, sub := range res {
clone := make([]int, len(sub), len(sub)+1)
copy(clone, sub)
clone = append(clone, num)
res = append(res, clone)
}
}
return res
}
https://leetcode.com/problems/single-number-ii/
class Solution:
def singleNumber(self, nums: List[int]) -> int:
ones, twos, threes = 0, 0, 0
for num in nums:
twos |= ones & num
ones ^= num
threes = ones & twos
ones &= ~threes
twos &= ~threes
return ones
func singleNumber(nums []int) int {
ones, twos, threes := 0, 0, 0
for i := 0; i < len(nums); i++ {
twos |= ones & nums[i]
ones ^= nums[i]
threes = ones & twos
ones = ones &^ threes
twos = twos &^ threes
}
return ones
}
https://leetcode.com/problems/repeated-dna-sequences
class Solution:
def findRepeatedDnaSequences(self, s: str) -> List[str]:
res = set()
keys = set()
for i in range(len(s)-9):
if s[i:i+10] in keys:
res.add(s[i:i+10])
else:
keys.add(s[i:i+10])
return list(res)
func isExist(strs []string, s string) bool {
for i := 0; i < len(strs); i++ {
if strs[i] == s {
return true
}
}
return false
}
func findRepeatedDnaSequences(s string) []string {
var key int
res := []string{}
keys := map[int]bool{}
if len(s) < 10 {
return res
}
for i := 0; i < 10; i++ {
key <<= 3
key |= int(s[i]) & 7
key = key & 0x3fffffff
}
keys[key] = true
for i := 10; i < len(s); i++ {
key <<= 3
key |= int(s[i]) & 7
key = key & 0x3fffffff
_, exist := keys[key]
if exist && !(isExist(res, s[i-9:i+1])) {
res = append(res, s[i-9:i+1])
} else {
keys[key] = true
}
}
return res
}
func findRepeatedDnaSequences(s string) []string {
rec := make(map[string]int, len(s)-9)
res := []string{}
if len(s) < 10 {
return res
}
for i := 0; i+10 <= len(s); i++ {
sub := s[i:i+10]
if v, _ := rec[sub]; v == 1 {
res = append(res, sub)
}
rec[sub]++
}
return res
}
https://leetcode.com/problems/bitwise-and-of-numbers-range/
class Solution:
def rangeBitwiseAnd(self, m: int, n: int) -> int:
while m < n:
n &= n-1
return n
func rangeBitwiseAnd(m int, n int) int {
for m < n {
n &= n-1
}
return n
}
https://leetcode.com/problems/single-number-iii
class Solution:
def singleNumber(self, nums: List[int]) -> List[int]:
from functools import reduce
import operator
xor = reduce(operator.xor, nums)
xor = xor & (-xor)
a, b = 0, 0
for num in nums:
if num & xor:
a ^= num
else:
b ^= num
return [a, b]
func singleNumber(nums []int) []int {
var res = []int{0, 0}
diff := 0
numLen := len(nums)
for i := 0; i < numLen; i++ {
diff ^= nums[i]
}
diff &= -diff
for i := 0; i < numLen; i++ {
if (diff & nums[i]) == 0 {
res[0] ^= nums[i]
} else {
res[1] ^= nums[i]
}
}
return res
}
https://leetcode.com/problems/maximum-product-of-word-lengths/
class Solution:
def maxProduct(self, words: List[str]) -> int:
d = {sum(1<<(ord(c)-ord('a')) for c in set(w)):len(w) for w in sorted(words, key=len)}
return max([d[i]*d[j] for i in d for j in d if not i&j] or [0])
func helper(word string) int {
t := 0
for _, c := range word {
t |= (1 << (uint(c) - uint('a')))
}
return t
}
func maxProduct(words []string) int {
wLen := len(words)
wTable := make([]int, wLen)
for i := 0; i < wLen; i++ {
wTable[i] = helper(words[i])
}
max := 0
for i := 0; i < wLen; i++ {
li := len(words[i])
for j := i + 1; j < wLen; j++ {
if (wTable[i] & wTable[j]) == 0 {
lj := len(words[j])
if li*lj > max {
max = li * lj
}
}
}
}
return max
}
https://leetcode-cn.com/problems/counting-bits/
class Solution:
def countBits(self, num: int) -> List[int]:
res = [0]
while len(res) < num + 1:
res += [x+1 for x in res]
return res[:num+1]
func countBits(num int) []int {
res := make([]int, num+1)
res[0] = 0
for i := 1; i < num+1; i++ {
res[i] = res[i&(i-1)] + 1
}
return res
}
https://leetcode.com/problems/utf-8-validation
class Solution:
def validUtf8(self, data: List[int]) -> bool:
count = 0
for i in data:
if count == 0:
if (i>>3) == 0b11110:
count = 3
elif (i>>4) == 0b1110:
count = 2
elif (i>>5) == 0b110:
count = 1
elif (i>>7) != 0:
return False
else:
if (i>>6) != 0b10:
return False
count -= 1
return count == 0
func validUtf8(data []int) bool {
count := 0
dataLen := (len(data))
for i := 0; i < dataLen; i++ {
if count == 0 {
if (data[i] >> 3) == 0x1e {
count = 3
} else if (data[i] >> 4) == 0xe {
count = 2
} else if (data[i] >> 5) == 0x6 {
count = 1
} else if (data[i] >> 7) != 0 {
return false
}
} else if (data[i] >> 6) == 0x2 {
count--
} else {
return false
}
}
return count == 0
}
https://leetcode.com/problems/integer-replacement/
class Solution:
def integerReplacement(self, n: int) -> int:
cnt = 0
while n != 1:
if n & 1:
if ((n >>1) & 1) and n != 3:
n = n+1
else:
n = n-1
else:
n >>= 1
cnt += 1
return cnt
func integerReplacement(n int) int {
cnt := 0
for n != 1 {
if n&1 == 1 {
if n != 3 && (n&0x3) == 0x3 {
n++
} else {
n--
}
cnt++
} else {
n >>= 1
cnt++
}
}
return cnt
}
https://leetcode.com/problems/maximum-xor-of-two-numbers-in-an-array/
class Solution:
def findMaximumXOR(self, nums: List[int]) -> int:
ans = 0
for i in range(32)[::-1]:
ans <<= 1
prefixes = { num >> i for num in nums}
ans += any(ans ^ 1 ^ p in prefixes for p in prefixes)
return ans
func findMaximumXOR(nums []int) int {
ans := 0
numsLen := len(nums)
for i := 31; i >= 0; i-- {
ans <<= 1
prefixes := make(map[int]bool, numsLen)
for j := 0; j < numsLen; j++ {
preNum := nums[j] >> uint(i)
prefixes[preNum] = true
}
for k := range prefixes {
if prefixes[ans^1^k] {
ans++
break
}
}
}
return ans
}
https://leetcode.com/problems/total-hamming-distance
class Solution:
def totalHammingDistance(self, nums: List[int]) -> int:
return sum([b.count('0')*b.count('1') for b in zip(*map("{:032b}".format, nums))])
func totalHammingDistance(nums []int) int {
numLen := len(nums)
sum := 0
for j := 0; j < 32; j++ {
ones := 0
for i := 0; i < numLen; i++ {
ones += (nums[i] >> uint(j)) & 1
}
sum += ones * (numLen - ones)
}
return sum
}
https://leetcode.com/problems/bitwise-ors-of-subarrays
class Solution:
def subarrayBitwiseORs(self, A: List[int]) -> int:
ans = set()
cur = {0}
for x in A:
cur = {y|x for y in cur} | {x}
ans |= cur
return len(ans)
func subarrayBitwiseORs(A []int) int {
ans := map[int]bool{}
cur := map[int]bool{0: true}
ALen := len(A)
for i := 0; i < ALen; i++ {
t := make(map[int]bool, len(cur)+1)
for k := range cur {
t[k|A[i]] = true
ans[k|A[i]] = true
}
t[A[i]] = true
ans[A[i]] = true
cur = t
}
return len(ans)
}
https://leetcode.com/problems/maximum-of-absolute-value-expression/
class Solution:
def maxAbsValExpr(self, arr1: List[int], arr2: List[int]) -> int:
A, B, C, D= [], [], [], []
for i in range(len(arr1)):
x, y = arr1[i], arr2[i]
A.append(x + y + i)
B.append(x + y - i)
C.append(x - y + i)
D.append(x - y - i)
a = max(A) - min(A)
b = max(B) - min(B)
c = max(C) - min(C)
d = max(D) - min(D)
return max(a, b, c, d)
func findMaxMin(arr []int) (int, int) {
max, min := arr[0], arr[0]
for i := 0; i < len(arr); i++ {
if arr[i] > max {
max = arr[i]
}
if arr[i] < min {
min = arr[i]
}
}
return max, min
}
func maxAbsValExpr(arr1 []int, arr2 []int) int {
arrLen := len(arr1)
A, B, C, D := make([]int, arrLen), make([]int, arrLen), make([]int, arrLen), make([]int, arrLen)
for i := 0; i < arrLen; i++ {
x, y := arr1[i], arr2[i]
A[i] = x + y + i
B[i] = x + y - i
C[i] = x - y + i
D[i] = x - y - i
}
Amax, Amin := findMaxMin(A)
Bmax, Bmin := findMaxMin(B)
Cmax, Cmin := findMaxMin(C)
Dmax, Dmin := findMaxMin(D)
max, _ := findMaxMin([]int{Amax - Amin, Bmax - Bmin, Cmax - Cmin, Dmax - Dmin})
return max
}
https://leetcode.com/problems/maximum-length-of-a-concatenated-string-with-unique-characters
class Solution:
def maxLength(self, arr: List[str]) -> int:
dp = [set()]
for a in arr:
if len(set(a)) < len(a): continue
a = set(a)
for c in dp:
if a&c: continue
dp.append(a|c)
return max(len(a) for a in dp)
func stringToBinary(s string) (int, bool) {
sLen := len(s)
res := 0
repeated := false
for i := 0; i < sLen; i++ {
t := 1 << (uint(s[i]) - uint('a'))
if t&res != 0 {
repeated = true
}
res |= t
}
return res, repeated
}
func maxLength(arr []string) int {
dp := map[int]int{}
arrLen := len(arr)
for i := 0; i < arrLen; i++ {
b, r := stringToBinary(arr[i])
if r {
continue
}
dp[b] = len(arr[i])
for k, v := range dp {
if k&b == 0 {
dp[k|b] = v + len(arr[i])
}
}
}
max := 0
for _, v := range dp {
if v > max {
max = v
}
}
return max
}
https://leetcode.com/problems/smallest-sufficient-team/
class Solution:
def smallestSufficientTeam(self, req_skills: List[str], people: List[List[str]]) -> List[int]:
n, m = len(req_skills), len(people)
key = {v:i for i, v in enumerate(req_skills)}
dp = {0:[]}
for i, p in enumerate(people):
skill = 0
for k in p:
if k in key:
skill |= 1 << key[k]
if skill == 0: continue
if skill in dp and len(dp[skill]) == 1: continue
for k, need in list(dp.items()):
with_him = skill | k
if with_him == k: continue
if with_him not in dp or len(dp[with_him]) > len(need) + 1:
dp[with_him] = need + [i]
return dp[(1 << n) - 1]
func smallestSufficientTeam(reqSkills []string, people [][]string) []int {
dp := map[int][]int{0: {}}
peopleLen := len(people)
reqMap := map[string]int{}
reqLen := len(reqSkills)
for i := 0; i < reqLen; i++ {
reqMap[reqSkills[i]] = 1 << uint(i)
}
for i := 0; i < peopleLen; i++ {
jLen := len(people[i])
if jLen == 0 {
continue
}
skill := 0
for j := 0; j < jLen; j++ {
skill |= reqMap[people[i][j]]
}
if len(dp[skill]) == 1 {
continue
}
for k, v := range dp {
withHim := k | skill
if withHim == k {
continue
}
if len(dp[withHim]) == 0 || len(dp[withHim]) > len(v)+1 {
if len(v) > 0 {
t := make([]int, len(v), len(v)+1)
copy(t, v)
dp[withHim] = append(t, i)
} else {
dp[withHim] = []int{i}
}
}
}
}
return dp[(1<<uint(reqLen))-1]
}
https://leetcode.com/problems/number-of-valid-words-for-each-puzzle
class Solution:
# [1] 开始
def getMask(self, word):
mask = 0
for c in word:
mask |= 1 << (ord(c) - ord('a'))
return mask
# [1] 结束
def findNumOfValidWords(self, words: List[str], puzzles: List[str]) -> List[int]:
# [2] 开始
words = [self.getMask(w) for w in words]
d = {}
for w in words:
d[w] = d.get(w, 0) + 1
# [2] 结束
ans = []
for p in puzzles:
mask = self.getMask(p)
sub_mask = mask
head_mask = 1 << (ord(p[0]) - ord('a'))
cnt = 0
# [3] 开始
while sub_mask:
# [4] 开始
if sub_mask & head_mask:
cnt += d.get(sub_mask, 0)
# [4] 结束
sub_mask = (sub_mask-1)&mask
# [3] 结束
ans.append(cnt)
return ans
func binaryWord(word string) int {
wordLen := len(word)
res := 0
for i := 0; i < wordLen; i++ {
res |= 1 << (uint(word[i]) - uint('a'))
}
return res
}
func findNumOfValidWords(words []string, puzzles []string) []int {
wordsLen := len(words)
puzzlesLen := len(puzzles)
ans := make([]int, puzzlesLen)
wordMap := make(map[int]int, wordsLen)
for i := 0; i < wordsLen; i++ {
wordMap[binaryWord(words[i])]++
}
for i := 0; i < puzzlesLen; i++ {
mask := binaryWord(puzzles[i])
subMask := mask
headMask := 1 << (uint(puzzles[i][0]) - uint('a'))
for subMask != 0 {
if (headMask & subMask) != 0 {
ans[i] += wordMap[subMask]
}
subMask = (subMask - 1) & mask
}
}
return ans
}
https://leetcode.com/problems/maximum-score-words-formed-by-letters
class Solution:
def maxScoreWords(self, words: List[str], letters: List[str], score: List[int]) -> int:
from collections import Counter
words_score = [sum(score[ord(c)-ord('a')] for c in word) for word in words]
words_counter = [Counter(word) for word in words]
self.max_score = 0
def dfs(start, current_score, letter_counter):
if current_score+sum(words_score[start:]) <= self.max_score:
return
self.max_score = max(self.max_score, current_score)
for i, w_cnt in enumerate(words_counter[start:], start):
if all(n <= letter_counter.get(c, 0) for c, n in w_cnt.items()):
dfs(i+1, current_score+words_score[i], {c:n-w_cnt.get(c, 0) for c, n in letter_counter.items()})
dfs(0, 0, Counter(letters))
return self.max_score
func wordCount(word string) map[byte]int {
wordLen := len(word)
res := map[byte]int{}
for i := 0; i < wordLen; i++ {
res[byte(word[i])]++
}
return res
}
func wordScore(word string, score []int) int {
res := 0
wordLen := len(word)
for i := 0; i < wordLen; i++ {
res += score[int(word[i])-int('a')]
}
return res
}
func getMinusMap(counter map[byte]int, letters map[byte]int) (map[byte]int, bool) {
res := map[byte]int{}
isValid := true
for k, v := range letters {
res[k] = v - counter[k]
if res[k] < 0 {
isValid = false
}
}
for k := range counter {
_, isExist := res[k]
if !isExist {
isValid = false
}
}
return res, isValid
}
func dfs(start int, score int, letters map[byte]int, wordsLen int, wordsScore []int, wordsCounter []map[byte]int, maxScore *int) {
tSum := 0
for i := start; i < wordsLen; i++ {
tSum += wordsScore[i]
}
if (score + tSum) <= *maxScore {
return
}
if score > *maxScore {
*maxScore = score
}
for i := start; i < wordsLen; i++ {
newLetters, isValid := getMinusMap(wordsCounter[i], letters)
if isValid {
dfs(i+1, score+wordsScore[i], newLetters, wordsLen, wordsScore, wordsCounter, maxScore)
}
}
}
func maxScoreWords(words []string, letters []byte, score []int) int {
wordsLen := len(words)
wordsCounter := make([]map[byte]int, wordsLen)
wordsScore := make([]int, wordsLen)
for i := 0; i < wordsLen; i++ {
wordsCounter[i] = wordCount(words[i])
wordsScore[i] = wordScore(words[i], score)
}
maxScore := 0
lettersMap := map[byte]int{}
for _, v := range letters {
lettersMap[byte(v)]++
}
dfs(0, 0, lettersMap, wordsLen, wordsScore, wordsCounter, &maxScore)
return maxScore
}
额外练习
https://leetcode.com/problems/power-of-two/
class Solution:
def isPowerOfTwo(self, n: int) -> bool:
return n > 0 and not n & (n-1)
func isPowerOfTwo(n int) bool {
return n > 0 && n & (n-1) == 0
}
https://leetcode.com/problems/missing-number
class Solution:
def missingNumber(self, nums: List[int]) -> int:
return sum(range(len(nums)+1)) - sum(nums)
func missingNumber(nums []int) int {
total := 0
for i, v := range nums {
total ^= i ^ v
}
total ^= len(nums)
return total
}
https://leetcode.com/problems/find-the-difference/
class Solution:
def findTheDifference(self, s: str, t: str) -> str:
from functools import reduce
return chr(reduce(int.__xor__, map(ord, s+t)))
func findTheDifference(s string, t string) byte {
var res byte
for i := 0; i < len(s); i++ {
res ^= s[i]
}
for i := 0; i < len(t); i++ {
res ^= t[i]
}
return res
}
https://leetcode.com/problems/binary-watch/
class Solution:
def readBinaryWatch(self, num: int) -> List[str]:
return [f"{h}:{m:02d}" for h in range(12) for m in range(60) if (bin(h)+bin(m)).count('1') == num]
func readBinaryWatch(num int) []string {
var res []string
for i := 0; i < 12; i++ {
for j := 0; j < 60; j++ {
h := fmt.Sprintf("%b", i)
m := fmt.Sprintf("%b", j)
countOne := strings.Count(h, "1") + strings.Count(m, "1")
if countOne == num {
res = append(res, fmt.Sprintf("%d:%02d", i, j))
}
}
}
return res
}
https://leetcode.com/problems/pyramid-transition-matrix
class Solution:
def pyramidTransition(self, bottom: str, allowed: List[str]) -> bool:
from collections import defaultdict
from itertools import product
f = defaultdict(lambda:defaultdict(list))
for a, b, c in allowed:
f[a][b].append(c)
def pyramid(inner_bottom):
if len(inner_bottom) == 1:
return True
for i in product(*(f[a][b] for a, b in zip(inner_bottom, inner_bottom[1:]))):
if pyramid(i):
return True
return False
return pyramid(bottom)
https://leetcode.com/problems/maximum-number-of-occurrences-of-a-substring/
class Solution:
def maxFreq(self, s: str, maxLetters: int, minSize: int, maxSize: int) -> int:
length = len(s)
from collections import defaultdict, Counter
d = defaultdict(int)
for i in range(length-minSize+1):
t = s[i:i+minSize]
c = Counter(t)
if len(c) <= maxLetters:
d[t] += 1
return max(d.values()) if d else 0
func sLetterCnt(s string) int {
sMap := map[rune]bool{}
for _, c := range s {
sMap[c] = true
}
return len(sMap)
}
func max(f map[string]int) int {
m := 0
for _, v := range f {
if v > m {
m = v
}
}
return m
}
func maxFreq(s string, maxLetters int, minSize int, maxSize int) int {
freqMap := map[string]int{}
sLen := len(s)
for i := 0; i < sLen-minSize+1; i++ {
if sLetterCnt(s[i:i+minSize]) <= maxLetters {
freqMap[s[i:i+minSize]]++
}
}
return max(freqMap)
}