LeetCode 笔记十三 【算法】买卖股票的最佳时机 +【数据库】组合两个表

n久没有刷题,疫情在家搞东搞西,读的学硕还没有开始找工作的感觉,但看着读专硕的同学们都在准备工作了,又想要继续刷题了,希望能坚持吧!打开leetcode老是自动跳转到中文版,索性直接注册了中文版块重新刷好了,坚持每天至少一道算法(python)跟一道数据库(MySQL)吧

【算法】买卖股票的最佳时机

leetcode搞了个每日打卡题,就直接做这道题了。第121题题目:

给定一个数组,它的第 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:
    def maxProfit(self, prices: List[int]) -> int:
        # Runtime out
        for i in range(len(prices)):
            for j in range(i, len(prices)):
                profit = max([profit, prices[j] - prices[i]])
        return profit

这个方法算是非常直接也很容易想到的,不过吧在提交的时候报超时了。看下前面写的代码,用了两层循环,时间复杂度 O ( log n 2 ) O(\text{log}n^2) O(logn2),既然运行时间超了,其实可以看到里面那层循环可以扔掉,用max()的命令直接对比出后面的列表中跟当前价格之差最大的数,然后再用一次max()筛选当前最大的利润:

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        profit = 0
        # runtime:6320 ms
        # memory:14.2 MB
        for i in range(len(prices) - 1):
            profit = max(profit, max(prices[i+1:]) - prices[i])
        return profit

提交了一下,成功了,但运行时间也太长了吧,6320ms。于是就想折腾出一个时间短一点的。咋整呢?看代码里面,外层这个循环基本是去不了了(对我来说省不了···),主要是每次循环,都得算一遍当前值之后所有数值的最大值。当列表长度很大时,这样的操作确实太耗时了。所以要怎么把里面这个max()的骚操作去掉呢?

想了一会,想要用一个最小值来替代,有点类似之前做其他题的时候用指针的想法。然后去看了眼解题,发现确实有人这么做,于是就写成以下代码:

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if len(prices) < 2:
            return 0
        profit = 0
        minPrice = prices[0]
        for i in range(len(prices) - 1):
            minPrice = min(minPrice, prices[i])
            profit = max(profit, prices[i + 1] - minPrice)

        return profit

这里有个小插曲,前面判断if len(prices) < 2这个条件,是因为没加这个判断的时候,提交结果会报错,看到加这个条件也不难猜出,报错原因主要是因为当输入列表为[]时,后面不存在prices[0]。显然当只有一个值时,并不存在多次交易,也可以直接返回结果0了。

这段代码提交后,运行结果是:

执行用时:64 ms
内存消耗:14.5 MB

今日份算法题over ~ 接下来做数据库的题。

【数据库】组合两个表

其实我之前没有系统的学习sql,只是曾经自己瞎折腾的看完一本sql的教程,距离瞎折腾也已经很久很久了,所以做数据库的题还得回忆下。

首先题目:

表1: Person
±------------±--------+
| 列名 | 类型 |
±------------±--------+
| PersonId | int |
| FirstName | varchar |
| LastName | varchar |
±------------±--------+
PersonId 是上表主键

表2: Address
±------------±--------+
| 列名 | 类型 |
±------------±--------+
| AddressId | int |
| PersonId | int |
| City | varchar |
| State | varchar |
±------------±--------+
AddressId 是上表主键

编写一个 SQL 查询,满足条件:无论 person 是否有地址信息,都需要基于上述两表提供 person 的以下信息:
FirstName, LastName, City, State

这个题是个简单题,所以比较简单,基本上就是从两个表中筛选出FirstName, LastName, City, State这四个变量。根据题目,要求筛选出来的在person中一定有记录对应的名字,但不一定有地址,所以链接连个表主要以person为主。代码如下:

# Write your MySQL query statement below
select FirstName, LastName, City, State 
from Person left join Address
on Person.PersonID = Address.PersonID;

这样就搞定啦,提交结果:

执行用时:169 ms
内存消耗:0B
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值