字符串分区,以便分区按升序排列

时间:2018-06-27 10:55:02

标签: algorithm

给出一个数字字符串,例如"12335457"。有效分区是字符串的分区,因此每个段都严格大于前一个段。

例如,"12 | 33 | 54 | 57"是有效分区,而57 > 54 > 33 > 12是有效分区。另一个有效分区可以是"12 | 335 | 457"

给定的字符串可能有多少个有效分区?字符串的最大长度可以为5000

如果我们使用带有参数ij的动态编程,这意味着最后一段来自i ... to ..j,那么我们可以递归其余部分。

int solve(int i,int j) {
    // memoization need to be added
    int last_length = j - i + 1;
    int ans = 0;
    for(int k = j + last_length ; k < n ; k++) {
        if( segment(j+1,k) > segment(i,j) ) {   // this is possible in O(1) even if segment lengths are equal
                                                // we should do some pre preocessing on the given string
                                                // which can take O(n^2) time
                                                // if segment(j+1,k) length is more than L , then it is trivial
            ans += solve(j+1 , k);
        }
    }
}

但是这种方法将花费O(n ^ 3)的时间。如何从O(n ^ 3)减少它?

谢谢

2 个答案:

答案 0 :(得分:1)

观察:

  • 让我们将sudo apt-get install python-dev的最小值index称为segment(j + 1 , index) > segment(i, j),我们可以看到x
  • 所以,让我们叫solve(i, j) = sum( solve(j + 1, k) ) with x <= k < n,我们有我们的功能:

    dp[i][j] = sum(solve[i][k]) with j <= k < n
  • 最后一个问题是如何计算int solve(int i,int j) { // memoization need to be added int last_length = j - i + 1; int ans = 0; int index = getMinIndexForSegment(i,j) ans = solve(j + 1, index) + solve(i, j + 1); return ans; } ?我们意识到我们可以使用二进制搜索来快速找到其结果。

    getMinIndexForSegment

如OP所述,如果数字仅包含正数,那么我们只需要比较int getMinIndexForSegment (int i, int j){ int st = j + 1; int ed = n - 1; int res = n; while(st <= ed){ int mid = (st + ed)/2; if(segment(i, j) < seg(j + 1, mid)){ res = mid; ed = mid - 1; }else{ st = mid + 1; } } return res; } (i , j)(j + 1 , k)的两个段

答案 1 :(得分:1)

我们可以有一个O(n^2)算法。令f(i, j, s)代表直到段i的第s个字符并向后扩展j个字符的段为止的有效分区数。然后:

f(i, j, s):
  # A segment extending all the way to the start
  if i + 1 == j:
    return 1

  # A one-character segment that's smaller
  # than the preceding character
  if j == 1 and s[i] <= s[i - 1]:
    return 0

  segment = s[i - j + 1...i]

  # Find longest preceding segment in O(1)
  longest = 
    a segment of length j extending back
    from s[i - j] or length (j-1) if the first
    segment was equal or larger than segment

  # Replace 'sum' with O(1) prefix sum calculation
  # since we can record that for each previous i
  # as we increase j
  return sum(f(i - j, k, s) for k = 1 to length(longest))