动态编程,第n个字符串

时间:2018-10-22 18:58:34

标签: algorithm dynamic-programming

如何解决问题https://www.hackerearth.com/problem/algorithm/special-numbers-39d71325/

一个数字序列中的第一个数字是1。通过对第(i-1)个数字应用以下操作来构造序列中的每个第i个数字:

  • 用114代替1
  • 用1代替4

因此,顺序如下:

1,114,1141141,11411411141141114,...

编写一个程序以查找一个数字,该数字是此序列中第i个数字的第j个数字。如果第i个数字少于j个数字,则打印-1。

输入格式

  • 第一行:T(测试用例数)
  • 每个测试用例的第一行:两个以空格分隔的整数i和j

输出格式

对于每个测试用例,按此顺序打印一个数字,该数字是第i个数字的第j个数字。如果第i个数字少于j个数字,则打印-1。

约束

1 <= T <= 10000(10等于4的幂)

1 <= i <= 1000000(10等于6的幂)

1 <= j <= 1000000000000(10等于12的幂)


Sample input                            Sample output
4
2 2                                               1
2 3                                               4
3 6                                               4
3 7                                               1

说明

第一个测试用例:序列中的第二个数字是114,第二个数字是1。

第二个测试用例:序列中的第二个数字为114,第三个数字为4。

第3个测试用例:序列中的第3个数字是1141141,第6个数字是4。

第4个测试用例:序列中的第3个数字是1141141,第7个(最后一个)数字是1。


将所有字符串(最多ith个字符串)存储在vector中将花费大量时间。问题的标记是记忆(动态编程)。我想要使​​用记忆(动态编程)的代码/策略。


我不认为我的以下方法更接近于实际/正确的解决方案。


vector<string> v(15);行之后查看注释


如果这是询问此类问题的平台,请告诉我在哪里提出此类问题。

#include<iostream>
#include<string>
#include<vector>
#include<cstring>
#include<climits>
//#define tr(v,it) for(typeof(v.begin()) it=v.begin();it!=v.end();it++)
using namespace std;

int main() {
    vector<string> v(15);//v(14) runs under 1 sec even v(15) gives tle. So think how much time v(1000000) will take.
    v[0]="1";
    vector<string>::iterator it;
    int n,h,i,j,tc;
    string s,s1;


    char ch='a';
    for(it=v.begin()+1;it!=v.end();it++) {//set value
         s=*(it-1); s1="";
         for(unsigned int i=0;i<s.length();i++) {
             char ch=s[i];
             if(ch=='1') {
                 s1=s1+"114";
             }
             else {
                 s1=s1+'1';
             }
         }
         *it=s1;
    }
    /*for(it=v.begin();it!=v.end();it++) {//print value
        cout<<*it<<endl;
    }
    cin>>tc;
    while(tc--) {
        cin>>i>>j;
        cout<<v[i-1][j-1];

    }*/
    return 0;
}

//谢谢!

2 个答案:

答案 0 :(得分:1)

让我们看一下序列及其长度;

114
3
114 114 1
7
114 114 1 114 114 1 114
    7         7      3
   773       773     7
773 773 7 773 773 7 773
...

每个长度是先前序列与之前序列(即AKA)的两倍。

length(i) =
  2 * length(i - 1) + length(i - 2)

给出最终字符串中的位置,因为我们知道先前的序列长度,所以我们可以确定它是在(1)翻倍前一个的第一个,(2)翻倍前一个的第二个,还是(3)附加,倒数第二个顺序。

通过跟踪其位置,我们不断将其位置转换为先前序列之一,直到到达第一个序列。

例如:

    7         7      3
114 114 1 114 114 1 114
                  ^

我们知道前两个序列的长度为7和3,因此我们可以确定我们在第二个7长度序列的第7个索引上。现在我们继续:

114 114 1
        ^

前两个序列的长度分别为3和1,因此我们位于倒数第二个序列(长度为1的序列)的第一个索引上。

结果:1​​

答案 1 :(得分:0)

基于גלעדברקן的回答,这是Java代码:

private static void getDigit( int n, long k ) {
    long[] L = new long[n+1];
    L[1] = 1;
    L[2] = 3;
    long MAX = Long.parseUnsignedLong("1000000000000");
    for ( int i = 3; i <= n; i++ ) {
      L[i] = 2*L[i-1] + L[i-2];
      if ( L[i] >= MAX ) break;
    }

    Long k1 = Long.valueOf(k);
    String s = "114";
    while ( n > 2 ) {
      if ( k1 <= L[n-1] ) {
          n--;
      } else if ( k1 > L[n-1] && k1 <= 2*L[n-1] ) {
        k1 = k1 - L[n-1];
        n--;
      } else {
        k1 = k1 - 2*L[n-1];
        n = n - 2;
      }
    }
    System.out.println( String.valueOf( s.charAt(k1.intValue()-1)));
}

您可以通过传递不同的n,k值here对其进行测试。