递归
深度优先搜索的基础。一种循环,自己调用自己。比如:盗梦空间
attention:递归出口,不然无限死循环。
eg1: 计算n!
def Factorial(n):
#递归的出口
if n<= 1:
return 1
return n * Factorial(n-1)
递归函数的形式:
def recursion(level,param1,param2,...):
#递归的终止条件
if level > MAX_LEVEL:
print_sult
return
#当前层对数据操作
process_data(level,data..)
#下沉下一层,调用自己
self.recursion(level+1,p1,...)
#返回层时收尾工作(如果需要的话可以设计)
reverse_state(level)
eg2: 费波拉契函数
费波拉契数组:1,1,2,3,5,8,13,21,34
通项公式: F(n) = F(n-1)+F(n-2)
def fib(n):
if n==0 or n==1:
return n
return fib(n-1)+fib(n-2)
费波拉契数组中可以看出当问题有重复子问题时,用递归解决效率不高。可以使用判重或者记录结果解决。
分治-Dived&Conquer
递归常用来解决分治算法的问题,即先把一个大问题分解成很多个子问题,子问题再一一分析解决。
eg1:将一个字符串的每个字符变成大写
子问题之间互不影响,并行计算。
分治的代码结构:
def divide_conquer(problem,param1,param2...):
#解决出口
if problem is None:
print_result
return
#准备数据
data = prepare_data(problem)
subproblems = split_problem(problem,data)
#解决子问题
subresult1 = self.divide_conquer(subproblems[0],p1,...)
subresult2 = self.divide_conquer(subproblems[1],p1,...)
subresult3 = self.divide_conquer(subproblems[2],p1,...)
...
#处理最后的解集合
result = process_result(subresult1,subresult2,subresult3...)
50.Pow(x, n)(中等)
来源: https://leetcode-cn.com/problems/powx-n/
题目: 实现 pow(x, n) ,即计算 x 的 n 次幂函数。 n可正可负。
思路1:暴力循法是可行的但是这题上没有意义,且会出现超时的情况。
这里采用分治的想法如图:
import math
class Solution(object):
def myPow(self ,x, n):
"""
:type x: float
:type n: int
:rtype: float
"""
if n==0:return 1
#if n==1:return x
if n<0:
return 1/self.myPow(x,-n)
if n%2:
return x*self.myPow(x,n-1)
return self.myPow(x*x,n/2)
tips:这里有个问题就是,一开始我并没有明白是
(
x
2
)
n
/
2
(x^2)^{n/2}
(x2)n/2
所以最后那个return 想不明白。如果好懂一点的话应该是
if n%2:
return x*self.myPow(x,n-1)
res = self.myPow(x,n/2)
return res*res
169.多元素数
来源:https://leetcode-cn.com/problems/majority-element/
题目:
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素
示例:
输入: [3,2,3]
输出: 3
思路1:MAP方法。可以使用字典,对数组中所有元素使用循环建立字典,value存这个元素出现的次数。再一次循环找value值大于n/2的最小的整数。时间复杂度O(n)
import math
class Solution(object):
def majorityElement(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
dic = {}
res = []
for i in range(len(nums)):
dic[nums[i]] = dic.get(nums[i],0) + 1
nums_1 = list(set(nums))
for i in range(len(nums_1)):
if dic.get(nums_1[i]) > math.ceil(len(nums)/2):
return nums_1[i]
思路2:sort排序数组,排好之后,计算元素重复的的次数是否大于n/2。时间复杂度O(nlogn)。
思路3:视频给出了分治的方法,个人感觉有点牵强。不好理解不好写时间复杂度还是O(nlogn),总的来说这题并不适合分治。
实战:贪心算法Greedy
在对问题求解是,总是做出当前看来是最好的选择。
适用场景:问题能够分解成子问题来解决,子问题的最优解能地推到最终问题的最优解。这种子问题最优解成为最优子结构。
与==动态规划==的不同在于它对每个子问题的解决方案都做出选择,不能回退。动态规划则会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能。
122.买卖股票的最佳时机
来源: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
题目:
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
来源: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
题目:
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
思路1:贪心算法,只要后一天的价格比今天高,那么今天买入,后一天卖出。
由于这是一个简单题,所以每天可以买卖无数次且买卖没有手续费,所以可以使用贪心算法,贪心算法的局限性还是很高的。其实这一题最好的方法是使用动态规划。后面学到了再说。
def maxProfit(self, prices):
"""
:type prices: List[int]
:rtype: int
"""
res = 0
for i in range(len(prices)-1):
if prices[i+1]>prices[i]:
res += prices[i+1]-prices[i]
return res