leetcode300:最长上升子序列 以及字节面试的引申题

题目就不描述啦,leetcode的题。这题应该蛮好想到思路。一般只有题目有最长的字眼都是动态规划求解。
动态规划在思考时有两个从选与不选下手。不选很简单,不选就是dp[i]= dp[i-1],选呢?
选的关键在于,找到前序序列中满足条件要求的前序序列
依次遍历0~i-1,如果满足条件nums[i] > nums[j],那么更新dp[i] = dp[j] + 1。注意!!这种结果是错误的!!!
以 [12,22,4,32] 为例,因为每次只要满足条件,32>12,32>22,32>4,那么dp[i]都更新,所以最后更新的是dp[i-1],也就是4的dp的值1再加1.很显然,这个最长子串的长度为3【12,22,32】
因此,还要满足一个条件,dp[j] + 1 >= dp[i]:时才更新。

若输入为:nums = [12,22,4,32,7,8,2,3,18]
输出:dp = [1, 2, 1, 3, 2, 3, 1, 2, 4]

注意,最长子串至少应该是一个不减的结果。如果在每次更新dp[i]时修改dp[i]为前面的最大值,也会出现错误。
如 对于4,前面的最大值为2,即【12,22】,当考虑到7时,7大于4,因此更新7为dp[4的位置] +1.这句话是说,我们当前找到的序列是[12,22,7]!!!这样是错误的!
那怎么找到最长呢?把dp每个位置取之前的max即可。

详细的解答可以看网上答案或者最后付的代码~

——————————————————————————————————————————————————————
分割线!!!
朋友在字节的面试时,出了类似的题目,但引申为返回最长元素的下标。她说当时动态规划没想到,用暴力法解的。我现在暴力法还没想到,等写出来会更新。

我思考了一下,动态规划应该也是能做的。就是添加一个记录每个位置的字符串就够了。我用的是字典,键为位置,值为此位置下的最长字符串,代码如下:

def findmaxlength(nums):

    dp = [1]*len(nums)
    dict={}
    dict[0] = [nums[0]]
    ans = [1]*len(nums) #存当前位置最长的
    re = {} #存最后返回的元素
    re[0] = [nums[0]]

    for i in range(1,len(nums)):
        dict[i] = [nums[i]] #初始化
        for j in range(i):
            if nums[i] > nums[j]: #dp[i]=max(dp[i],dp[j]+1)
                if dp[j] + 1 >= dp[i]:
                    dp[i] = dp[j] + 1
                    tmp = dict[j][:]
                    tmp.append(nums[i])
                    dict[i] = tmp[:]
        #都没有的话,dict[i]应该为最大值
        maxindex = 0
        for k in range(i+1):
            if dp[k] > dp[maxindex]:
                maxindex = k
        ans[i] = dp[maxindex]
        re[i] = dict[maxindex]

    print(dp)
    print(ans)
    print(dict)
    return re


if __name__ == "__main__":
    nums = [12,22,4,32,7,8,2,3,18]
    print(findmaxlength(nums))

结果:

[1, 2, 1, 3, 2, 3, 1, 2, 4]
[1, 2, 2, 3, 3, 3, 3, 3, 4]
{0: [12], 1: [12, 22], 2: [4], 3: [12, 22, 32], 4: [4, 7], 5: [4, 7, 8], 6: [2], 7: [2, 3], 8: [4, 7, 8, 18]}
{0: [12], 1: [12, 22], 2: [12, 22], 3: [12, 22, 32], 4: [12, 22, 32], 5: [12, 22, 32], 6: [12, 22, 32], 7: [12, 22, 32], 8: [4, 7, 8, 18]}

————————————————————————————————
更新:暴力解法
暴力解法的思路就是,找到以每个数字打头的所有满足条件的子串,然后再从里面找最大。以【12,3,32,4,7,8,2】为例,如果是找3的话,就是3打头,以32,4,7,8,2依次作为第二个元素,一直向下找。
朋友说字节的题是要递增1,只要把条件改成相差1即可。最后的代码为:

def findmaxlength(nums):
#思路:找从每个下标开始所有可能的数组
    ans = [1]*len(nums)
    maxlen = 1
    ans = []
    for i in range(len(nums)):
        for j in range(i+1,len(nums)): #第j个元素依次作为第二个元素
            if nums[j] - nums[i] == 1:
                tmp = [nums[i],nums[j]]
                for k in range(j+1,len(nums)):
                    if nums[k] - tmp[-1] == 1:
                        tmp.append(nums[k])
                if len(tmp) >maxlen:
                    ans = tmp[:]
                    maxlen = len(tmp)


    print(ans)
    return maxlen

测试:nums = [9,1,2,7,3,4,5,8]
输出:

[1, 2, 3, 4, 5]
5
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值