题目
爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
- 1 阶 + 1 阶
- 2 阶
示例 2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
3. 1 阶 + 1 阶 + 1 阶
4. 1 阶 + 2 阶
5. 2 阶 + 1 阶
class Solution(object):
"""
假设爬n层台阶有f(n)种方法,注意到爬n层台阶有两种情况:
1. 最后一步跨了1层台阶,这种可能的方法有f(n-1)种
2. 最后一步跨了2层台阶,这种可能的方法有f(n-2)种
即,f(n) = f(n-1) + f(n-1)
这不就是斐波那契数列么?递归太耗时间,循环就可以实现了!
"""
def climbStairs(self, n):
if n == 1:
return 1
if n == 2:
return 2
a = 1
b = 2
res = 0
while n >= 3:
res = (a + b)
a = b
b = res
n -= 1
return b
最大子序列和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
class Solution(object):
"""
【动态规划解法】
时间复杂度:o(n),空间复杂度:o(1)
设dp[i]表示以位置i结尾的子序列的最大和,那么dp[i+1]有两种情况
1. 数组的第i+1个位置的值 + dp[i],也就是说这个新的子序列是以i+1结尾的
2. 数组的第i+1个位置的值,也就是说新的子序列是以i+1开始的(也是i+1结束的)
方程式: dp[i+1] = max{dp[i]+nums[i], nums[i]}
最后我们的答案就是dp这个数组中的最大值(实际上相当于判断在子序列在数组的哪个位置结尾会得到最大值),同时注意到,其实这里的dp没有必要设成数组,用两个变量就可以实现了
"""
def maxSubArray(self, nums):
if not nums:
return
n = nums[0]
sum = nums[0]
for i in range(1, len(nums)):
n = max(nums[i]+ n, nums[i])
if n > sum:
sum = n
return sum
max = lambda x, y: x if x > y else y
class Solution(object):
def maxSubArray(self, nums):
"""
【Divide and Conquer】
复杂度: O(n log n)
- f(n) = O(n), n ^ (log b a) = n
- Master theorem --- case 2 --- T(n) = f(n) log n = O(n log n)
解法:
合并的时候要看一下左右连接处是不是有更大的值
"""
return self.divide(nums, 0, len(nums)-1)
def divide(self, nums, left, right):
if left == right:
return nums[left]
mid = (left + right) / 2
sum1 = self.divide(nums, left, mid)
sum2 = self.divide(nums, mid+1, right)
sum = 0
maxl = nums[mid]
for i in range(mid, left-1, -1):
sum += nums[i]
if sum > maxl:
maxl = sum
sum = 0
maxr = nums[mid+1]
for i in range(mid+1, right+1):
sum += nums[i]
if sum > maxr:
maxr = sum
sum3 = maxl + maxr
return max(max(sum1, sum2), sum3)
max = lambda x, y: x if x > y else y
打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 1:
输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
示例 2:
输入: [2,7,9,3,1]
输出: 12
解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
偷窃到的最高金额 = 2 + 9 + 1 = 12 。
class Solution(object):
"""
【动态规划】
前i个最大的金额只有两种情况
1. 抢第i个位置的金额: = 前i-2的最大金额 + 当前第i个位置的金额
2. 不抢抢第i个位置的金额:= 前i-1的最大金额
【动态方程】
dp[i] = max{dp[i-2]+nums[i], dp[i-1]}
"""
def rob(self, nums):
if not nums:
return 0
res1 = 0
res2 = nums[0]
for i in range(1, len(nums)):
if res1 + nums[i] > res2:
tmp = res2
res2 = res1 + nums[i]
res1 = tmp
else:
res1 = res2
return res2
# 对于上面的代码更优雅的是如下写法
class Solution(object):
def rob(self, nums):
res1 = 0
res2 = 0
for num in nums:
res1, res2 = res2, max(res1 + num, res2)
return res2
买卖股票的最佳时机
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。
注意你不能在买入股票前卖出股票。
示例 1:
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例 2:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
class Solution(object):
"""
时间复杂度o(n),空间复杂度o(1)
原数组: 7 1 5 3 6 4 1
相邻的差值: -6 +4 -2 +3 -2 -3
cur: x 0 4 2 5 2 0
benefits: x 0 4 4 5 5 5
"""
def maxProfit(self, prices):
benefits = 0
cur = 0
for i in range(1, len(prices)):
cur = max(cur + prices[i] - prices[i-1], 0)
benefits = max(cur, benefits)
return benefits