6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)

243 最短单词距离
6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第1张图片

class Solution(object):
    def shortestDistance(self, words, word1, word2):
        """
        :type words: List[str]
        :type word1: str
        :type word2: str
        :rtype: int
        """
        res = len(words) - 1
        pos1, pos2 = -1, -1
        for i, word in enumerate(words):
            if word == word1:
                pos1 = i
            elif word == word2:
                pos2 = i
            if pos1 != -1 and pos2 != -1:
                res = min(res, abs(pos1 - pos2))
        return res

244. 最短单词距离 II
6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第2张图片
使用哈希表,key是words里的每个单词,val是每个word出现的所有下标

class WordDistance(object):
 
    def __init__(self, words):
        """
        :type words: List[str]
        """
        self.words = words
        self.record = defaultdict(list)
        for i, word in enumerate(words):
            self.record[word].append(i)
        # print self.record
    def shortest(self, word1, word2):
        """
        :type word1: str
        :type word2: str
        :rtype: int
        """
        res = len(self.words)
        for pos1 in self.record[word1]:
            for pos2 in self.record[word2]:
                res = min(res, abs(pos1 - pos2))
        return res

245. 最短单词距离 III
6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第3张图片
如果相等,那么就用一个变量记录上一次出现的下表即可。

class Solution(object):
    def shortestDistance(self, words, word1, word2):
        """
        :type words: List[str]
        :type word1: str
        :type word2: str
        :rtype: int
        """
        res = len(words) - 1
        pos1, pos2 = -1, -1
        if word1!=word2:
            for i,word in enumerate(words):
                if word==word1:
                    pos1=i
                if word==word2:
                    pos2=i
                if pos1!=-1 and pos2!=-1:
                    res=min(res,abs(pos1-pos2))
        else:
            for i,word in enumerate(words):
                if word==word1:
                    if pos1!=-1:
                        res=min(res,i-pos1)
                    pos1=i
        return res

121. 买卖股票的最佳时机
6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第4张图片
我们只需要遍历价格数组一遍,记录历史最低点,然后在每一天考虑这么一个问题:如果我是在历史最低点买进的,那么我今天卖出能赚多少钱?
如果暴力计算每天赚的钱,会超时

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        maxc=0
        minprice=float('inf')
        for i in range(len(prices)):
            maxc=max(maxc,prices[i]-minprice)
            minprice=min(minprice,prices[i])
        return maxc

单调栈:
单调栈的应用场景 当你需要高效率查询某个位置左右两侧比他大(或小)的数的位置的时候
维护一个单调递增栈,每次弹出不符合的栈顶元素时,更新栈顶与栈底的差值,因为这个栈顶元素无论再大,后续也不会使用了

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        #添加哨兵
        prices.append(0)
        maxp=0
        stack=[]
        for price in prices:
            while stack and stack[-1]>price:
                maxp=max(maxp,stack[-1]-stack[0])
                stack.pop()
            stack.append(price)
        return maxp

122. 买卖股票的最佳时机 II
6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第5张图片
6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第6张图片
不限制交易次数,所有产生利润的天都买卖,利润为0或者负就不参与买卖
6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第7张图片
在这里插入图片描述

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

123. 买卖股票的最佳时机 III
6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第8张图片
6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第9张图片
作者:labuladong
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/solution/yi-ge-tong-yong-fang-fa-tuan-mie-6-dao-gu-piao-wen/
利用「状态」进行穷举。我们具体到每一天,看看总共有几种可能的「状态」,再找出每个「状态」对应的「选择」。我们要穷举所有「状态」,穷举的目的是根据对应的「选择」更新状态。
每天都有三种「选择」:买入、卖出、无操作,我们用 buy, sell, rest 表示这三种选择。但问题是,并不是每天都可以任意选择这三种选择的,因为 sell 必须在 buy 之后,buy 必须在 sell 之后。那么 rest 操作还应该分两种状态,一种是 buy 之后的 rest(持有了股票),一种是 sell 之后的 rest(没有持有股票)。而且别忘了,我们还有交易次数 k 的限制,就是说你 buy 还只能在 k > 0 的前提下操作

6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第10张图片
我们想求的最终答案是 dp[n - 1][K][0],即最后一天,最多允许 K 次交易,最多获得多少利润。读者可能问为什么不是 dp[n - 1][K][1]?因为 [1] 代表手上还持有股票,[0] 表示手上的股票已经卖出去了,很显然后者得到的利润一定大于前者。
dp状态转移方程表示的是利润
dp[i][k][0 or 1]表示第i天,最多可完成k笔交易时,是(1)否(0)持有股票时,的最大利润。
买股票的时候交易次数减一
如果 buy,就要从利润中减去 prices[i],如果 sell,就要给利润增加 prices[i]。今天的最大利润就是这两种可能选择中较大的那个
6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第11张图片
base case:
6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第12张图片
k从1开始,因为dp[i][0][0 or 1]表示最多可进行0笔交易,不论什么时候结果都是0
k表示最多进行的交易次数,dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])后面的k-1表示:当前最多进行K次交易,且此次已经进行了一次买入交易,那么之前最多进行k-1次交易
dp[i][k][0]=max(dp[i-1][k][0],dp[i-1][k][1]+prices[i]) ,第i天未持有:(1)第i-1天未持有,(2)第i-1天持有,第i天卖出,赚钱第i天利润
dp[i][k][1]=max(dp[i-1][k][1],dp[i-1][k-1][0]-prices[i]) ,第i天持有:(1)第i-1天持有,(2)第i-1天未持有,第i天买入,买入时需要消耗一次k,成本为prices[i]
dp[0][k][1]=float("-inf") 第0天不可能有一次交易,设为负无穷float("-inf")

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        #状态转移方程
        #买入股票消耗交易次数
        # 三个维度,第一维表示天,第二维表示交易了几次,第三维表示是否持有股票。
        if not prices:
            return 0
        maxk=2
        n=len(prices)
        ##最里面的[0,0]表示:第一位是未持有股票的利润,第二位是持有股票的利润
        dp=[[[0,0]for i in range(maxk+1)]for j in range(n+1)]
        #dp[i][0][0]=0:无论哪天,没有交易,没有持有股票,利润都为0,不用单独初始化
        for k in range(maxk+1):
            #第0天未持有股票,初始利润为0
            dp[0][k][0]=0
            #第0天不可能持有股票,初始化为负无穷
            dp[0][k][1]=float('-inf')
        #i从1开始,从第一天开始计数
        #k表示最多进行的交易次数,1,2,
        for i in range(1,n+1):
            for k in range(1,3):
                dp[i][k][0]=max(dp[i-1][k][0],dp[i-1][k][1]+prices[i-1])
                dp[i][k][1]=max(dp[i-1][k][1],dp[i-1][k-1][0]-prices[i-1])
        return dp[-1][2][0]

188. 买卖股票的最佳时机 IV
6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第13张图片
一次交易由买入和卖出构成,至少需要两天。所以说有效的限制 k 应该不超过 n/2,如果超过,就没有约束作用了,相当于 k = +infinity。

class Solution:
    def maxProfit(self, k: int, prices: List[int]) -> int:
        if not prices:
            return 0
        #天数从第一天开始,最多交易次数从1开始
        #买股票消耗交易次数
        n=len(prices)

        # 当允许交易的次数大于交易天数时,相当于是可以无限交易,使用贪心算法
        if k>=n/2:
            maxp=0
            for i in range(1,n):
                if prices[i]-prices[i-1]>0:
                    maxp+=prices[i]-prices[i-1]
            return maxp

        dp=[[[0,0] for _ in range(k+1)] for _ in range(n+1)]
        for i in range(k+1):
            #第0天不可能持有股票,负无穷表示不可能
            dp[0][i][1]=float('-inf')
            #第0天无股票利润为0
            dp[0][i][0]=0
        #dp[i][0][0]=0 :无交易次数,且不持有股票,利润为0
        #dp[i][0][1]=float('-inf):无交易次数,不可能还持有股票,负无穷表示,这个初始化已经包含在上面的初始化
        for i in range(1,n+1):
            for j in range(1,k+1):
                #当前不持有股票,可能之前也不持有或者之前持有股票,但是今天卖了
                dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]+prices[i-1])
                #当前持有股票,可能之前也持有或者之前未持有股票,但是今天买了,消耗一次交易次数
                dp[i][j][1]=max(dp[i-1][j][1],dp[i-1][j-1][0]-prices[i-1])
        return dp[-1][k][0]

309. 最佳买卖股票时机含冷冻期
6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第14张图片
第 i 天选择 buy 的时候,要从 i-2 的状态转移,而不是 i-1 。
dp[i][1]可由两种情况得到:【i-1天本来就持有股票】和【i-1天没有股票,是今天进行了买入操作】。后者dp[i-1][0] - prices[i-1]由于是今天(i天)进行了买入操作,那么i-1天没有股票的原因就一定【不能是】i-1天进行了卖出操作(因为冷冻期)。即i-1天没有股票的原因一定是因为i-2天就没有股票。即dp[i-1][0] =dp[i-2][0] ,因此直接用dp[i-2][0]表示,就可以避免dp[i-1][0]中可能包含的上述违禁操作。

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        #交易不限次数
        if not prices:
            return 0
        n=len(prices)
        dp=[[0,0] for i in range(n+1)]
        #初始化
        dp[0][0]=0
        dp[0][1]=float('-inf')
        dp[1][0]=0
        #dp[-1][1]=float('-inf):因为不可能存在
        #dp[-1][0]=0:未开始交易,利润为0
        dp[1][1]=-prices[0]
        #因为有i-2,所以i从2开始
        for i in range(2,n+1):
            #因为有冷冻期,所以卖出和买入隔一天状态转移
            #【i-1天没有股票,是今天进行了买入操作】。后者dp[i-1][0] - prices[i-1]由于是今天(i天)进行了买入操作,那么i-1天没有股票的原因就一定【不能是】i-1天进行了卖出操作(因为冷冻期)。即i-1天没有股票的原因一定是因为i-2天就没有股票。即dp[i-1][0] =dp[i-2][0] ,因此直接用dp[i-2][0]表示,就可以避免dp[i-1][0]中可能包含的上述违禁操作。
            dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i-1])
            dp[i][1]=max(dp[i-1][1],dp[i-2][0]-prices[i-1])

        return dp[-1][0]

714. 买卖股票的最佳时机含手续费
6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第15张图片

class Solution:
    def maxProfit(self, prices: List[int], fee: int) -> int:
        if not prices:
            return 0
        n=len(prices)
        dp=[[0,0]for _ in range(n+1)]
        dp[0][0]=0
        dp[0][1]=float('-inf')
        #买入股票计入一次交易,每次交易从利润里减去手续费即可
        for i in range(1,n+1):
            dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i-1])
            dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i-1]-fee)
        return dp[-1][0]

898. 子数组按位或操作
6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第16张图片
6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第17张图片
一个cur集合储存上一次循环的位或结果集合,将这些集合和当前循环的元素进行位或运算,在补充上当前元素,然后结果集与cur求并集,可以添加进来
暴力求每个数字与后面数字的异或会超时
6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第18张图片

class Solution:
    def subarrayBitwiseORs(self, A: List[int]) -> int:
        cur={0}
        res=set()
        for i in A:
            #cur保存上一次循环的位或结果集
            #当前循环每个元素与cur或,最后添加当前元素进来
            cur={i|y for y in cur}|{i}
            res|=cur
        return len(res)

面试题 05.06. 整数转换
6.4 力扣 买卖股票六道动态规划(三维,穷举状态 好难,多看题解)_第19张图片
python3中的整形,是以补码形式存在
正数的补码和原码相同
负数的补码是原码取反加1
python3中的负数,输出的是原码的二进制加一个负号,所以你为了获得负数(十进制表示)的补码,需要手动将其和十六进制数 0xffffffff 进行按位与操作,得到结果是个十六进制数,再交给 bin() 进行输出,得到的才是你想要的补码表示

class Solution:
    def convertInteger(self, A: int, B: int) -> int:
        #a^b :a,b不一样的位为1
        #对负数来说,& 0xffffffff是转换成32位补码
        tmp=(A&0xffffffff)^(B&0xffffffff)
        count=0
        while tmp!=0:
            count+=1
            #用来求Tmp中有几个1
            tmp&=(tmp-1)
        return count

你可能感兴趣的:(力扣,python,补码)