【后缀数组】[UVA10829]L-Gap substring

本文介绍了一种使用后缀数组解决 L-Gap 字串问题的方法,通过枚举相同子串长度并利用后缀数组查找间隔 g 的相同子串,实现对字符串中特定模式的有效搜索。

题目
分析,这道题很显然要找两个相同的字串,也就是两个后缀公共前缀,很自然地可以想到,可以使用后缀数组。
所谓的L-Gap字串,就是两个相同的字串,中间间隔了g个字符,所以,我们枚举这两个字串的长度l,然后看0和l,l和l*2…..分别从这两个位置向前和向后匹配,匹配的长度减去l就是这个位置对答案的贡献。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define MAXN 50000*2
#define MAXC 128
#define Log 17
int array[4][MAXN+10],st[MAXN+10][Log+1],g,*sa,*nsa,*rk,*nrk,b[MAXN+10],n,na,m,T,height[MAXN+10],ans,cnt;
char s[MAXN+10];
void Read(int &x){
    char c;
    while(c=getchar(),c!=EOF)
        if(c>='0'&&c<='9'){
            x=c-'0';
            while(c=getchar(),c>='0'&&c<='9')
                x=x*10+c-'0';
            ungetc(c,stdin);
            return;
        }
}
void cal_sa(){
    rk=array[0],nrk=array[1],sa=array[2],nsa=array[3];
    int i,k;
    rk[n]=nrk[n]=-1;
    memset(b,0,sizeof b);
    for(i=0;i<n;i++)
        b[s[i]]++;
    for(i=1;i<=MAXC;i++)
        b[i]+=b[i-1];
    for(i=0;i<n;i++)
        sa[--b[s[i]]]=i;
    for(rk[sa[0]]=0,i=1;i<n;i++){
        rk[sa[i]]=rk[sa[i-1]];
        if(s[sa[i]]!=s[sa[i-1]])
            rk[sa[i]]++;
    }
    for(k=1;rk[sa[n-1]]<n-1;k<<=1){
        for(i=0;i<n;i++)
            b[rk[sa[i]]]=i;
        for(i=n-1;i>=0;i--)
            if(sa[i]>=k)
                nsa[b[rk[sa[i]-k]]--]=sa[i]-k;
        for(i=n-k;i<n;i++)
            nsa[b[rk[i]]--]=i;
        for(nrk[nsa[0]]=0,i=1;i<n;i++){
            nrk[nsa[i]]=nrk[nsa[i-1]];
            if(rk[nsa[i]]!=rk[nsa[i-1]]||rk[nsa[i]+k]!=rk[nsa[i-1]+k])
                nrk[nsa[i]]++;
        }
        swap(sa,nsa);
        swap(rk,nrk);
    }
}
void read(){
    Read(g);
    scanf("%s",s);
    na=strlen(s);
    s[na]='$';
    int i;
    for(i=1;i<=na;i++)
        s[na+i]=s[na-i];
    n=(na<<1)|1;
    s[n]=0;
}
void cal_height(){
    int i,j,k=0;
    for(i=0;i<n;i++)
        if(!rk[i])
            height[rk[i]]=0;
        else{
            if(k)
                k--;
            for(j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
            height[rk[i]]=k;
        }
}
void prepare(){
    int i,j;
    for(i=0;i<n;i++)
        st[i][0]=height[i];
    for(j=1;j<=Log;j++)
        for(i=0;i<n;i++)
            if(i+(1<<(j-1))<n)
                st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
int Get_st(int rk1,int rk2){
    if(rk1>rk2)
        swap(rk1,rk2);
    int t=log2(rk2-rk1);
    return min(st[rk1+1][t],st[rk2-(1<<t)+1][t]);
}
void solve(){
    int i,j,k,t;
    for(i=1;i<na;i++){
        for(j=0;j<na&&j+i+g<na;j+=i){
            k=i+j+g;
            t=min(Get_st(rk[j],rk[k]),i);
            t+=min(Get_st(rk[n-j],rk[n-k]),i-1);
            ans+=max(t-i+1,0);
        }
    }
}
int main()
{
    Read(T);
    while(T--){
        memset(st,0,sizeof st);
        ans=0;
        read();
        cal_sa();
        cal_height();
        prepare();
        solve();
        printf("Case %d: %d\n",++cnt,ans);
    }
}
<think>好的,我现在需要帮助用户解决如何用JavaScript或Ajax处理日期数组,去掉年份部分并渲染到页面上。首先,用户的问题明确:他们有一个包含日期字符串的数组,如['2025-04-12', '2026-05-23'],想要转换成['04-12', '05-23'],并展示在网页中。 首先,我要回顾用户之前的对话历史。之前用户询问如何用jq处理同样的日期转换,我提供了几种方法,包括split和正则表达式。现在用户转向JavaScript的实现,可能需要类似的方法,但用JS语法。同时,用户提到了Ajax,可能需要从服务器获取数据,但问题中并没有具体说明Ajax的部分,可能只是获取数据后的处理。 接下来,用户提供的引用内容可能相关。引用[1]展示了如何用JavaScript获取当前日期并格式化为YYYY-MM-DD,包括补零操作。引用[2]则关于apply和call的使用,可能在合并数组时有帮助,但当前问题中是否需要合并数组?用户的需求是转换数组中的每个元素,所以可能用map方法更合适。不过引用中的内容可能可以作为参考,比如处理数组的方法。 现在,用户的需求分两部分:处理日期数组和渲染到页面。处理数组方面,需要遍历每个日期字符串,去掉年份,保留月份和日期。可能的实现方式有几种: 1. 使用字符串分割:split('-')后取后两个元素,再拼接。如dateStr.split('-').slice(1).join('-')。 2. 使用substring或slice方法:由于日期格式固定,年份是前4个字符,可以直接截取从第5个字符开始的部分。例如dateStr.substring(5)。 3. 正则表达式替换:用正则匹配年份部分并替换为空,但需要保留后面的部分。例如replace(/^\d{4}-/, '')。 需要考虑日期的格式是否固定。如果日期字符串都是YYYY-MM-DD格式,那么方法2最简单高效。但如果月份或日期可能为单数字(如2025-4-12),则split方法并手动补零可能更可靠。但根据用户提供的例子,日期已经是补零的,所以可能可以直接使用substring或slice。 然后是渲染到页面。用户可能希望将处理后的数组显示为列表或其他形式。可以用JavaScript动态创建DOM元素,比如用ul和li,或者直接插入到div中。 另外,用户提到使用Ajax获取数组,所以可能需要先通过Ajax请求获取数据,再进行处理。但用户的问题中没有给出具体的Ajax代码,可能需要补充这部分,比如使用fetch或XMLHttpRequest。 现在,综合这些信息,我需要分步骤给出解决方案: 1. 数据获取:使用Ajax(如fetch API)从服务器获取日期数组。 2. 数据处理:将每个日期字符串转换为月-日格式。 3. 数据渲染:将处理后的数组插入到网页的DOM中。 在数据处理部分,选择合适的方法。如果日期格式固定,推荐使用substring,因为效率高。如果有不确定因素,比如可能没有补零,可以使用split方法并处理补零,但根据用户之前的例子,可能不需要。 还需要考虑错误处理,比如日期字符串是否有效,但用户的问题中可能暂时不需要,可以假设数据正确。 关于引用[1]中的补零操作,如果在处理过程中月份或日期可能为单数字,需要补零,但用户提供的例子中已经是两位,所以可能不需要。但为了代码的健壮性,可以加入补零的处理,比如在split后对月份和日期进行检查,确保两位。不过这可能超出当前需求,用户可能只需要简单的截取。 现在,具体步骤: 使用Ajax获取数据,假设返回的是JSON数组。例如: fetch('url').then(response => response.json()).then(data => { // 处理数据 const processed = data.map(date => date.substring(5)); // 渲染到页面 }); 然后渲染部分,可以用createElement和appendChild,或者使用模板字符串插入innerHTML。 例如,创建一个ul元素,将每个处理后的日期作为li添加进去。 可能还需要考虑浏览器的兼容性,但用户没有特别说明,所以使用现代JavaScript语法即可。 最后,给出完整代码示例,包括Ajax请求、数据处理和渲染,并解释每一步的作用。同时,可以提到不同的处理方法,如split和substring,以及它们的适用场景。</think>根据您的需求,我将分步骤讲解如何通过JavaScript实现日期格式转换与数据渲染: --- ### 一、基础实现方案 #### 1. 数据处理核心逻辑 ```javascript // 原始数据 const originalDates = ['2025-04-12', '2026-05-23']; // 方案1:字符串截取(推荐) const processedDates = originalDates.map(date => date.substring(5)); // 方案2:split+join方式 const processedDates = originalDates.map(date => { const [_, month, day] = date.split('-'); return `${month}-${day}`; }); // 两种方案结果相同:["04-12", "05-23"] ``` #### 2. 结合AJAX请求 ```javascript // 使用fetch API获取数据 fetch('/api/dates') .then(response => response.json()) .then(dates => { const processed = dates.map(date => date.substring(5)); renderDates(processed); }) .catch(error => console.error('获取数据失败:', error)); ``` --- ### 二、增强健壮性方案 #### 1. 格式校验与自动补零 ```javascript function formatDate(dateStr) { // 正则校验格式 if (!/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) return '无效日期'; const [year, month, day] = dateStr.split('-'); // 自动去除前导零(可选) return `${parseInt(month)}-${parseInt(day)}`; // 输出"4-12"格式 // 或保持原格式直接截取:dateStr.substring(5) } ``` #### 2. 处理单数字日期(参考引用[1]) ```javascript const processedDates = originalDates.map(date => { const [year, month, day] = date.split('-'); return `${month.padStart(2, '0')}-${day.padStart(2, '0')}`; }); ``` --- ### 三、页面渲染方案 #### 1. 动态创建DOM元素 ```javascript function renderDates(datesArray) { const container = document.getElementById('date-container'); // 清空旧内容 container.innerHTML = ''; // 创建列表 const ul = document.createElement('ul'); datesArray.forEach(date => { const li = document.createElement('li'); li.textContent = date; ul.appendChild(li); }); container.appendChild(ul); } ``` #### 2. 使用模板字符串 ```javascript function renderDates(datesArray) { const html = ` <div class="date-list"> ${datesArray.map(date => ` <div class="date-item">📅 ${date}</div> `).join('')} </div> `; document.getElementById('date-container').innerHTML = html; } ``` --- ### 四、完整工作流程 ```javascript // 完整示例 fetch('/api/dates') .then(res => res.json()) .then(dates => { const processed = dates.map(date => { if (!date.includes('-')) return '格式错误'; return date.substr(5); // 直接截取第6个字符开始的子串 }); document.getElementById('output').innerHTML = ` <h3>处理结果:</h3> ${processed.map(d => `<p>${d}</p>`).join('')} `; }); ``` --- ### 五、方案对比 | 方法 | 执行效率 | 优势 | 局限性 | |---------------------|----------|--------------------------|-------------------------| | substring截取 | O(n) | 性能最优,代码简洁 | 依赖固定格式 | | split+join | O(n) | 可处理动态分割符 | 多一次数组操作 | | 正则表达式 | O(n) | 可处理复杂格式 | 需要理解正则语法 | --- ### 六、效果演示 输入数据:`['2025-04-12', '2026-05-23']` 页面渲染效果: ```html <div id="date-container"> <ul> <li>04-12</li> <li>05-23</li> </ul> </div> ``` --- ### 七、错误排查技巧 1. 使用`console.log`检查中间结果: ```javascript dates.map(date => { console.log('原始数据:', date); // 打印原始值 const processed = date.substring(5); console.log('处理后:', processed); // 验证处理结果 return processed; }); ``` 2. 添加异常捕获: ```javascript try { const processed = date.substring(5); } catch (e) { console.warn('日期处理异常:', date); return 'N/A'; } ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值