leetcode数组中的问题(十一)

本文探讨了LeetCode中涉及动态规划和数据结构的多项算法问题,包括子矩形查询、商品折扣后的最终价格、每日温度、按递增顺序显示卡牌、非递减数列和统计作战单位数。文章分析了各种解题策略,如使用非递增栈、单调递增栈、模拟法、树状数组等,并提供了不同时间复杂度和空间复杂度的解决方案。
摘要由CSDN通过智能技术生成

目录

1476. 子矩形查询

1475. 商品折扣后的最终价格

739. 每日温度

950. 按递增顺序显示卡牌

665. 非递减数列

1395. 统计作战单位数

357. 计算各个位数不同的数字个数

1291. 顺次数


 

 

1476. 子矩形查询

https://leetcode-cn.com/problems/subrectangle-queries/

请你实现一个类 SubrectangleQueries ,它的构造函数的参数是一个 rows x cols 的矩形(这里用整数矩阵表示),并支持以下两种操作:

1. updateSubrectangle(int row1, int col1, int row2, int col2, int newValue),用 newValue 更新以 (row1,col1) 为左上角且以 (row2,col2) 为右下角的子矩形。
2. getValue(int row, int col),返回矩形中坐标 (row,col) 的当前值。

示例 1:

输入:
["SubrectangleQueries","getValue","updateSubrectangle","getValue","getValue","updateSubrectangle","getValue","getValue"]
[[[[1,2,1],[4,3,4],[3,2,1],[1,1,1]]],[0,2],[0,0,3,2,5],[0,2],[3,1],[3,0,3,2,10],[3,1],[0,2]]
输出:
[null,1,null,5,5,null,10,5]
解释:
SubrectangleQueries subrectangleQueries = new SubrectangleQueries([[1,2,1],[4,3,4],[3,2,1],[1,1,1]]);  
// 初始的 (4x3) 矩形如下:
// 1 2 1
// 4 3 4
// 3 2 1
// 1 1 1
subrectangleQueries.getValue(0, 2); // 返回 1
subrectangleQueries.updateSubrectangle(0, 0, 3, 2, 5);
// 此次更新后矩形变为:
// 5 5 5
// 5 5 5
// 5 5 5
// 5 5 5 
subrectangleQueries.getValue(0, 2); // 返回 5
subrectangleQueries.getValue(3, 1); // 返回 5
subrectangleQueries.updateSubrectangle(3, 0, 3, 2, 10);
// 此次更新后矩形变为:
// 5   5   5
// 5   5   5
// 5   5   5
// 10  10  10 
subrectangleQueries.getValue(3, 1); // 返回 10
subrectangleQueries.getValue(0, 2); // 返回 5
示例 2:

输入:
["SubrectangleQueries","getValue","updateSubrectangle","getValue","getValue","updateSubrectangle","getValue"]
[[[[1,1,1],[2,2,2],[3,3,3]]],[0,0],[0,0,2,2,100],[0,0],[2,2],[1,1,2,2,20],[2,2]]
输出:
[null,1,null,100,100,null,20]
解释:
SubrectangleQueries subrectangleQueries = new SubrectangleQueries([[1,1,1],[2,2,2],[3,3,3]]);
subrectangleQueries.getValue(0, 0); // 返回 1
subrectangleQueries.updateSubrectangle(0, 0, 2, 2, 100);
subrectangleQueries.getValue(0, 0); // 返回 100
subrectangleQueries.getValue(2, 2); // 返回 100
subrectangleQueries.updateSubrectangle(1, 1, 2, 2, 20);
subrectangleQueries.getValue(2, 2); // 返回 20

提示:

最多有 500 次updateSubrectangle 和 getValue 操作。
1 <= rows, cols <= 100
rows == rectangle.length
cols == rectangle[i].length
0 <= row1 <= row2 < rows
0 <= col1 <= col2 < cols
1 <= newValue, rectangle[i][j] <= 10^9
0 <= row < rows
0 <= col < cols

题解

一:矩阵规模和操作次数不算很大,可以直接操作。

二:空间换时间,思路挺赞的,下面转一下大神题解,https://leetcode-cn.com/problems/subrectangle-queries/solution/bu-bao-li-geng-xin-ju-zhen-yuan-su-de-jie-fa-by-li/

这道题暴力模拟就可以通过,不多说了。但是,这个问题可以不暴力更新矩阵的内容。

我们可以设置一个history的数组,记录每次调用updateSubrectangle的信息。这样,updateSubrectangle的复杂度是 O(1) 的。

相应的,在 getValue 的过程中,我们只需要倒序查找我们记录的 history,如果发现我们要查找的 (row, col) 包含在某一次历史更新的位置中,直接返回这个历史更新值就好了。否则的,历史更新没有动过这个位置,返回原始矩阵中这个位置的值。

class SubrectangleQueries(object):

    def __init__(self, rectangle):
        """
        :type rectangle: List[List[int]]
        """
        m, n = len(rectangle), len(rectangle[0])
        self.rectangle = [[rectangle[i][j] for j in range(n)] for i in range(m)]
        self.history = []


    def updateSubrectangle(self, row1, col1, row2, col2, newValue):
        """
        :type row1: int
        :type col1: int
        :type row2: int
        :type col2: int
        :type newValue: int
        :rtype: None
        """
        self.history.append([row1, col1, row2, col2, newValue])

    def getValue(self, row, col):
        """
        :type row: int
        :type col: int
        :rtype: int
        """
        n = len(self.history)
        for i in range(n - 1, -1, -1):
            if (self.history[i][0] <= row <= self.history[i][2] and self.history[i][1] <= col <= self.history[i][3]):
                return self.history[i][4]
        return self.rectangle[row][col]


# Your SubrectangleQueries object will be instantiated and called as such:
# obj = SubrectangleQueries(rectangle)
# obj.updateSubrectangle(row1,col1,row2,col2,newValue)
# param_2 = obj.getValue(row,col)

1475. 商品折扣后的最终价格

https://leetcode-cn.com/problems/final-prices-with-a-special-discount-in-a-shop/

给你一个数组 prices ,其中 prices[i] 是商店里第 i 件商品的价格。商店里正在进行促销活动,如果你要买第 i 件商品,那么你可以得到与 prices[j] 相等的折扣,其中 j 是满足 j > i 且 prices[j] <= prices[i] 的 最小下标 ,如果没有满足条件的 j ,你将没有任何折扣。请你返回一个数组,数组中第 i 个元素是折扣后你购买商品 i 最终需要支付的价格。

示例 1:输入:prices = [8,4,6,2,3],输出:[4,2,4,2,3]
解释:

商品 0 的价格为 price[0]=8 ,你将得到 prices[1]=4 的折扣,所以最终价格为 8 - 4 = 4 。
商品 1 的价格为 price[1]=4 ,你将得到 prices[3]=2 的折扣,所以最终价格为 4 - 2 = 2 。
商品 2 的价格为 price[2]=6 ,你将得到 prices[3]=2 的折扣,所以最终价格为 6 - 2 = 4 。
商品 3 和 4 都没有折扣。
示例 2:输入:prices = [1,2,3,4,5],输出:[1,2,3,4,5],解释:在这个例子中,所有商品都没有折扣。
示例 3:输入:prices = [10,1,1,6],输出:[9,0,1,6]
提示:1 <= prices.length <= 500,1 <= prices[i] <= 10^3

题解

一:暴力解法,时间复杂度O(n^2)。

class Solution(object):
    def finalPrices(self, prices):
        """
        :type prices: List[int]
        :rtype: List[int]
        """
        ans, n = prices[:], len(prices)
        min_val = prices[-1]
        for i in range(n -2, -1, -1):
            if prices[i] < min_val:
                min_val = prices[i]
            else:
                for j in range(i + 1, n):
                    if prices[j] <= prices[i]:
                        ans[i] = prices[i] - prices[j]
                        break 
        return ans

二:单调递增栈,时间复杂度O(n),时间复杂度O(n),新的元素肯定是要入栈的,并且必须维持单调递增栈的性质。若新元素比栈顶元素大则直接入栈成为栈顶,若小于等于栈顶元素,所有比新元素大的元素全部出栈(由于单调递增栈,只要栈顶元素小于新元素则栈内元素必小于新元素)。这边说说为啥可以用单调递增栈,因为这边需要减去第一个小于等于该元素的元素的值,当新元素值大于栈顶元素,则栈内的所有元素都没有找到比他小的元素,无需处理;若新元素小于等于栈顶元素,则对于栈内所有比它大的元素来说,新元素都是小于该元素的第一个值,此刻处理。参考大神题解,https://leetcode-cn.com/problems/final-prices-with-a-special-discount-in-a-shop/solution/dan-diao-zhan-zui-quan-mian-xiang-jie-bao-ni-dong-/https://leetcode-cn.com/problems/final-prices-with-a-special-discount-in-a-shop/solution/dan-diao-zhan-ji-chu-ti-kan-bu-dong-da-lou-shang-b/,以及可以看看大神的博客,https://mp.weixin.qq.com/s/poOH6CbXKtdGf1raBBI-0g,关于单调栈算法的讲解,文中写的还是清晰的。

class Solution(object):
    def finalPrices(self, prices):
        # 列表stack的append和pop刚好和栈的先进后出对应上。
        # stack[0]栈底,stack[-1]栈顶
        # 这边栈存储的是下标,其下标对应的值从栈顶到栈底递增
        stack, ans, n = [], prices[:], len(prices)
        for i in range(n):
            while len(stack) > 0 and ans[i] <= ans[stack[-1]]:
                idx = stack.pop()
                ans[idx] -= ans[i]
            stack.append(i)
        return ans

739. 每日温度

https://leetcode-cn.com/problems/daily-temperatures/

请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。

例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。

提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。

题解

一:非递增栈,参见姐妹题1475. 商品折扣后的最终价格,相似点,都要找到大于或小于等于的第一个,再处理。

class Solution(object):
    def dailyTemperatures(self, T):
        """
        :type T: List[int]
        :rtype: List[int]
        """
        n = len(T)
        # 非递增栈,从栈顶stack[-1]到栈底stack[0]非递增,也即是stack当作列表看非递减排序
        # stack存下标
        stack, ans = [], [0] * n 
        for i in range(n):
            while len(stack) != 0 and T[i] > T[stack[-1]]:
                idx = stack.pop()
                ans[idx] = i - idx 
            stack.append(i)
        # stack栈内最终存在的下标不用处理,因为他们后面没有比它更高的了,直接用初始值0即可。
        return ans

950. 按递增顺序显示卡牌

https://leetcode-cn.com/problems/reveal-cards-in-increasing-order/

牌组中的每张卡牌都对应有一个唯一的整数。你可以按你想要的顺序对这套卡片进行排序。最初,这些卡牌在牌组里是正面朝下的(即,未显示状态)。

现在,重复执行以下步骤,直到显示所有卡牌为止:

从牌组顶部抽一张牌,显示它,然后将其从牌组中移出。
如果牌组中仍有牌,则将下一张处于牌组顶部的牌放在牌组的底部。
如果仍有未显示的牌,那么返回步骤 1。否则,停止行动。
返回能以递增顺序显示卡牌的牌组顺序。

答案中的第一张牌被认为处于牌堆顶部。

示例:输入:[17,13,11,2,3,5,7],输出:[2,13,3,11,5,17,7]
解释:
我们得到的牌组顺序为 [17,13,11,2,3,5,7](这个顺序不重要),然后将其重新排序。
重新排序后,牌组以 [2,13,3,11,5,17,7] 开始,其中 2 位于牌组的顶部。
我们显示 2,然后将 13 移到底部。牌组现在是 [3,11,5,17,7,13]。
我们显示 3,并将 11 移到底部。牌组现在是 [5,17,7,13,11]。
我们显示 5,然后将 17 移到底部。牌组现在是 [7,13,11,17]。
我们显示 7,并将 13 移到底部。牌组现在是 [11,17,13]。
我们显示 11,然后将 17 移到底部。牌组现在是 [13,17]。
我们展示 13,然后将 17 移到底部。牌组现在是 [17]。
我们显示 17。
由于所有卡片都是按递增顺序排列显示的,所以答案是正确的。
提示:1 <= A.length <= 1000,1 <= A[i] <= 10^6,对于所有的 i != j,A[i] != A[j]

题解

一:通过,看了示例的无道理的感觉,总感觉是每隔一个未取到的下标取下标。

class Solution(object):
    def deckRevealedIncreasing(self, deck):
        """
        :type deck: List[int]
        :rtype: List[int]
        """
        n = len(deck)
        deck = sorted(deck)
        ans, count, i = [0] * n, 0, 0
        while True:
            i = i % n
            ans[i] = deck[count]
            count += 1
            if count >= n:
                return ans
            local_count = 0
            while local_count < 2:
                i = (i + 1) % n 
                if ans[i] == 0:
                    local_count += 1

        return ans

二:模拟法,参考各大神题解,用q来模拟操作顺序,q中存储下表,将deck排序,每次都是取最上面的,即q最左侧的下标(取出,即弹出popleft)放置目前最小的数,若还有牌(即q不为空),将下一张牌放到最底下(即将目前q的最左侧的下标弹出并放入最右端,即不为空,先popleft,再append)。

from collections import deque
class Solution(object):
    def deckRevealedIncreasing(self, deck):
        q = deque(range(len(deck)))
        ans = deck[:]
        for item in sorted(deck):
            ans[q.popleft()] = item 
            if q:
                index = q.popleft()
                q.append(index)
        return ans

665. 非递减数列

https://leetcode-cn.com/problems/non-decreasing-array/

给你一个长度为 n 的整数数组,请你判断在 最多 改变 1 个元素的情况下,该数组能否变成一个非递减数列。我们是这样定义一个非递减数列的: 对于数组中所有的 i (0 <= i <= n-2),总满足 nums[i] <= nums[i + 1]。

示例 1:输入: nums = [4,2,3],输出: true
解释: 你可以通过把第一个4变成1来使得它成为一个非递减数列。
示例 2:输入: nums = [4,2,1],输出: false
解释: 你不能在只改变一个元素的情况下将其变为非递减数列。
说明:1 <= n <= 10 ^ 4,- 10 ^ 5 <= nums[i] <= 10 ^ 5

题解

一:暴力法,O(n^2)的时间复杂度,每次修改一个值,看是否满足非递减序列。下标0的元素特殊处理,取0,1的最小值,其余的在破坏非递减序列的时候,只需要让它等于他前面的一个元素,该元素也是最有可能使后面满足非递减条件的。

class Solution(object):
    def checkPossibility(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        def check(nums):
            for i in range(1, len(nums)):
                if nums[i] < nums[i - 1]:
                    return False 
            return True 

        n = len(nums)
        if n <= 2:
            return True 
        
        for i in range(1, n):
            if check(nums[: i] + [nums[i - 1]] + nums[i + 1: ]):
                return True 
        if check([min(nums[:2])] + [min(nums[:2])] + nums[2:]):
            return True 
        return False

二:找出破坏了非递减的元素,O(n)时间复杂度。

class Solution(object):
    def checkPossibility(self, nums):
        def check(nums):
            for i in range(1, len(nums)):
                if nums[i] < nums[i - 1]:
                    return False 
            return True 

        n = len(nums)
        if n <= 2:
            return True
        
        l = 1
        while l < n:
            if nums[l] < nums[l - 1]:
                break 
            l += 1

        if l >= n - 1:
            return True
        # nums[l - 1] > nums[l] 
        if l == 1:
            if check([min(nums[:2])] + nums[2:]):
                return True 
            return False
        
        if nums[l] < nums[l - 2]:
            if check(nums[: l] + [nums[l - 1]] + nums[l + 1:]):
                return True
            return False
        
        if nums[l] >= nums[l - 2]:
            if check(nums[: l - 1] + [nums[l]] + nums[l:]):
                return True
            return False

三:缩小问题规模,和二差不多。

class Solution(object):
    def checkPossibility(self, nums):
        n = len(nums)
        if n <= 2:
            return True 

        while len(nums) >= 3:
            if nums[0] <= nums[1] <= nums[2]:
                nums.pop(0) 
            else:
                break

        while len(nums) >= 3:
            if nums[-3] <= nums[-2] <= nums[-1]:
                nums.pop() 
            else:
                break
        n = len(nums)
        if n <= 2:
            return True 
        elif n == 3:
            if not (nums[0] > nums[1] > nums[2]):
                return True 
        elif n == 4:
            if nums[0]>nums[1]: 
                return False
            if nums[-1]<nums[-2]: 
                return False
            return nums[0]<=nums[1]<=nums[3] or nums[0]<=nums[2]<=nums[3]
        else:
            return False 
        return False

1395. 统计作战单位数

https://leetcode-cn.com/problems/count-number-of-teams/

 n 名士兵站成一排。每个士兵都有一个 独一无二 的评分 rating 。每 3 个士兵可以组成一个作战单位,分组规则如下:

从队伍中选出下标分别为 i、j、k 的 3 名士兵,他们的评分分别为 rating[i]、rating[j]、rating[k]
作战单位需满足: rating[i] < rating[j] < rating[k] 或者 rating[i] > rating[j] > rating[k] ,其中  0 <= i < j < k < n
请你返回按上述条件可以组建的作战单位数量。每个士兵都可以是多个作战单位的一部分。

示例 1:输入:rating = [2,5,3,4,1]、输出:3
解释:我们可以组建三个作战单位 (2,3,4)、(5,4,1)、(5,3,1) 。
示例 2:输入:rating = [2,1,3]、输出:0
解释:根据题目条件,我们无法组建作战单位。
示例 3:输入:rating = [1,2,3,4]、输出:4
提示:n == rating.length、1 <= n <= 200、1 <= rating[i] <= 10^5

题解

一:暴力法,时间复杂度O(n^3)

二:固定中间的,再看他前面和后面有几个比他大的和比他小的,时间复杂度O(n^2)。

class Solution(object):
    def numTeams(self, rating):
        """
        :type rating: List[int]
        :rtype: int
        """
        ans, n = 0, len(rating) 
        for i in range(1, n - 1):
            l_lt, l_gt = 0, 0
            for j in range(i):
                if rating[j] > rating[i]:
                    l_gt += 1
                elif rating[j] < rating[i]:
                    l_lt += 1
            r_lt, r_gt = 0, 0 
            for j in range(i + 1, n):
                if rating[j] > rating[i]:
                    r_gt += 1
                elif rating[j] < rating[i]:
                    r_lt += 1
            ans += l_lt * r_gt + l_gt * r_lt
        return ans

三:树状数组,参见《算法竞赛入门经典训练指南》P194,个人感觉讲的还是挺赞的,时间复杂度O(nlgm),n是rating的长度,m是rating的最大值。空间复杂度O(m)。

class Solution(object):
    def numTeams(self, rating):
        def add(rec, i, num):
            while i < len(rec):
                rec[i] += num
                i += (i & (-i))

        def get(rec, i):
            ans = 0 
            while i > 0:
                ans += rec[i]
                i -= (i & (-i))
            return ans
             
        max_num, n = max(rating), len(rating)
        rec = [0] * (max_num + 1)
        left_less =[0] * n
        left_large = [0] * n
        for i in range(n):
            left_less[i] = get(rec, rating[i])
            add(rec, rating[i], 1)
            left_large[i] = i - left_less[i]

    
        rec = [0] * (max_num + 1)
        right_less =[0] * n
        right_large = [0] * n
        for i in range(n - 1, -1, -1):
            right_less[i] = get(rec, rating[i]) 
            add(rec, rating[i], 1)
            right_large[i] = n - i - right_less[i] - 1
        ans = 0
        for i in range(1, n - 1):
            ans += left_less[i] * right_large[i] + left_large[i] * right_less[i]

        return ans

四:针对三的优化,因为相对于最大值来说,rating的规模是比较小的,可以进行压缩,让时间复杂度O(nlgn),空间复杂度O(n)。参见官方题解方法三,离散化树状数组https://leetcode-cn.com/problems/count-number-of-teams/solution/tong-ji-zuo-zhan-dan-wei-shu-by-leetcode-solution/

class Solution(object):
    def numTeams(self, rating):
        def add(rec, i, num):
            while i < len(rec):
                rec[i] += num
                i += (i & (-i))

        def get(rec, i):
            ans = 0 
            while i > 0:
                ans += rec[i]
                i -= (i & (-i))
            return ans
        def get_id(arr, target):
            l, r = 0, len(arr)
            while l < r:
                mid = l + (r - l) // 2
                if arr[mid] == target:
                    return mid 
                elif arr[mid] < target:
                    l = mid + 1
                else:
                    r = mid

        n = len(rating)
        rec = [0] * (200 + 1)
        left_less =[0] * n
        left_large = [0] * n
        rating_copy = sorted(rating)
        for i in range(n):
            idx = get_id(rating_copy, rating[i]) + 1
            left_less[i] = get(rec, idx)
            add(rec, idx, 1)
            left_large[i] = i - left_less[i]

        rec = [0] * (200 + 1)
        right_less =[0] * n
        right_large = [0] * n
        for i in range(n - 1, -1, -1):
            idx = get_id(rating_copy, rating[i]) + 1
            right_less[i] = get(rec, idx) 
            add(rec, idx, 1)
            right_large[i] = n - i - right_less[i] - 1
        ans = 0
        for i in range(1, n - 1):
            ans += left_less[i] * right_large[i] + left_large[i] * right_less[i]

        return ans

357. 计算各个位数不同的数字个数

https://leetcode-cn.com/problems/count-numbers-with-unique-digits/

给定一个非负整数 n,计算各位数字都不同的数字 x 的个数,其中 0 ≤ x < 10n 。

示例:

输入: 2
输出: 91 
解释: 答案应为除去 11,22,33,44,55,66,77,88,99 外,在 [0,100) 区间内的所有数字。

题解

一:数学方法,我们可以容易的推算出固定一个n位的符合的数字的个数,然后把小于等于n位的所有数字的个数加一下。

解题思路
参数定义

n:数字的位数
i:遍历到的整数含i个数字
res:返回值,数字为1~i个的整数中不含重复数字的总和
cur:整数位数为i时无重复数字的个数
k:0~9中剩余可选数字的个数
思路

由于数字只有0~9十个,所以当n大于10时,必然会有重复,此时不同数字的结果和n为10时相同
当n=0时,满足条件的只有0,即个数为res=1
当n=1时,满足条件的数为0~9,即个数为res=10
当n=2时,数字包含两位时,第一位可选1~9中的数C(9,1),第二位可选0~10中除去第一位选择的数C(9,1),即cur=9*9,再加上一位数字的情况res+=cur,即res=10+81=91
当n=3时,数字包含三位时,第一位第一位可选1~9中的数C(9,1),第二位可选0~9中除去第一位选择的数C(9,1),第三位可选0~9中除去前两位选择的数C(8,1),即cur=9*9*8,再加上一位数字和两位数字的情况res+=cur,即res=91+648=739
复杂度分析

时间复杂度:O(N)
空间复杂度:O(1)

class Solution(object):
    def countNumbersWithUniqueDigits(self, n):
        """
        :type n: int
        :rtype: int
        """
        """固定位数n符合条件的数字的个数"""
        def perm(n):
            if n == 0:
                return 1
            elif n > 10:
                return 0
            res = 9 
            # 9, 9, 8, 7
            # 9, 8, 7
            for i in range(0, n - 1):
                res *= (9 - i)
            return res 

        ans = 0
        for i in range(n + 1):
            ans += perm(i)
        return ans

二:动态规划,其实同数学方法差不多,还可以优化一下空间。这边当n>=1时dp[1:]表示不同的数位,一共n个数位。

class Solution(object):
    def countNumbersWithUniqueDigits(self, n):
        if n == 0:
            return 1
        dp = [0] * (n + 1)
        dp[0], dp[1] = 1, 9
        ans = 10
        for i in range(1, n):
            dp[i + 1] = dp[i] * (10 - i)
            ans += dp[i + 1]
            if dp[i] == 0:
                return ans
        return ans
class Solution(object):
    def countNumbersWithUniqueDigits(self, n):
        if n == 0:
            return 1
        ans, dp = 10, 9
        for i in range(1, n):
            dp *= (10 - i)
            ans += dp
            if dp == 0:
                return ans
        return ans

1291. 顺次数

https://leetcode-cn.com/problems/sequential-digits/

我们定义「顺次数」为:每一位上的数字都比前一位上的数字大 1 的整数。请你返回由 [low, high] 范围内所有顺次数组成的 有序 列表(从小到大排序)。

示例 1:输出:low = 100, high = 300,输出:[123,234]
示例 2:输出:low = 1000, high = 13000,输出:[1234,2345,3456,4567,5678,6789,12345]
提示:10 <= low <= high <= 10^9

题解

一:还是同上一题一样的思路固定位数,每当固定数据位数为n时,我们就能很方便的列出该位数的所有数据。

class Solution(object):
    def sequentialDigits(self, low, high):
        """
        :type low: int
        :type high: int
        :rtype: List[int]
        """
        # 1 2 3 , 9 - n + 1
        # 2 3 4 , 
        # n位数符合要求的数据
        def cnt(n, low, high, l_n, h_n):
            ans = []
            if n != l_n and n != h_n:
                for i in range(1, 10 - n + 1):
                    ans.append(int("".join(str(i + j) for j in range(n))))
            else:
                for i in range(1, 10 - n + 1):
                    num = int("".join(str(i + j) for j in range(n)))
                    if int(low) <= num <= int(high):
                        ans.append(num)  
            return ans
            
        l_n, h_n = len(str(low)), len(str(high))
        ans = []
        low, high = str(low), str(high)
        for i in range(l_n, h_n + 1):
            l = cnt(i, low, high, l_n, h_n)
            ans.extend(l)
        return ans

二:枚举,转自官方题解, https://leetcode-cn.com/problems/sequential-digits/solution/shun-ci-shu-by-leetcode-solution/, 枚举。我们可以枚举所有的「顺次数」,并依次判断它们是否在 [low, high] 的范围内。

具体地,我们首先枚举「顺次数」的最高位数字 i,随后递增地枚举「顺次数」的最低位数字 j,需要满足 j > i。对于每一组 (i, j),我们可以得到其对应的「顺次数」num,如果 num 在 [low, high] 的范围内,就将其加入答案中。

在枚举完所有的「顺次数」后,我们将答案进行排序,就可以得到最终的结果。

复杂度分析:时间复杂度:O(1)。根据定义,每一组满足1 \leq i < j \leq 9的 (i, j) 就对应了一个「顺次数」,那么「顺次数」的数量为 \binom{9}{2} = \frac{9 \times 8}{2} = 36个,可以视作一个常数。因此时间复杂度为 O(1)。

lass Solution:
    def sequentialDigits(self, low: int, high: int) -> List[int]:
        ans = list()
        for i in range(1, 10):
            num = i
            for j in range(i + 1, 10):
                num = num * 10 + j
                if low <= num <= high:
                    ans.append(num)
        return sorted(ans)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值