所有题目来源于LeetCode
1、哈希
1.1 两数之和
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出和为目标值 target 的那两个整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。你可以按任意顺序返回答案。
example:
输入:nums = [2,7,11,15],target = 9
输出:[0,1]
class Solution(object):
def twoSum(self, nums, target):
hashTable = dict()
for i,v in enumerate(nums):
if target - v in hashTable:
return i, hashTable[target - v]
hashTable[v] = i
1.2 字母异位词分组
给你一个字符串数组,请你将字母异位词组合在一起。可以按任意顺序返回结果列表。字母异位词是由重新排列源单词的所有字母得到的一个新单词。
example:
输入:strs = ["eat","tea","tan","ate","nat","bat"]
输出:[["bat"],["nat","tan"],["ate","eat","tea"]]
class Solution(object):
def groupAnagrams(self, strs):
hashTable = dict()
for key in strs:
val="".join(sorted(key))
hashTable[val]=hashTable.get(val,[])+[key]
return hashTable.values()
1.3 最长连续序列
给定一个未排序的整数数组 nums
,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。请你设计并实现时间复杂度为 O(n)
的算法解决此问题。
example:
输入:nums = [100,4,200,1,3,2]
输出:4
class Solution(object):
def longestConsecutive(self, nums):
nums = set(nums)
maxLength=0
for num in nums:
if num-1 not in nums:
startNumber = num+1
length=1
while startNumber in nums:
length+=1
startNumber+=1
maxLength=max(maxLength,length)
return maxLength
2、双指针
2.1 移动零
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
example:
输入:nums = [0,1,0,3,12]
输出:[1,3,12,0,0]
class Solution(object):
def moveZeroes(self, nums):
slow=0
for fast in range(len(nums)):
if nums[fast] != 0:
nums[slow],nums[fast]=nums[fast],nums[slow]
slow+=1
return nums
2.2 盛最多水的容器
给定一个长度为 n
的整数数组 height
。有 n
条垂线,第 i
条线的两个端点是 (i, 0)
和 (i, height[i])
。找出其中的两条线,使得它们与 x
轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。
题解:指针移动由最短边决定,无论长边移动后高度增加或者减少,都只能是装水量变少。
# 双指针
nums = [1, 8, 6, 2, 5, 4, 8, 3, 7]
left = 0
right = len(nums) - 1
maxContainer = 0
while left != right:
if nums[left] <= nums[right]:
maxContainer = max(maxContainer, (right - left) * nums[left])
left += 1
else:
maxContainer = max(maxContainer, (right - left) * nums[right])
right -= 1
print(maxContainer) # 49
2.3 三数之和
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
example:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
# 三数之和 a+b+c=0
nums = [-1, 0, 1, 2, -1, -4]
nums = sorted(nums)
arr = list()
n = len(nums)
for i in range(n):
if i > 0 and nums[i] == nums[i - 1]:
continue
target = -nums[i]
end = n - 1
for start in range(i + 1, n):
if start > i + 1 and nums[start] == nums[start - 1]:
continue
while start < end and nums[start] + nums[end] > target:
end -= 1
if start == end:
break
if nums[start] + nums[end] == target:
arr.append([nums[i], nums[start], nums[end]])
print(arr) # [[-1, -1, 2], [-1, 0, 1]]
2.4 接雨水
给定 n
个非负整数表示每个宽度为 1
的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
方法:使用单调栈。找到中间凹槽位置,并利用单调栈找出其左边的第一个最高柱子,右边的第一个最高柱子即循环遍历到的这一个元素。
# 单调栈(单增栈)
# 若当前遍历元素大于栈顶元素,则出现凹槽
height = [4, 2, 0, 3, 2, 5]
list = []
s = 0
for i, v in enumerate(height):
while list and v > height[list[-1]]:
top = list.pop()
if list:
left = list[-1]
wid = i - left - 1
hei = min(height[left], height[i]) - height[top]
s += wid * hei
else:
break
list.append(i)
print(s) # 9
3、滑动窗口
3.1 无重复字符的最长子串
给定一个字符串s,请你找出其中不含有重复字符的最长子串的长度。
example:
输入:s = "abcabcbb"
输出:3
s = 'abcabcbb'
left, right, length, max_length = 0, 0, 0, 0
hashTable = set()
while right < len(s):
if s[right] not in hashTable:
hashTable.add(s[right])
right += 1
length += 1
if length > max_length:
max_length = length
else:
while s[right] in hashTable:
hashTable.remove(s[left])
left += 1
length -= 1
hashTable.add(s[right])
right += 1
length += 1
print(max_length) # 3
3.2 找到字符串中所有字母异位词
给定两个字符串 s
和 p
,找到 s
中所有 p
的异位词的子串,返回这些子串的起始索引。不考虑答案输出的顺序。异位词指由相同字母重排列形成的字符串(包括相同的字符串)。
example:
输入:s = "abab",p = "ab"
输出:[0,1,2]
# 找到字符串中所有字母异位词
s = "cbaebabacd"
p = "abc"
record = []
hashTable = dict()
for k in range(26):
hashTable[k] = 0
for i in p:
hashTable[ord(i) - ord('a')] += 1
left = right = 0
length = len(s)
while right < length:
hashTable[ord(s[right]) - ord('a')] -= 1
while hashTable[ord(s[right]) - ord('a')] < 0:
hashTable[ord(s[left]) - ord('a')] += 1
left += 1
if right - left + 1 == len(p):
record.append(left)
right += 1
print(record) # [0, 6]
4、子串
4.1 和为K的子数组
给你一个整数数组 nums
和一个整数 k
,请你统计并返回该数组中和为 k
的子数组的个数 。子数组是数组中元素的连续非空序列。
example:
输入:nums= [1,1,1], k=2
输出:2
# 和为K的子数组
# 方法:使用前缀和
import collections
nums = [1, 2, 3]
k = 3
count = 0 # 返回结果
# 初始化
hashTable = collections.defaultdict(int) # 用来计数
hashTable[0] = 1 # 这一步要有,不然结果可能会少一个
# 查找差值有无为K的
# prenum = 0
# for num in nums:
# prenum += num
# if prenum - k in hashTable:
# count += hashTable[prenum - k]
# hashTable[prenum] += 1
# print(count) # 2
# 简化版
prenum = 0
for num in nums:
prenum += num
count += hashTable[prenum - k]
hashTable[prenum] += 1
print(count) # 2
方法:使用前缀和。
4.2 滑动窗口最大值
给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
思想:使用单调队列,并且维护出口处为最大值。
方法:
(1)若push的元素比前面的元素大,则pop掉前面的元素,即出口处为最大值的思想。
(2)使用deque(double-end queue)进行队列操作,详细可以看这篇文章:Python collections模块之deque()详解_python collections.deque-CSDN博客
deque的使用:
from collections import deque
list = [1, 2, 3]
dlist = deque(list)
dlist.append(4)
print(dlist) # deque([1, 2, 3, 4])
dlist.appendleft(0)
print(dlist) # deque([0, 1, 2, 3, 4])
end = dlist.pop()
print(end) # 4
print(dlist) # deque([0, 1, 2, 3])
end1 = dlist.popleft()
print(end1) # 0
print(dlist) # deque([1, 2, 3])
example:
输入:nums=[1,3,-1,-3,5,3,6,7], k=3
输出:[3,3,5,5,6,7]
# 滑动窗口最大值
from collections import deque
class Deque:
def __init__(self):
self.value = deque()
def pop(self, val):
if self.value and val == self.value[0]:
self.value.popleft()
def push(self, val):
while self.value and val > self.value[-1]:
self.value.pop()
self.value.append(val)
def getMax(self):
return self.value[0]
nums = [7, 2, 4]
k = 2
maxResult = []
queue = Deque()
for i in range(k):
queue.push(nums[i])
maxResult.append(queue.getMax())
for j in range(i + 1, len(nums)):
queue.pop(nums[j - k])
queue.push(nums[j])
maxResult.append(queue.getMax())
print(maxResult) # [7, 4]
4.3 最小覆盖子串
给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串 ""
。
注意:
- 对于
t
中重复字符,我们寻找的子字符串中该字符数量必须不少于t
中该字符数量。 - 如果
s
中存在这样的子串,我们保证它是唯一的答案。
思想:用两个指针表示滑动窗口
方法:记needCount为还需满足要求的数量。将right指针向右移动,直至needCount==0为止。将left指针向左移动,直至needTable中包含 t 的关键字存在为0的情况时,记录左右指针位置,再重复之前的步骤即可。
import collections
s = "ADOBECODEBANC"
t = "ABC"
needTable = collections.defaultdict(int)
res = (0, float('inf'))
for i in t:
needTable[i] += 1
left = 0
needCount = len(t)
# 移动right指针
for right, val in enumerate(s):
if needTable[val] > 0:
needCount -= 1
needTable[val] -= 1
# 移动left指针
if needCount == 0:
while True:
if needTable[s[left]] == 0:
needCount += 1
needTable[s[left]] += 1
break
needTable[s[left]] += 1
left += 1
if right - left < res[1] - res[0]:
res = (left, right)
left += 1
print("" if res[1] > len(s) else s[res[0]:res[1] + 1]) # BANC
5、普通数组
5.1 最大子数组和
给你一个整数数组 nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。子数组是数组中的一个连续部分。
example:
输入:nums=[-2,1,-3,4,-1,2,1,-5,4]
输出:6
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
maxValue = nums[0]
dp = []
dp.append(nums[0])
for i in range(1, len(nums)):
if dp[i - 1] < 0:
dp.append(nums[i])
else:
dp.append(dp[i - 1] + nums[i])
if dp[i] > maxValue:
maxValue = dp[i]
print(maxValue) # 6