跳转至

32. Longest Valid Parentheses

Leetcode String Dynamic Programming

题目

[Hard]

Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring.

For "(()", the longest valid parentheses substring is "()", which has length = 2.

Another example is ")()())", where the longest valid parentheses substring is "()()", which has length = 4.

中文题目

实现下一个排列,将排列中的数字重新排列成字典序中的下一个更大的排列。

如果这样的重新排列是不可能的,它必须重新排列为可能的最低顺序(即升序排序)。

重排必须在原地,不分配额外的内存。

以下是一些示例,左侧是输入,右侧是输出:

1,2,31,3,2 3,2,11,2,3 1,1,51,5,1

思路

做题目前,应该先理解排列permuation的概念,以及next permutation的含义。例如题目例子里的1,2,3的全排列,依次是:

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

next permuation的含义是从上面的第i行到第i+1行,如果是最后一行,则为第1行。

首先,应该了解到在前面变换数字,会导致排列增加很多,例如从1 2 33 2 1。所以既然要找到比原来的数的排列大一点的数,自然是从后往前找。如果数组从尾到前是增加的,那么就表明,从尾到前增加的这几个数字已经是最大的排列了,不能增加了。所以,我们的目标是找到从尾到前是减小的数字。

假设数组从尾到前是增加的,然后在有一个地方出现了反转,例如数组:[1,5,8,4,7,6,5,3,1]在7和4的位置出现减小,我们需要做的就是找到该数字,将数字与最接近于并大于该数的数字交换(这里是5)。交换了以后,排列立刻增加了,但是后面的排列仍旧是非常大的。所以应该将之后的数组变成升序排列,也就是将后面的数的排列降到最低。可以分为下面三个步骤:

  • 从尾到前,找到反转点
  • 从尾部向前找到后半区比该值(1)大的数,交换两个数
  • 将后面的数组变成升序排列

图片来自leetcode

也就是说如果对于一个全排列a_1,a_2,a_3,...,a_k来说,如果满足a_1 < a_2 ≥ a_3 ≥ a_4 ... ≥ a_k(所有a_1开头的全排列中字典序最大的情况),就说明这个全排列的下一个全排列不能再由a_1开头,而是a_1在字典中的下一个元素a_j(即满足a_j > a_12 ≤ j ≤ k的最小的a_j),由于任何a_j开头的全排列都大于a_1开头的全排列,所以我们寻找的全排列是a_j开头的最小的全排列。

class Solution(object):
    def nextPermutation(self, nums):
        """
        :type nums: List[int]
        :rtype: void Do not return anything, modify nums in-place instead.
        """
        n = len(nums)

        # 特殊情况,空的列表或只有一个元素
        if n < 2:
            return


        # 找到从尾到前开始减小的数的下标loc
        loc = None
        for i in reversed(range(1, n)):
            # 找到了
            if  nums[i-1] < nums[i]:
                loc = i-1
                break

        # 始终没有找到,即已经是最大排列,直接反转
        if loc is None:
            nums.reverse()

        else:
            # 找到了该数字,将数字与最接近于并大于该数的数字交换
            larger_than_loc = filter(lambda x: x > nums[loc], nums[loc+1:])
            number_index = nums[loc+1:].index(min(larger_than_loc)) + loc + 1
            nums[number_index], nums[loc] = nums[loc], nums[number_index]
            # 将后面的元素变成升序序列
            nums[loc+1:] = sorted(nums[loc+1:])

参考

  • https://shenjie1993.gitbooks.io/leetcode-python/031%20Next%20Permutation.html
  • https://www.tianmaying.com/tutorial/LC31
  • https://leetcode.com/problems/next-permutation/solution/