以下是一个名为codility的编码访谈网站的演示问题:
字符串S的前缀是S的任何前导连续部分。例如," c"和" cod"是字符串" codility"的前缀。为简单起见,我们要求前缀为非空。
字符串S的前缀P的乘积是P的出现次数乘以P的长度。更准确地说,如果前缀P由K个字符组成而P在S中恰好出现T次,那么乘积等于K *吨。
例如,S =" abababa"具有以下前缀:
- " a",其产品等于1 * 4 = 4,
- " ab",其产品等于2 * 3 = 6,
- " aba",其产品等于3 * 3 = 9,
- " abab",其产品等于4 * 2 = 8,
- " ababa",其产品等于5 * 2 = 10,
- " ababab",其产品等于6 * 1 = 6,
- " abababa",其产品等于7 * 1 = 7。
最长前缀与原始字符串相同。目标是选择这样的前缀以最大化产品的价值。在上面的例子中,最大乘积是10。
以下是我在Java中的糟糕解决方案,需要O(N ^ 2)时间。显然可以在O(N)中执行此操作。我在考虑Kadanes算法。但我无法想到任何可以在每个步骤编码某些信息的方法,这些信息可以让我找到最大运行时间。任何人都可以为此考虑O(N)算法吗?
'........, IsDeleted,bCensusCount, Vgtl, Vstd, ' + @colnames + ' ' + char(13)
答案 0 :(得分:2)
这是一个基于后缀数组的O(n log n)版本。后缀数组有O(n)构造算法,我只是没有耐心对它们进行编码。
示例输出(此输出不是O(n),但它只是表明我们确实可以计算所有分数):
4*1 a
3*3 aba
2*5 ababa
1*7 abababa
3*2 ab
2*4 abab
1*6 ababab
基本上你必须反转字符串,并计算后缀数组(SA)和最长公共前缀(LCP)。
然后,您向后遍历SA数组,查找与整个后缀匹配的LCP(原始字符串中的前缀)。如果匹配,则递增计数器,否则将其重置为1.每个后缀(前缀)都会收到与其在原始字符串中出现的次数相对应的“得分”(SCR)。
#include <iostream>
#include <cstring>
#include <string>
#define MAX 10050
using namespace std;
int RA[MAX], tempRA[MAX];
int SA[MAX], tempSA[MAX];
int C[MAX];
int Phi[MAX], PLCP[MAX], LCP[MAX];
int SCR[MAX];
void suffix_sort(int n, int k) {
memset(C, 0, sizeof C);
for (int i = 0; i < n; i++)
C[i + k < n ? RA[i + k] : 0]++;
int sum = 0;
for (int i = 0; i < max(256, n); i++) {
int t = C[i];
C[i] = sum;
sum += t;
}
for (int i = 0; i < n; i++)
tempSA[C[SA[i] + k < n ? RA[SA[i] + k] : 0]++] = SA[i];
memcpy(SA, tempSA, n*sizeof(int));
}
void suffix_array(string &s) {
int n = s.size();
for (int i = 0; i < n; i++)
RA[i] = s[i] - 1;
for (int i = 0; i < n; i++)
SA[i] = i;
for (int k = 1; k < n; k *= 2) {
suffix_sort(n, k);
suffix_sort(n, 0);
int r = tempRA[SA[0]] = 0;
for (int i = 1; i < n; i++) {
int s1 = SA[i], s2 = SA[i-1];
bool equal = true;
equal &= RA[s1] == RA[s2];
equal &= RA[s1+k] == RA[s2+k];
tempRA[SA[i]] = equal ? r : ++r;
}
memcpy(RA, tempRA, n*sizeof(int));
}
}
void lcp(string &s) {
int n = s.size();
Phi[SA[0]] = -1;
for (int i = 1; i < n; i++)
Phi[SA[i]] = SA[i-1];
int L = 0;
for (int i = 0; i < n; i++) {
if (Phi[i] == -1) {
PLCP[i] = 0;
continue;
}
while (s[i + L] == s[Phi[i] + L])
L++;
PLCP[i] = L;
L = max(L-1, 0);
}
for (int i = 1; i < n; i++)
LCP[i] = PLCP[SA[i]];
}
void score(string &s) {
SCR[s.size()-1] = 1;
int sum = 1;
for (int i=s.size()-2; i>=0; i--) {
if (LCP[i+1] < s.size()-SA[i]-1) {
sum = 1;
} else {
sum++;
}
SCR[i] = sum;
}
}
int main() {
string s = "abababa";
s = string(s.rbegin(), s.rend()) +".";
suffix_array(s);
lcp(s);
score(s);
for(int i=0; i<s.size(); i++) {
string ns = s.substr(SA[i], s.size()-SA[i]-1);
ns = string(ns.rbegin(), ns.rend());
cout << SCR[i] << "*" << ns.size() << " " << ns << endl;
}
}
这些代码中的大部分(特别是后缀数组和LCP实现)我已经在竞赛中使用了几年。这个版本特别改编自this one I wrote some years ago。
答案 1 :(得分:0)
public class Main {
public static void main(String[] args) {
String input = "abababa";
String prefix;
int product;
int maxProduct = 0;
for (int i = 1; i <= input.length(); i++) {
prefix = input.substring(0, i);
String substr;
int occurs = 0;
for (int j = prefix.length(); j <= input.length(); j++) {
substr = input.substring(0, j);
if (substr.endsWith(prefix))
occurs++;
}
product = occurs*prefix.length();
System.out.println("product of " + prefix + " = " +
prefix.length() + " * " + occurs +" = " + product);
maxProduct = (product > maxProduct)?product:maxProduct;
}
System.out.println("maxProduct = " + maxProduct);
}
}
答案 2 :(得分:0)
我已经解决了这个挑战超过4天,阅读了大量文档,发现了O(N)的解决方案。
我有81%的想法,使用窗口幻灯片很简单。
def解决方案(s:字符串):Int = {
var max = s.length // length of the string
var i, j = 1 // start with i=j=1 ( is the beginning of the slide and j the end of the slide )
val len = s.length // the length of the string
val count = Array.ofDim[Int](len) // to store intermediate results
while (i < len - 1 || j < len) {
if (i < len && s(0) != s(i)) {
while (i < len && s(0) != s(i)) { // if the begin of the slide is different from
// the first letter of the string skip it
i = i + 1
}
}
j = i + 1
var k = 1
while (j < len && s(j).equals(s(k))) { // check for equality and update the array count
if (count(k) == 0) {
count(k) = 1
}
count(k) = count(k) + 1
max = math.max((k + 1) * count(k), max)
k = k + 1
j = j + 1
}
i = i + 1
}
max // return the max
}