相邻字符串之间的最长公共前缀
相邻字符串之间的最长公共前缀
第456场周赛
题目
给你一个字符串数组 words,对于范围 [0, words.length - 1] 内的每个下标 i,执行以下步骤:
从 words 数组中移除下标 i 处的元素。
计算修改后的数组中所有 相邻对 之间的 最长公共前缀 的长度。
返回一个数组 answer,其中 answer[i] 是移除下标 i 后,相邻对之间最长公共前缀的长度。如果 不存在 相邻对,或者 不存在 公共前缀,则 answer[i] 应为 0。
字符串的前缀是从字符串的开头开始延伸到任意位置的子字符串。
示例 1:
输入: words = ["jump","run","run","jump","run"]
输出: [3,0,0,3,3]
解释:
移除下标 0:
words 变为 ["run", "run", "jump", "run"]
最长的相邻对是 ["run", "run"],其公共前缀为 "run"(长度为 3)
移除下标 1:
words 变为 ["jump", "run", "jump", "run"]
没有相邻对有公共前缀(长度为 0)
移除下标 2:
words 变为 ["jump", "run", "jump", "run"]
没有相邻对有公共前缀(长度为 0)
移除下标 3:
words 变为 ["jump", "run", "run", "run"]
最长的相邻对是 ["run", "run"],其公共前缀为 "run"(长度为 3)
移除下标 4:
words 变为 ["jump", "run", "run", "jump"]
最长的相邻对是 ["run", "run"],其公共前缀为 "run"(长度为 3)
示例 2:
输入: words = ["dog","racer","car"]
输出: [0,0,0]
解释:
移除任意下标都会导致答案为 0。
提示:
1 <= words.length <= 105
1 <= words[i].length <= 104
words[i] 仅由小写英文字母组成。
words[i] 的长度总和不超过 105。
解答
为了避免重复计算,我们可以先求解每个相邻的公共前缀长度,也就是nextCommon[i]代表i和i+1两个元素的公共前缀长度。顺便,我们可以把i和i+2的公共长度(nnCommon[i])也求了,也就是删除i+1的时候会新增的前缀公共长度。
当移除i时,也就是移除了nextCommon[i]和nextCommon[i-1],新增nnCommon[i-1]。
刚开始想用priorityqueue来处理这种边增变加的情况,后来看了下,priorityqueue不支持对不是队头的元素进行删除。
然后想了下,其实我们只需要知道前几个最大值,然后把“移除”的前缀长和“新增”的前缀长和这几个前几个最大进行比较。如果移除的前缀长是最大值,则answer[i]可能是后面的最大值,或者新增的前缀长。
那我们需要前几个最大值呢?答案是3个,我们移除i时,移除了两个nextCommon,最坏情况时,这两个nextCommon是前两个最大值,那这时候answer[i]可能是这两种中的一个:第三个最大值或者新增的nnCommon[i-1]。
这种解法的时间复杂度是:
O(Len_Sum)+O(N): 先计算nextCommon和nnCommon,这个复杂度是所有words的总长度,然后遍历求ans的复杂度是n数组长度。
import java.util.Arrays;
class Solution {
public int[] longestCommonPrefix(String[] words) {
int n=words.length;
int[] nextCommon=new int[n];
int[] nnCommon=new int[n];
for(int i=0;i<n-1;i++){
nextCommon[i]=calPreLen(words[i],words[i+1]);
if(i<n-2){
nnCommon[i]=calPreLen(words[i],words[i+2]);
}
}
// max 3
int[] max=new int[3];
int[] maxId=new int[3];
calMax(nextCommon,max,maxId);
// System.out.println(Arrays.toString(max));
int[] res=new int[n];
for(int i=0;i<n;i++){
//remove i= remove remove nextCommon[i] & nextCommon[i-1], add nnCommon[i-1]
res[i]=max[0];
if(i==maxId[0]||i-1==maxId[0]){
//delete max0, answer max1 or max2
if(i==maxId[1]||i-1==maxId[1]){
//delete max1, ans=max2
res[i]=max[2];
}else{
//ans=max1
res[i]=max[1];
}
}
//compare res[i] and nnCommon[i-1]
if(i!=0){
if(nnCommon[i-1]>res[i]){
// System.out.println("remove i:"+i+" nnC: "+nnCommon[i-1]);
res[i]=nnCommon[i-1];
}
}
}
return res;
}
//max[0] zuida, max[2] dier da
private void calMax(int[] nCom,int[] max,int[] maxId){
int n=nCom.length;
for(int i=0;i<n;i++){
if(nCom[i]>max[0]){
max[2]=max[1];
maxId[2]=maxId[1];
max[1]=max[0];
maxId[1]=maxId[0];
max[0]=nCom[i];
maxId[0]=i;
}else if(nCom[i]>max[1]){
max[2]=max[1];
maxId[2]=maxId[1];
max[1]=nCom[i];
maxId[1]=i;
}else if(nCom[i]>max[2]){
max[2]=nCom[i];
maxId[2]=i;
}
}
}
private int calPreLen(String a,String b){
char[] aArr=a.toCharArray();
char[] bArr=b.toCharArray();
int n1=aArr.length,n2=bArr.length;
int i=0;
for(;i<n1&&i<n2;i++){
if(aArr[i]!=bArr[i]){
break;
}
}
// System.out.println(a+" len "+b+":"+i);
return i;
}
}
大佬code
这里缓存的不是两个相邻元素之间的公共长度,而是[0,i]或者[i,n-1]的相邻公共长度的最大值pre和suf,当删除元素i的时候,直接可以利用pre[i-1]/suf[i+1]的值作为candidate。另外额外求解i左右两个元素的公共长度,从这三个里面选最大的一个。
class Solution {
public int[] longestCommonPrefix(String[] words) {
int n = words.length;
int[] ans = new int[n];
if (n == 1) {
return ans;
}
int[] pre = new int[n], suf = new int[n];
for (int i = 1; i < n; i++) {
int c = 0;
for (int j = 0; j < Math.min(words[i].length(), words[i - 1].length()); j++) {
if (words[i].charAt(j) != words[i - 1].charAt(j)) {
break;
}
c++;
}
pre[i] = Math.max(pre[i - 1], c);
}
for (int i = n - 2; i >= 0; i--) {
int c = 0;
for (int j = 0; j < Math.min(words[i].length(), words[i + 1].length()); j++) {
if (words[i].charAt(j) != words[i + 1].charAt(j)) {
break;
}
c++;
}
suf[i] = Math.max(suf[i + 1], c);
}
ans[0] = suf[1];
ans[n - 1] = pre[n - 2];
for (int i = 1; i < n - 1; i++) {
ans[i] = Math.max(pre[i - 1], suf[i + 1]);
int c = 0;
for (int j = 0; j < Math.min(words[i + 1].length(), words[i - 1].length()); j++) {
if (words[i + 1].charAt(j) != words[i - 1].charAt(j)) {
break;
}
c++;
}
ans[i] = Math.max(ans[i], c);
}
return ans;
}
}

浙公网安备 33010602011771号