文章目录
- leetcode高频题列表
- 字符串
- 数组
- 递归
- 哈希
- 动态规划
- [面试题 17.16. 按摩师](https://leetcode-cn.com/problems/the-masseuse-lcci/)
- [面试题42. 连续子数组的最大和](https://leetcode-cn.com/problems/contiguous-sequence-lcci/)
- [152. 乘积最大连续子序列](https://leetcode-cn.com/problems/maximum-product-subarray/)
- [300. 最长上升子序列](https://leetcode-cn.com/problems/longest-increasing-subsequence/)
- 334.递增的三元子序列
- 别人思路-双指针
- [322. 零钱兑换](https://leetcode-cn.com/problems/coin-change/)
- 279.完全平方数
- 121.买卖股票的最佳时机
- 122.买卖股票的最佳时机II
- 1143.最长公共子序列
- 数学
- 双指针
- 贪心
- 滑动窗口
leetcode高频题列表
字符串
面试题 01.06. 字符串压缩
字符串压缩。利用字符重复出现的次数,编写一种方法,实现基本的字符串压缩功能。比如,字符串aabcccccaaa会变为a2b1c5a3。若“压缩”后的字符串没有变短,则返回原先的字符串。你可以假设字符串中只包含大小写英文字母(a至z)。
示例1:
输入:“aabcccccaaa”
输出:“a2b1c5a3”
示例2:
输入:“abbccd”
输出:“abbccd”
解释:“abbccd"压缩后为"a1b2c2d1”,比原字符串长度更长。
提示:
字符串长度在[0, 50000]范围内。
class Solution(object):
def compressString(self, S):
"""
:type S: str
:rtype: str
"""
S += '#'
cnt = 0
res = ''
for i in range(len(S)-1):
cnt += 1
if S[i] != S[i+1]:
res = res + S[i] + str(cnt)
cnt = 0
S = S.replace('#','')
if len(res) < len(S):
return res
else:
return S
if __name__ == "__main__":
s = input()
test = Solution()
print(test.compressString(s))
最长回文串
思路
中心扩展法
for循环一遍,判断左右是否相等,还有左右指针的边界
注意:要将原始字符串改成左右都添加#字符,让长度为奇数就可以。
class Solution(object):
def longestPalindrome(self, s):
"""
:type s: str
:rtype: str
"""
if not s:
return ''
ss = ''
for i in s[:len(s)]:
ss += '#' + i
ss += '#'
s = ss
res = ''
for i in range(len(s)):
cur = s[i]
start = i-1
end = i + 1
while(start >= 0 and end <= len(s)-1 and s[start] == s[end]):
cur = s[start] + cur + s[end]
start -= 1
end += 1
if len(cur) > len(res):
res = cur
res = res.replace('#','')
return res
数组
945.使数组唯一的最小增量
134.加油站
我的思路
- gas 和 cost做差得到新的数组gas2,if sum(gas2) < 0 return -1
- if gas2 > 0 ,记下当前索引重新拼接这个数组,遍历一遍中间不能小于0
class Solution(object):
def canCompleteCircuit(self, gas, cost):
"""
:type gas: List[int]
:type cost: List[int]
:rtype: int
"""
for i in range(len(gas)):
gas[i] -= cost[i]
if sum(gas) < 0:
return -1
for i in range(len(gas)):
if gas[i] >= 0:
new_gas = gas[i:] + gas[:i]
cursum = 0
flag = i
for j in range(0,len(new_gas)):
if cursum + new_gas[j] < 0:
break
elif j == len(new_gas) - 1:
return flag
else:
cursum += new_gas[j]
别人的
# -*- coding:utf-8 -*-
class Solution(object):
def canCompleteCircuit(self, gas, cost):
"""
:type gas: List[int]
:type cost: List[int]
:rtype: int
"""
# 0 到 start的油量
total = 0
# 从起始位置到i的油量
tank = 0
# 记录加油的位置
start = 0
for i in range(len(gas)):
tank += gas[i] - cost[i]
if tank < 0:
total += tank
tank = 0
start = i + 1
if total + tank >=0:
return start
else:
return -1
4.寻找两个有序数组的中位数
我的思路
分类讨论:
使用栈的方法,比较大小,然后计数
注意特例:
输入[1] 和 [1]
# -*- coding:utf-8 -*-
import sys
class Solution(object):
def findMedianSortedArrays(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: float
"""
if len(nums1) == 1 and len(nums2) == 1:
return (nums1[0] + nums2[0]) / 2
lenght = len(nums1) + len(nums2)
if lenght % 2 == 0:
mid_o = int(lenght / 2)
i = 0
n1 = sys.maxsize
n2 = sys.maxsize
while nums1 or nums2:
if nums1 and n1 == sys.maxsize:
n1 = nums1.pop(0)
if nums2 and n2 == sys.maxsize:
n2 = nums2.pop(0)
if n1 < n2:
i += 1
if i == mid_o:
a = n1
n1 = sys.maxsize
elif i == mid_o + 1:
b = n1
return float((a+b) / 2)
else:
n1 = sys.maxsize
else:
i += 1
if i == mid_o:
a = n2
n2 = sys.maxsize
elif i == mid_o + 1:
b = n2
return float((a+b) / 2)
else:
n2 = sys.maxsize
else:
mid_j = int(lenght / 2) + 1
i = 0
n1 = sys.maxsize
n2 = sys.maxsize
while nums1 or nums2:
if nums1 and n1 == sys.maxsize:
n1 = nums1.pop(0)
if nums2 and n2 == sys.maxsize:
n2 = nums2.pop(0)
if n1 < n2:
i += 1
if i == mid_j:
return float(n1)
else:
n1 = sys.maxsize
else:
i += 1
if i == mid_j:
return float(n2)
else:
n2 = sys.maxsize
递归
112.路径总和
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def hasPathSum(self, root, sum):
"""
:type root: TreeNode
:type sum: int
:rtype: bool
"""
if not root:
return False
sum -= root.val
# 叶子结点的判断条件
if not root.left and not root.right:
return sum == 0
return self.hasPathSum(root.left,sum) or self.hasPathSum(root.right,sum)
哈希
两数之和
思路
用哈希存下数组每个元素并记录其index
遍历一遍数组,查找是否存在 target - nums[i],有的话返回i和该哈希值
class Solution(object):
def twoSum(self, nums,target):
nums_dict = {}
for index,val in enumerate(nums):
nums_dict[val] = index
for ind,n in enumerate(nums):
j = nums_dict.get(target - n)
if j and ind != j:
return [ind,j]
1160. 拼写单词
class Solution(object):
def countCharacters(self, words, chars):
"""
:type words: List[str]
:type chars: str
:rtype: int
"""
## Counter['item'] 不存在会返回0
ans = 0
char_dict = str2dict(chars)
for w in words:
w_dict = str2dict(w)
for key,val in w_dict.items():
if key not in char_dict.keys():
break
if char_dict[key] - w_dict[key] < 0:
break
#for else用法
else:
ans += len(w)
return ans
def str2dict(s):
s_dict = {}
for i in s:
s_dict[i] = s_dict.get(i,0) + 1
return s_dict
方法二
class Solution:
def countCharacters(self, words: List[str], chars: str) -> int:
ans = 0
cnt = collections.Counter(chars)
for w in words:
c = collections.Counter(w)
if all([c[i] <= cnt[i] for i in c]):
ans += len(w)
return ans
- for else使用
- 可以用collections.Counter来代替字典,Counter[‘item’] 不存在会返回0
动态规划
面试题 17.16. 按摩师
思路
动态规划
cur = 0
pre = 0
res = max(cur,pre + nums[i])
class Solution(object):
def massage(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
pre = 0
cur = 0
res = 0
for i in nums:
res = max(cur,pre + i)
pre = cur
cur = res
return res
面试题42. 连续子数组的最大和
给定一个整数数组(有正数有负数),找出总和最大的连续数列,并返回总和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
cur = nums[0]
max_sum = nums[0]
for i in range(1,len(nums)):
if cur <= 0:
cur = nums[i]
else:
cur += nums[i]
##
if cur > max_sum:
max_sum = cur
return max_sum
152. 乘积最大连续子序列
思路:
- 1、初始化最大值为负无穷,当前最大值max_cur为1,当前最小值min_cur为1
- 2、max_cur更新max(max_cur*nums[i],nums[i])
- 3、min_cur更新min(min_cur*nums[i],nums[i])
- if nums[i]为负数,max_cur和min_cur要互换
- max_res更新max(max_res,max_cur)
import sys
class Solution(object):
def maxProduct(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
max_cur = 1
min_cur = 1
max_res = -sys.maxsize
for i in nums:
if i < 0:
tmp = max_cur
max_cur = min_cur
min_cur = tmp
max_cur = max(max_cur * i,i)
min_cur = min(min_cur *i,i)
max_res = max(max_res,max_cur)
return max_res
300. 最长上升子序列
思路:
- 1、先判断nums是不是空的
- 2、令dp数组为1
- 3、i ~ range(len(nums)) : j ~ range(i)
-
状态转移方程 dp[i] = max(dp[i],dp[j]+1)
- return max(dp)
class Solution(object):
def lengthOfLIS(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if not nums:
return 0
dp = [1] * len(nums)
for i in range(len(nums)):
for j in range(i):
if nums[j] < nums[i]:
dp[i] = max(dp[i],dp[j] + 1)
return max(dp)
334.递增的三元子序列
我的思路
上一题树递增的子序列的长度,所以直接搬过来,判断长度是否大于三即可
class Solution(object):
def increasingTriplet(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
if not nums:
return False
dp = [1] * len(nums)
for i in range(len(nums)):
for j in range(i):
if nums[j] < nums[i]:
dp[i] = max(dp[i],dp[j] + 1)
if dp[i] >= 3:
return True
return False
别人思路-双指针
能跳到第二个小的,说明前面保存两个小的,跳到第三个就是三个递增子序列
class Solution(object):
def increasingTriplet(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
min1 = sys.maxsize
min2 = sys.maxsize
for i in nums:
if min1 >= i:
min1 = i
elif min2 >= i:
min2 = i
else:
return True
return False
322. 零钱兑换
思路:
import sys
class Solution(object):
def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
dp = [sys.maxsize] * (amount + 1)
## 这一步很关键,要不然无法min + 1
dp[0] = 0
for c in coins:
for i in range(c,len(dp)):
dp[i] = min(dp[i],dp[i-c]+1)
return dp[amount] if dp[amount] != sys.maxsize else -1
279.完全平方数
类似零钱兑换,但是python会超时
要将j的遍历区间变为[1,int(sqrt(i))+1):
class Solution(object):
def numSquares(self, n):
"""
:type n: int
:rtype: int
"""
dp = [i for i in range(n+1)]
for i in range(2,n+1):
for j in range(1,int(i**(0.5))+1):
dp[i] = min(dp[i],dp[i-j*j]+1)
return dp[-1]
121.买卖股票的最佳时机
思路
找到最小的值,然后跟当前的maxprofit比较,然后更新
import sys
class Solution(object):
def maxProfit(self, prices):
"""
:type prices: List[int]
:rtype: int
"""
max_profit = 0
min_val = sys.maxsize
for i in prices:
if i < min_val:
min_val = i
elif i - min_val > max_profit:
max_profit = i - min_val
return max_profit
122.买卖股票的最佳时机II
思路
直接前后做差,相加差大于即可得到。
class Solution(object):
def maxProfit(self, prices):
"""
:type prices: List[int]
:rtype: int
"""
for i in range(1,len(prices)):
prices[i-1] = prices[i] - prices[i-1]
max_profit = 0
for i in range(len(prices)-1):
if prices[i] > 0:
max_profit += prices[i]
return max_profit
class Solution:
def minCostClimbingStairs(self, cost: List[int]) -> int:
cost = [0,0] + cost
for i in range(2,len(cost)):
cost[i] = min(cost[i-1], cost[i-2]) + cost[i]
l = len(cost)
if cost[l-1] > cost[l-2]:
return cost[l-2]
else:
return cost[l-1]
1143.最长公共子序列
思路
注意赋值为0
class Solution(object):
def longestCommonSubsequence(self, text1, text2):
"""
:type text1: str
:type text2: str
:rtype: int
"""
m = len(text1) + 1
n = len(text2) + 1
# dp = [[0] * m] * n有个坑,改变一个值会改变整一列
dp = [[0] * m for i in range(n)]
for i in range(1,n):
for j in range(1,m):
if text1[j-1] == text2[i-1]:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = max(dp[i-1][j],dp[i][j-1])
return dp[n-1][m-1]
数学
365.水壶问题
看题解:
取xy的最大公约数,看z是否能整除
注意边界条件:
1、x + y < z
2、x = 0或y=0
只有python3才有gcd函数
class Solution:
def canMeasureWater(self, x,y,z):
if x + y < z:
return False
if x == 0 or y == 0:
return z == 0 or x + y == z
return z % math.gcd(x, y) == 0
双指针
392.判断子序列
class Solution(object):
def isSubsequence(self, s, t):
"""
:type s: str
:type t: str
:rtype: bool
"""
i = 0
j = 0
while i < len(s) and j < len(t):
if s[i] == t[j]:
i += 1
j += 1
else:
j+=1
return i == len(s)
我的思路
双指针解法,哪边小,更新哪边指针。
class Solution(object):
def maxArea(self, height):
i = 0
j = len(height) - 1
res = 0
while i < j:
if height[i] > height[j]:
width = height[j]
length = j - i
j -= 1
else:
width = height[i]
length = j - i
i += 1
area = length * width
if area > res:
res = area
return res
贪心
135.分发糖果
题解
将左右规则拆分为左规则和右规则,取两个数组的最大值。
class Solution(object):
def candy(self, ratings):
"""
:type ratings: List[int]
:rtype: int
"""
left2right = [1] * len(ratings)
right2left = [1] * len(ratings)
for i in range(1,len(ratings)):
if ratings[i] > ratings[i-1]:
left2right[i] = left2right[i-1] + 1
for i in reversed(range(0,len(ratings)-1)):
if ratings[i] > ratings[i+1]:
right2left[i] = right2left[i+1] + 1
for i in range(len(ratings)):
if left2right[i] < right2left[i]:
left2right[i] = right2left[i]
return sum(left2right)
滑动窗口
3.无重复字符的最长子串
思路
其实就是一个队列,比如例题中的 abcabcbb,进入这个队列(窗口)为 abc 满足题目要求,当再进入 a,队列变成了 abca,这时候不满足要求。所以,我们要移动这个队列!
如何移动?
我们只要把队列的左边的元素移出就行了,直到满足题目要求!
一直维持这样的队列,找出队列出现最长的长度时候,求出解!
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
s_list = []
res = 0
for i in s:
if i in s_list:
if len(s_list) > res:
res = len(s_list)
while s_list.pop(0) != i:
continue
s_list.append(i)
else:
s_list.append(i)
if len(s_list) > res:
res = len(s_list)
return res