সি, 618 564 বাইট
d,M,N,A[9999][2];char*(R[9999][20]),b[1000];L(char**s,n){char*j[20],c,a=0;int x[n],y=n-1,z,i,t,m=0,w=1;for(;y;)x[y--]=999;for(;y<N;y++){for(i=0;i<n&&s[i]==R[y][i];i++);if(i/n){a=A[y][0];m=A[y][1];w=0;if(m+d<M||!a)goto J;else{c=a;goto K;}}}for(c=97;w&&c<'{';c++){K:t=1,y=1,z=1;for(i=0;i<n;j[i++]++){for(j[i]=s[i];*j[i]-c;j[i]++)t&=!!*j[i];y&=j[i]-s[i]>x[i]?z=0,1:0;}t&=!y;I:if(t){if(z)for(i=0;i<n;i++)x[i]=j[i]-s[i];d++,t+=L(j,n),d--,m=t>m?a=c,t:m;}}if(w){for(y=0;y<n;y++)R[N][y]=s[y];A[N][0]=a;A[N++][1]=m;}J:if(d+m>=M)M=d+m,b[d]=a;if(!d)N=0,M=0,puts(b);return m;}
এবং এখানে এটি "পাঠযোগ্যতা" এর জন্য অবমুক্ত করা হয়েছে:
d,M,N,A[9999][2];
char*(R[9999][20]),b[1000];
L(char**s,n){
char*j[20],c,a=0;
int x[n],y=n-1,z,i,t,m=0,w=1;
for(;y;)
x[y--]=999;
for(;y<N;y++){
for(i=0;i<n&&s[i]==R[y][i];i++);
if(i/n){
a=A[y][0];
m=A[y][1];
w=0;
if(m+d<M||!a)
goto J;
else{
c=a;
goto K;
}
}
}
for(c=97;w&&c<'{';c++){
K:
t=1,
y=1,
z=1;
for(i=0;i<n;j[i++]++){
for(j[i]=s[i];*j[i]-c;j[i]++)
t&=!!*j[i];
y&=j[i]-s[i]>x[i]?z=0,1:0;
}
t&=!y;
I:
if(t){
if(z)
for(i=0;i<n;i++)
x[i]=j[i]-s[i];
d++,
t+=L(j,n),
d--,
m=t>m?a=c,t:m;
}
}
if(w){
for(y=0;y<n;y++)R[N][y]=s[y];
A[N][0]=a;
A[N++][1]=m;
}
J:
if(d+m>=M)
M=d+m,b[d]=a;
if(!d)
N=0,M=0,puts(b);
return m;
}
মহিলা ও ভদ্রলোক, আমি একটি ভয়াবহ ভুল করেছি। এটা তোলে ব্যবহৃত সুন্দর হতে ... এবং এতে যান-কম ... এখন অন্তত এটা ফাস্ট ।
আমরা একটি পুনরাবৃত্ত ফাংশন সংজ্ঞায়িত করি যা অক্ষরের অ্যারে এবং স্ট্রিংয়ের সংখ্যার অ্যারে L
ইনপুট হিসাবে গ্রহণ করে। ফাংশন ফলাফল স্ট্রিংকে স্টডআউটে আউটপুট করে এবং ঘটনাক্রমে সেই স্ট্রিংয়ের অক্ষরগুলিতে আকার দেয়।s
n
অভিগমন
কোডটি বিভ্রান্ত হওয়া সত্ত্বেও, কৌশলটি এখানে খুব জটিল নয়। আমরা বরং একটি নিষ্পাপ পুনরাবৃত্ত আলগোরিদিম দিয়ে শুরু করি, যা আমি সিউডোকোড দিয়ে বর্ণনা করব:
Function L (array of strings s, number of strings n), returns length:
Create array of strings j of size n;
For each character c in "a-z",
For each integer i less than n,
Set the i'th string of j to the i'th string of s, starting at the first appearance of c in s[i]. (e.g. j[i][0] == c)
If c does not occur in the i'th string of s, continue on to the next c.
end For
new_length := L( j, n ) + 1; // (C) t = new_length
if new_length > best_length
best_character := c; // (C) a = best_character
best_length := new_length; // (C) m = best_length
end if
end For
// (C) d = current_depth_in_recursion_tree
if best_length + current_depth_in_recursion_tree >= best_found
prepend best_character to output_string // (C) b = output_string
// (C) M = best_found, which represents the longest common substring found at any given point in the execution.
best_found = best_length + current_depth;
end if
if current_depth_in_recursion_tree == 0
reset all variables, print output_string
end if
return best_length
এখন, এই অ্যালগরিদমটি নিজেরাই বেশ নৃশংস (তবে প্রায় 230 ডলার বাইটে ফিট হতে পারে, আমি খুঁজে পেয়েছি)। এইভাবে কেউ দ্রুত ফলাফল পায় না। এই অ্যালগরিদমটি স্ট্রিং দৈর্ঘ্যের সাথে অবিশ্বাস্যভাবে দুর্বল। এই অ্যালগরিদম নেই , তবে, মোটামুটি ভাল স্ট্রিং বৃহত্তর সংখ্যার স্কেল। শেষ পরীক্ষার কেসটি কার্যত তাত্ক্ষণিকভাবে সমাধান করা হবে, কারণ কোনও স্ট্রিংয়ের s
কোনও অক্ষরই c
মিল নেই have আমি উপরে দুটি বাস্তব কৌশল প্রয়োগ করেছি যার ফলে অবিশ্বাস্য গতি বৃদ্ধি পেয়েছিল:
প্রতি কল এ L
, আমাদের আগে এই একই ইনপুট দেওয়া হয়েছিল কিনা তা পরীক্ষা করে দেখুন । যেহেতু অনুশীলনে তথ্য একই পংক্তির মাধ্যমে একই স্ট্রিংগুলিতে প্রেরণ করা হয়, তাই আমাদের আসলে স্ট্রিংগুলির তুলনা করতে হবে না , কেবলমাত্র অবস্থানগুলি, যা দুর্দান্ত। যদি আমরা দেখতে পাই যে আমরা এই তথ্যটি আগে পেয়েছি, গণনাগুলি চালানোর দরকার নেই (বেশিরভাগ সময়, তবে আউটপুট পাওয়া এটিকে আরও জটিল করে তোলে) এবং আমরা কেবল দৈর্ঘ্য ফিরিয়ে দিয়ে পালাতে পারি। আমরা যদি কোনও মিল খুঁজে না পাই তবে ভবিষ্যতের কলগুলির সাথে তুলনা করতে এই ইনপুট / আউটপুটটির সেটটি সংরক্ষণ করুন। সি কোডে, দ্বিতীয় for
লুপটি ইনপুটটির সাথে মিল খুঁজে পাওয়ার চেষ্টা করে। পরিচিত ইনপুট পয়েন্টারগুলিতে সংরক্ষণ করা হয় R
এবং সংশ্লিষ্ট দৈর্ঘ্য এবং অক্ষরের আউটপুট মানগুলি সংরক্ষণ করা হয়A
। এই পরিকল্পনার রানটাইমের উপর বিশেষত দীর্ঘতর স্ট্রিংগুলির সাথে কঠোর প্রভাব ছিল।
প্রতিটি সময় আমরা অবস্থানে এটি c
মধ্যে s
, একটি সুযোগ আমরা ডান বাদুড় বন্ধ জানি যে কি আমরা পেয়েছি অনুকূল নয়। যদি প্রতিটি অবস্থানের অন্য কোনও বর্ণের কিছু পরিচিত অবস্থানের পরেc
উপস্থিত হয় তবে আমরা স্বয়ংক্রিয়ভাবে জানি যে এটি c
একটি সর্বোত্তম স্তরকে বাড়ে না কারণ আপনি এটিতে আরও একটি অক্ষর ফিট করতে পারেন fit এর অর্থ হ'ল অল্প ব্যয়ের জন্য আমরা L
বড় বড় স্ট্রিংয়ের জন্য কয়েকশ কল কল করতে পারি । উপরের সি y
কোডটিতে একটি পতাকা সেট রয়েছে যদি আমরা স্বয়ংক্রিয়ভাবে জানতে পারি যে এই চরিত্রটি একটি সাবপটিমাল স্ট্রিংয়ের দিকে পরিচালিত করে, এবং z
আমরা যদি এমন কোনও চরিত্র পাই যা অন্য কোনও পরিচিত চরিত্রের চেয়ে একচেটিয়াভাবে পূর্বের উপস্থিতিগুলি খুঁজে পেয়ে থাকে। অক্ষরের বর্তমানতম উপস্থিতি সংরক্ষণ করা হয়x
। এই ধারণার বর্তমান বাস্তবায়ন কিছুটা অগোছালো তবে অনেক ক্ষেত্রে প্রায় দ্বিগুণ কর্মক্ষমতা।
এই দুটি ধারণার সাহায্যে, এক ঘন্টার মধ্যে যা শেষ হয়নি তা এখন প্রায় 0.015 সেকেন্ড সময় নেয়।
সম্ভবত আরও অনেক ছোট কৌশল রয়েছে যা পারফরম্যান্সকে গতিময় করতে পারে, তবে এই মুহুর্তে আমি সবকিছু গল্ফ করার ক্ষমতা নিয়ে চিন্তিত হতে শুরু করি। আমি এখনও গল্ফ নিয়ে সন্তুষ্ট নই, তাই সম্ভবত আমি পরে এটিতে ফিরে আসব!
সময়
এখানে কিছু টেস্টিং কোড রয়েছে, যা আমি আপনাকে অনলাইনে চেষ্টা করার জন্য আমন্ত্রণ জানিয়েছি :
#include "stdio.h"
#include "time.h"
#define SIZE_ARRAY(x) (sizeof(x) / sizeof(*x))
int main(int argc, char** argv) {
/* Our test case */
char* test7[] = {
"nqrualgoedlf",
"jgqorzglfnpa",
"fgttvnogldfx",
"pgostsulyfug",
"sgnhoyjlnfvr",
"wdttgkolfkbt"
};
printf("Test 7:\n\t");
clock_t start = clock();
/* The call to L */
int size = L(test7, SIZE_ARRAY(test7));
double dt = ((double)(clock() - start)) / CLOCKS_PER_SEC;
printf("\tSize: %d\n", size);
printf("\tElapsed time: %lf s\n", dt);
return 0;
}
আমি অপ্টিমাইজেশন সেটিং সহ একটি 1.7 গিগাহার্টজ ইন্টেল কোর আই 7 চিপযুক্ত একটি ল্যাপটপে ওপির পরীক্ষার কেসগুলি চালিয়েছি -Ofast
। সিমুলেশনটি 712KB প্রয়োজনের একটি শীর্ষের প্রতিবেদন করেছে। সময় সহ প্রতিটি পরীক্ষার মামলার উদাহরণ এখানে দেওয়া হয়েছে:
Test 1:
a
Size: 1
Elapsed time: 0.000020 s
Test 2:
x
Size: 1
Elapsed time: 0.000017 s
Test 3:
hecbpyhogntqppcqgkxchpsieuhbmcbhuqdjbrqmclchqyfhtdvdoysuhrrl
Size: 60
Elapsed time: 0.054547 s
Test 4:
ihicvaoodsnktkrar
Size: 17
Elapsed time: 0.007459 s
Test 5:
krkk
Size: 4
Elapsed time: 0.000051 s
Test 6:
code
Size: 4
Elapsed time: 0.000045 s
Test 7:
golf
Size: 4
Elapsed time: 0.000040 s
Test 8:
Size: 0
Elapsed time: 0.000029 s
Total time: 0.062293 s
গল্ফিংয়ের ক্ষেত্রে, আমি পারফরম্যান্সের পরিবর্তে উল্লেখযোগ্যভাবে হিট করেছি এবং যেহেতু লোকেরা আমার আগের 618-বাইট সমাধানের ব্রুট স্পিড (0.013624 গুলি সংযুক্ত সমস্ত পরীক্ষার সংশ্লেষ সম্পন্ন করতে) পছন্দ করেছে, তাই আমি এখানে রেফারেন্সের জন্য রেখে দেব:
d,M,N,A[9999][2];char*(R[9999][20]),b[1000];L(char**s,n){char*j[20],c,a=0;int x[n],y,z,i,t,m=0,w=1;for(y=0;y<n;y++)x[y]=999;for(y=0;y<N;y++){for(i=0;i<n;i++)if(s[i]!=R[y][i])break;if(i==n){a=A[y][0];m=A[y][1];w=0;if(m+d<M||!a)goto J;else{c=a;goto K;}}}for(c=97;w&&c<'{';c++){K:t=1,y=1,z=1;for(i=0;i<n;j[i++]++){for(j[i]=s[i];*j[i]-c;j[i]++)if(!*j[i]){t=0;goto I;}if(j[i]-s[i]>x[i])z=0;if(j[i]-s[i]<x[i])y=0;}if(y){t=0;}I:if(t){if(z){for(i=0;i<n;i++){x[i]=j[i]-s[i];}}d++,t+=L(j,n),d--,m=t>m?(a=c),t:m;}}if(w){for(y=0;y<n;y++)R[N][y]=s[y];A[N][0]=a;A[N++][1]=m;}J:if(d+m>=M)M=d+m,b[d]=a;if(!d)N=0,M=0,puts(b);return m;}
অ্যালগরিদম নিজেই অপরিবর্তিত, তবে নতুন কোডটি বিভাগগুলি এবং কিছু কৌশলযুক্ত বিটওয়াইজ অপারেশনগুলির উপর নির্ভর করে যা পুরো বিষয়টি ধীর করে দেয়।