484.Find Permutation

Tags: [permutation], [lexicographically], [string], [reverse], [greedy], [trick]

Com: {g}

Link: https://leetcode.com/problems/find-permutation/\#/description

By now, you are given a secret signature consisting of character 'D' and 'I'. 'D' represents a decreasing relationship between two numbers, 'I' represents an increasing relationship between two numbers. And our secret signature was constructed by a special integer array, which contains uniquely all the different number from 1 to n (n is the length of the secret signature plus 1). For example, the secret signature "DI" can be constructed by array [2,1,3] or [3,1,2], but won't be constructed by array [3,2,4] or [2,1,3,4], which are both illegal constructing special string that can't represent the "DI"secret signature.

On the other hand, now your job is to find the lexicographically smallest permutation of [1, 2, ... n] could refer to the given secret signature in the input.

Example 1:

Input: "I"
Output:
 [1,2]

Explanation:
 [1,2] is the only legal initial spectial string can construct secret signature "I", where the number 1 and 2 construct an increasing relationship.

Example 2:

Input: "DI"
Output:
 [2,1,3]

Explanation:
 Both [2,1,3] and [3,1,2] can construct the secret signature "DI", 

but since we want to find the one with the smallest lexicographical permutation, you need to output [2,1,3]

Note:

The input string will only contain the character 'D' and 'I'.

The length of input string is a positive integer and will not exceed 10,000


Solution: Reverse

class Solution(object):
    def findPermutation(self, s):
        """
        :type s: str
        :rtype: List[int]
        """
        if not s:
            return [1]

        rest = [x for x in xrange(1, len(s) + 2)]
        i = 0
        while i < len(s):
            c = s[i]
            if c == 'D':
                end = i
                while end < len(s) and s[end] == 'D':
                    end += 1

                # if s[i:end] (not including end) contains all 'D',
                # then we should reverse rest from i to end (including end).
                self.reverse(rest, i, end)
                i = end
                continue
            i += 1

        return rest

    def reverse(self, arr, start, end):
        while start < end:
            arr[start], arr[end] = arr[end], arr[start]
            start += 1
            end -= 1

Revelation:

  • 在s中遇到连续的D的序列,例如s[3:7] (不包括index = 7) 中都是‘D’, 那么就reverse rest[3:8](包括index = 7,不包括index = 8), reverse 完后s的index指到8(即第一个不是'D'的char),遇到‘I’ 就略过.
  • 为什么这个算法是对的,原因是,一开始rest是从小到大sorted的,遇到'I'我们不做任何处理,遇到‘D’ sub str时,就reverse相应的rest,即便这个‘D’ sub str前有‘I’, 因为这个sub str ‘D’ 在‘I’ 之后,所以不管reverse与不reverse这部分的rest都比前面的大,所以这就保证了‘I’ 的正确性,reverse 的 这段rest保证了‘D’ 的正确性,如果之后有‘I’, 因为这段‘D’ 对应的rest在后面 ‘I’ 对应的rest之前,所以这段‘D’ 对应的 rest都比后面‘I’ 对应的rest 小,这也就保证了后面的‘I’ 的正确性.

Note:

  • Time complexity = O(n), n is the length of given string.

results matching ""

    No results matching ""