排序
1.排序

::: details
- 有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
示例 1:
输入: s = "anagram", t = "nagaram"
输出: true
示例 2:
输入: s = "rat", t = "car"
输出: false
说明:
你可以假设字符串只包含小写字母。
# 参考字符串中的第一个唯一字符
# 思路就是计算所有的字符出现的次数,相同满足要求
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
return collections.Counter(s)==collections.Counter(t)
:::
递归

汉诺塔

1.斐波那契数
斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
给你 n ,请计算 F(n) 。
示例 1:
输入:2
输出:1
解释:F(2) = F(1) + F(0) = 1 + 0 = 1
示例 2:
输入:3
输出:2
解释:F(3) = F(2) + F(1) = 1 + 1 = 2
示例 3:
输入:4
输出:3
解释:F(4) = F(3) + F(2) = 2 + 1 = 3
'''
递归过程中会遇到重复子问题,对其进行优化,存储子问题的答案,通过记忆化不重复计算已计算的值
'''
class Solution:
@lru_cache
def fib(self, n: int) -> int:
if n <= 1:
return n
else:
return self.fib(n-1) + self.fib(n-2)
# 与上述直接使用装饰器@lru_cache类似,这里自定义一个备忘录函数
class Solution1:
def fib(self, n: int) -> int:
if n <= 1:
return n
# 定义一个备忘录
self.cache = {0:0,1:1}
return self.memoize(n)
def memoize(self, n: int) -> int:
# 遇到子问题先查备忘录,如果不在备忘录中,则添加
if n in self.cache.keys():
return self.cache[n]
self.cache[n] = self.memoize(n-1) + self.memoize(n-2)
# 最后输出
return self.memoize(n)
查找


二分查找
1、最长递增子序列
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
示例 1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:
输入:nums = [7,7,7,7,7,7,7]
输出:1
解题思路:
利用二分查找维护最长的严格递增子序列, 目的是使递增序列的增量尽可能的小, 利用贪心的思想, 如果我们能保证递增序列的增量一直处于最小的状态, 我们就能得到最后的最长递增序列长度
时间复杂度: O(NlogN)
::: details
思路
最长上升子序列是动规的经典题目,这里dp[i]是可以根据dp[j] (j < i)推导出来的,那么依然用动规五部曲来分析详细一波:
1、dp[i]的定义
dp[i]表示i之前包括i的最长上升子序列。
2、状态转移方程
位置i的最长升序子序列等于j从0到i-1各个位置的最长升序子序列 + 1 的最大值。
所以:if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);
注意这里不是要dp[i] 与 dp[j] + 1进行比较,而是我们要取dp[j] + 1的最大值。
3、dp[i]的初始化
每一个i,对应的dp[i](即最长上升子序列)起始大小至少都是是1.
4、确定遍历顺序
dp[i] 是有0到i-1各个位置的最长升序子序列 推导而来,那么遍历i一定是从前向后遍历。
j其实就是0到i-1,遍历i的循环里外层,遍历j则在内层,代码如下:
for (int i = 1; i < nums.size(); i++) {
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);
}
if (dp[i] > result) result = dp[i]; // 取长的子序列
}




# Dynamic programming + Dichotomy.
class Solution:
def lengthOfLIS(self, nums: [int]) -> int:
tails, res = [0] * len(nums), 0
for num in nums:
i, j = 0, res
while i < j:
m = (i + j) // 2
if tails[m] < num: i = m + 1 # 如果要求非严格递增,将此行 '<' 改为 '<=' 即可。
else: j = m
tails[i] = num
if j == res: res += 1
return res
:::
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
if len(nums) <= 1:
return len(nums)
dp = [1] * len(nums)
result = 0
for i in range(1, len(nums)):
for j in range(0, i):
if nums[i] > nums[j]:
dp[i] = max(dp[i], dp[j] + 1)
result = max(result, dp[i]) #取长的子序列
return result

浙公网安备 33010602011771号