Блог пользователя ybc_c

Автор ybc_c, 10 лет назад, По-английски

Hi All :-)

I think some of you may read this problem from hackerrank. Here is the link:

https://www.hackerrank.com/challenges/dynamic-programming-classics-the-longest-common-subsequence

Since the test data is so weak, the traditional O(mn) solution can pass all the test data. So let's assume the two strings can be as long as 10^5. In this case, how to solve this problem? I guess the time complexity of the solution should be O(500*10^5) but have no idea to code it ... :-(

  • Проголосовать: нравится
  • +3
  • Проголосовать: не нравится

»
10 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

Deleted

»
10 лет назад, # |
Rev. 4   Проголосовать: нравится 0 Проголосовать: не нравится

I think Hirschberg algorithm can be implemented in O(n*n*log(n)) time and O(n) space. But I don't know is it enough to get AC because i don't know time limit
Function int solveLCS(String x, String y) should return whole vector K[1]. And instead of

c1 = solveLCS( x1, y.substring(0, k) ) ; // LCS of first half
c2 = solveLCS( x2, y.substring(k, n) ) ; // LCS of second half

if ( c1 + c2 == c )

there should be

c1 = solveLCS( x1, y) ; // LCS of first half
c2 = solveLCS( x2.reverse(), y.reverse() ) ; // LCS of second half

if ( c1[k] + c2[n - k] == c )
»
10 лет назад, # |
Rev. 4   Проголосовать: нравится 0 Проголосовать: не нравится

There is an algorithm faster than O(N*M). Suppose that the sequences are A and B. For each element that occurs in A write its positions in B in decreasing order.

For the given case:

5 6

1 2 3 4 1

3 4 1 2 1 3

It should look like this:

1 -> (5,3)

2 -> (4)

3 -> (6,1)

4 -> (2)

Then replace each element in A with its list:

(5,3) (4) (6,1) (2) (5,3)

5 3 4 6 1 2 5 3

Find one of its longest increasing subsequences X(There are a lot of algorithms for doing this fast like binary search, fenwick tree, segment tree and so on).

Then just print B[X1], B[X2], ..., B[Xk].

For example we can take 3, 4 and 6 as an increasing subsequence. Then we just print B[3]=1, B[4]=2 and B[6]=1 which is a valid answer.

Edit: It's not faster every time. If there is a case where all numbers in the sequences are the same it will be slower. But it's good with random test cases. When you make the list for each number you can check which of the algorithms is better to use.

  • »
    »
    10 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

    You're wrong. Your algorithm fails on a very simple test:

    2
    1 1
    2
    1 1
    

    Furthermore, it is believed (or even proved, I'm not sure) that general LCS problem cannot be solved in o(NM).

    • »
      »
      »
      10 лет назад, # ^ |
      Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

      Why do you think that it fails? The list for 1 is (2,1) and the sequence is 2 1 2 1. Its longest increasing subsequence is of length 2 -> 1 2. And the answer is B[1], B[2] -> 1 1. It's not wrong.

      Note: We are to find a LCS of two sequences :)

      • »
        »
        »
        »
        10 лет назад, # ^ |
          Проголосовать: нравится +3 Проголосовать: не нравится

        Yep, sure, it should be LCS :)

        Yes, you're right, your algorithm passes this test, it was my misunderstanding.

»
10 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

There is an algo working in O(500·(N + M)). Here is the idea.

The standard DP for this problem is d[i][j] = k = LCS of S[0..i] and T[0..j]. Let's swap the parameter and the value: g[i][k] = minimal j that LCS of S[0..i] and T[0..j] = k.

Then, g[i][k] = min(g[i-1][k], nextOcc[s[i]][g[i-1][k-1]]), where nextOcc[c][j] is the position of the first occurrence of c in T after position j.

  • »
    »
    10 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    What is LIS in your text? We have to find LCS — longest common subsequence. How to calculate g[i][k] faster than n^2? What is 500?

    • »
      »
      »
      10 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      In this case k is 500. If you replace LIS with LCS in his text it should be valid. The transition state is also O(1), since g[i][k] only requires g[i-1][k] and g[i-1][k-1]. The definition of g[i][k] is just as stated above, just make sure you recognize which variables correspond to which.

    • »
      »
      »
      10 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      It's a typo, LIS should be read as LCS (never write anything late at night).

      The second parameter is a bound for the answer (500 in this exact problem).

      • »
        »
        »
        »
        10 лет назад, # ^ |
        Rev. 5   Проголосовать: нравится 0 Проголосовать: не нравится

        I have not seen this constraint beacause it was in section "output format". And problem statement still unclear "Print the longest common subsequence, with length no greater than 500". What if length of actual LCS is greater than 500? can I print any common subsquence with length 500, or only subsequence of actual LCS?