文章目录
- 2 双指针
- 2.1 【双指针】验证回文串
- 2.2 【双指针】判断子序列
- 2.3 【双指针】两数之和 II - 输入有序数组
- 2.4 【双指针】盛最多水的容器
- 2.5 【双指针】三数之和
- 3 滑动窗口
- 3.1 【双指针】长度最小的子数组
- 3.2 【滑动窗口】无重复字符的最长子串
- 3.3 【哈希表】串联所有单词的子串
- 3.4 【哈希表】最小覆盖子串
- 4 矩阵
- 4.1 【哈希表】有效的数独
- 4.2 【模拟】螺旋矩阵
- 4.3 【数学】旋转图像
- 4.4 【哈希】矩阵置零
- 4.5 【模拟】生命游戏
2 双指针
2.1 【双指针】验证回文串
题目地址:https://leetcode.cn/problems/valid-palindrome/description/?envType=study-plan-v2&envId=top-interview-150
详见代码。
class Solution:def isPalindrome(self, s: str) -> bool:newStr = ""s = s.lower()for c in s:if (c >= "a" and c <= "z") or (c >= "0" and c <= "9"):newStr += cleft, right = 0, len(newStr)-1while(left<=right):if newStr[left] != newStr[right]:return Falseleft += 1right -= 1return True
2.2 【双指针】判断子序列
题目地址:https://leetcode.cn/problems/is-subsequence/description/?envType=study-plan-v2&envId=top-interview-150
双指针挨个遍历 s s s和 t t t中的字符,看能否找到相对位置一致的字串。
class Solution:def isSubsequence(self, s: str, t: str) -> bool:s_len = len(s)t_len = len(t)s_index = 0if s_len == 0:return Trueif t_len == 0:return Falsefor i in range(t_len):if s_index == s_len:breakif s[s_index] == t[i]:s_index += 1if s_index == s_len:return Trueelse:return False
2.3 【双指针】两数之和 II - 输入有序数组
题目地址:https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/description/?envType=study-plan-v2&envId=top-interview-150
双指针前后遍历元素,找到合适的值。
class Solution:def twoSum(self, numbers: List[int], target: int) -> List[int]:left, right = 0, len(numbers)-1while(left < right):if numbers[left] + numbers[right] > target:right -= 1elif numbers[left] + numbers[right] < target:left += 1else:breakreturn [left+1,right+1]
2.4 【双指针】盛最多水的容器
题目地址:https://leetcode.cn/problems/container-with-most-water/description/?envType=study-plan-v2&envId=top-interview-150
木桶原理,水最多取决于左右边界更短的那个边界,所以希望最短边界尽可能长。
class Solution:def maxArea(self, height: List[int]) -> int:left, right = 0, len(height)-1max_water = 0while left < right:tmp_water = min(height[left],height[right])*(right-left)max_water = max(max_water,tmp_water)if height[left] <= height[right]:left += 1else:right -= 1return max_water
2.5 【双指针】三数之和
题目地址:https://leetcode.cn/problems/3sum/description/?envType=study-plan-v2&envId=top-interview-150
先排序,然后去重,每次固定一个数,在剩下的范围中用双指针找合为0的三元组。
class Solution:def threeSum(self, nums: List[int]) -> List[List[int]]:length = len(nums)ans = []if length < 3:return ansnums.sort()for i in range(length):if nums[i] > 0:return ansif i > 0 and nums[i] == nums[i-1]:continueleft = i + 1right = length - 1while left < right:if nums[i] + nums[left] + nums[right] == 0:ans.append([nums[i],nums[left],nums[right]])while left<right and nums[left] == nums[left+1]:left += 1while left<right and nums[right] == nums[right-1]:right -= 1left += 1right -= 1elif nums[i] + nums[left] + nums[right] < 0:left += 1else:right -= 1return ans
3 滑动窗口
3.1 【双指针】长度最小的子数组
题目地址:https://leetcode.cn/problems/minimum-size-subarray-sum/description/?envType=study-plan-v2&envId=top-interview-150
设置滑动窗口比较窗口内的数字之和与 t a r g e t target target,当满足条件时去掉窗口内首元素,将窗口右移,再次比较。
class Solution:def minSubArrayLen(self, target: int, nums: List[int]) -> int:length = len(nums)slow, fast = 0, 0sum, ans = 0, length+1while fast < length:sum += nums[fast]while sum >= target:ans = min(ans,fast-slow+1)sum -= nums[slow]slow += 1fast += 1return 0 if ans==length+1 else ans
3.2 【滑动窗口】无重复字符的最长子串
题目地址:https://leetcode.cn/problems/longest-substring-without-repeating-characters/description/?envType=study-plan-v2&envId=top-interview-150
详见代码。
class Solution:def lengthOfLongestSubstring(self, s: str) -> int:max_len = 0tmp_str = ""length = len(s)i = 0while i < length:if s[i] not in tmp_str:tmp_str += s[i]max_len = max(max_len,len(tmp_str))i += 1else:while s[i] in tmp_str:tmp_str = tmp_str[1:]return max_len
3.3 【哈希表】串联所有单词的子串
题目地址:https://leetcode.cn/problems/substring-with-concatenation-of-all-words/description/?envType=study-plan-v2&envId=top-interview-150
依次比较每个滑动窗口中单词的出现次数与 w o r d s words words是否一致即可。
class Solution:def findSubstring(self, s: str, words: List[str]) -> List[int]:word_len = len(words[0])word_num = len(words)window = word_len * word_numans = []cnt = {word:0 for word in words}word_cnt = cnt.copy()for word in words:word_cnt[word] += 1start = 0while start < len(s) - window + 1:tmp_cnt = cnt.copy()for i in range(start, start+window, word_len):tmp_word = s[i:i+word_len]if tmp_word in tmp_cnt:tmp_cnt[tmp_word] += 1else:breakif tmp_cnt == word_cnt:ans.append(start)start += 1return ans
3.4 【哈希表】最小覆盖子串
题目地址:https://leetcode.cn/problems/minimum-window-substring/description/?envType=study-plan-v2&envId=top-interview-150
- 不断增加使滑动窗口增大,直到窗口包含了t的所有元素;
- 不断增加使滑动窗口缩小,将不必要的元素排除在外,直到碰到一个必须包含的元记录此时滑动窗口的长度,并保存最小值;
- 再增加一个位置,这个时候滑动窗口肯定不满足条件了,继续从步骤一开始执行,寻找新的满足条件的滑动窗口。
class Solution:def minWindow(self, s: str, t: str) -> str:s_len, t_len, needCnt = len(s), len(t), len(t)need = collections.defaultdict(int)for c in t:need[c] += 1ans = (0,float('inf'))# 增加右边界使滑窗包含ti = 0for j,c in enumerate(s):if need[c] > 0:needCnt -= 1need[c] -= 1# 收缩左边界直到无法再去掉元素if needCnt == 0:while True:ch = s[i]if need[ch] == 0:breakelse:need[ch] += 1i += 1if j-i < ans[1]-ans[0]:ans = (i,j+1)# i多增加一个位置,准备开始下一次循环need[s[i]] += 1needCnt += 1i += 1return ""if ans[1]>s_len else s[ans[0]:ans[1]]
4 矩阵
4.1 【哈希表】有效的数独
题目地址:https://leetcode.cn/problems/valid-sudoku/description/?envType=study-plan-v2&envId=top-interview-150
将数组分别按照行、列、块构造哈希表,判断是否有重复元素。
class Solution:def isValidSudoku(self, board: List[List[str]]) -> bool:row = [[0] * 9 for _ in range(9)]col = [[0] * 9 for _ in range(9)]block = [[0] * 9 for _ in range(9)]for i in range(9):for j in range(9):if board[i][j] != '.':num = int(board[i][j]) - 1b = (i // 3) * 3 + j // 3if row[i][num] or col[j][num] or block[b][num]:return Falserow[i][num] = col[j][num] = block[b][num] = 1return True
4.2 【模拟】螺旋矩阵
题目地址:https://leetcode.cn/problems/spiral-matrix/description/?envType=study-plan-v2&envId=top-interview-150
设置上下左右边界,按照从左到右、从上到下、从右到左、从下到上的顺序挨个遍历即可。
class Solution:def spiralOrder(self, matrix: List[List[int]]) -> List[int]:l,r,t,b,res = 0,len(matrix[0])-1,0,len(matrix)-1,[]while True:# left to rightfor i in range(l,r+1):res.append(matrix[t][i])t += 1if t > b:break# top to bottomfor i in range(t,b+1):res.append(matrix[i][r])r -= 1if r < l:break# right to leftfor i in range(r,l-1,-1):res.append(matrix[b][i])b -= 1if b < t:break# bottom to topfor i in range(b,t-1,-1):res.append(matrix[i][l])l += 1if l > r:breakreturn res
4.3 【数学】旋转图像
题目地址:https://leetcode.cn/problems/rotate-image/description/?envType=study-plan-v2&envId=top-interview-150
主对角线翻转+左右翻转。
class Solution:def rotate(self, matrix: List[List[int]]) -> None:length = len(matrix)# 主对角线for i in range(length):for j in range(i+1,length):matrix[i][j],matrix[j][i] = matrix[j][i],matrix[i][j]# 左右for i in range(length):for j in range(length//2):matrix[i][j],matrix[i][length-j-1] = matrix[i][length-j-1],matrix[i][j]
4.4 【哈希】矩阵置零
题目地址:https://leetcode.cn/problems/set-matrix-zeroes/description/?envType=study-plan-v2&envId=top-interview-150
首先判断第一行和第一列是否存在零,然后分别用第一行和第一列的空间表示该行或者该列是否存在零,最后统一置零即可。
class Solution:def setZeroes(self, matrix: List[List[int]]) -> None:row = len(matrix)col = len(matrix[0])zero_first = [False,False]# 第一行是否有零for i in range(col):if matrix[0][i] == 0:zero_first[0] = Truebreak# 第一列是否有零for i in range(row):if matrix[i][0] == 0:zero_first[1] = Truebreak# 记录其他行和列的零for i in range(1,row):for j in range(1,col):if matrix[i][j] == 0:matrix[i][0] = matrix[0][j] = 0# 矩阵置零for i in range(1,row):for j in range(1,col):if matrix[i][0] == 0 or matrix[0][j] == 0:matrix[i][j] = 0if zero_first[0] == True:for i in range(col):matrix[0][i] = 0if zero_first[1] == True:for i in range(row):matrix[i][0] = 0
4.5 【模拟】生命游戏
题目地址:https://leetcode.cn/problems/game-of-life/description/?envType=study-plan-v2&envId=top-interview-150
卷积运算,计算每个细胞的得分。
import numpy as npclass Solution:def gameOfLife(self, board: List[List[int]]) -> None:row,col = len(board),len(board[0])# zero paddingboard_tmp = np.array([[0 for _ in range(col+2)] for _ in range(row+2)])board_tmp[1:row+1,1:col+1] = np.array(board)# kernelkernel = np.array([[1,1,1],[1,0,1],[1,1,1]])# convfor i in range(1,row+1):for j in range(1,col+1):tmp = np.sum(kernel * board_tmp[i-1:i+2,j-1:j+2])if board_tmp[i][j] == 1:if tmp < 2 or tmp > 3:board[i-1][j-1] = 0else:if tmp == 3:board[i-1][j-1] = 1