leetcode 316 321 单调栈强化

之前做过402,也是单调栈,那个题可以选择去掉k个数字后的最小数,这种思想其实和本次的两个题是一样的,就是贪心的去掉前面较大的数字即可。而leetcode 768则是稍复杂的单调栈,pop的元素不是移除,而是合并,保留的是最大值,这个题是很值得回味的。
回到316,这个题是一道难度超过medium的题,代码非常简单,思想不是那么容易。首先,与402类似,但咱们只能排出还能放进去的元素,所以要存个数组,放剩余的元素个数。第二个问题是,如果元素已在栈中,还要不要处理?答案很简单,不要。因为如果元素在栈中却没有被排出,说明在他后面的元素都比他大,所以没必要排出,不处理就好。代码如下:

class Solution:
    def removeDuplicateLetters(self, s: str) -> str:
        def c2i(c):
            return ord(c)-ord('a')

        d = [0 for _ in range(26)]
        for c in s:
            d[c2i(c)] += 1
        
        # push
        stack = []
        for c in s:
            d[c2i(c)] -= 1
            if c not in stack:
                while stack and c < stack[-1] and d[c2i(stack[-1])] > 0:
                    stack.pop()
                stack.append(c)

        return ''.join(stack)

321这个题也蛮有意思,也不太好想。他是一个组合,就是每个数组从1到k-1都组合一下,看看效果。原理和上面的题类似。

class Solution:
    def maxNumber(self, nums1: List[int], nums2: List[int], k: int) -> List[int]:
        # get a length k stack
        def get_stack(nums, k):
            if k == 0 or len(nums) < k: return []
            rem = len(nums) - k
            stack = []
            for num in nums:
                while stack and num > stack[-1] and rem > 0:
                    stack.pop()
                    rem -= 1
                stack.append(num)
            return stack[:k]

        # merge
        def merge(s1, s2, arr, k):
            # print('merge')
            result, p1, p2 = [], 0, 0
            while k > 0:
                k -= 1

                # check value
                if p1 < len(s1) and s1[p1:] > s2[p2:]:
                    result.append(s1[p1])
                    p1 += 1
                else:
                    result.append(s2[p2])
                    p2 += 1

            return max(arr, result)

        # generate different result
        result = max(get_stack(nums1, k), get_stack(nums2, k))
        for i in range(1, k):
            s1, s2 = get_stack(nums1, i), get_stack(nums2, k-i)
            if s1 and s2:
                result = merge(s1, s2, result, k)
        
        return result

上面的代码运行是比较慢的,因为用了list索引,这个是O(N)的复杂度,代价非常高,吃力不讨好。直接pop会好一点点,i和k-i的边界条件也可以更快些。

class Solution:
    def maxNumber(self, nums1: List[int], nums2: List[int], k: int) -> List[int]:
        # get a length k stack
        def get_stack(nums, k):
            if k == 0 or len(nums) < k: return []
            rem = len(nums) - k
            stack = []
            for num in nums:
                while stack and num > stack[-1] and rem > 0:
                    stack.pop()
                    rem -= 1
                stack.append(num)
            return stack[:k]

        # merge
        def merge(s1, s2, arr, k):
            result = []
            while s1 and s2:
                if s1 > s2:
                    result.append(s1.pop(0))
                else:
                    result.append(s2.pop(0))
            result += s1+s2
            return max(arr, result)

        # generate different result
        result = max(get_stack(nums1, k), get_stack(nums2, k))
        for i in range(1, k):
            s1, s2 = get_stack(nums1, i), get_stack(nums2, k-i)
            if s1 and s2:
                result = merge(s1, s2, result, k)
        
        return result
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值