回文对
时间:2022-07-22
本文章向大家介绍回文对,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
问题描述
给定一组唯一的单词, 找出所有不同 的索引对(i, j)
,使得列表中的两个单词, words[i] + words[j]
,可拼接成回文串。
示例 1:
输入: ["abcd","dcba","lls","s","sssll"]
输出: [[0,1],[1,0],[3,2],[2,4]]
解释: 可拼接成的回文串为 ["dcbaabcd","abcddcba","slls","llssssll"]
示例 2:
输入: ["bat","tab","cat"]
输出: [[0,1],[1,0]]
解释: 可拼接成的回文串为 ["battab","tabbat"]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/palindrome-pairs
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解决方案
一种直观的方案为对于word1从前往后遍历,对于word2从后往前遍历进行匹配,若中间出现一个位置匹配不上,则说明word1+word2无法构成回文串。匹配过程中两者中如果有某个单词用光了,则判断还有剩余部分的那个单词其后的字符串能否构成回文串,例如:
word1 = “accbc” word2 = "ca"
上述为word2用完了,word1剩余的情况,之后判断word1中的“cbc”能否构成回文;
word1 = “ad” word2 = "bbada"
上述为word1用完了,word2剩余的情况,之后判断word2中的“bba”能否构成回文。
匹配过程中若两个单词都用光了,则word1+word2一定能构成回文串,不过需要注意的是word1不能等于word2(题目提到时唯一的一组单词,即不会出现重复单词)。
该问题很容易想到用前缀树来求解,首先将反转后的单词统统插入到前缀树中,然后遍历这组单词,以当前单词(记做word1)为前缀进行查找能够匹配的那些单词,如上述分析,查找中若出现word1没用完,当前缀树中某个单词用完,此时需要判断word1其后面的部分能否构成回文串,查找中若word1用完了,则以当前的结点开始做dfs,找到所有前缀为word1的单词,再判断其前面的部分能够构成回文。
最后还需要注意的是对于空字符串,其可以和任意一个回文串构成回文串。
class Solution {
public static class Node{
// 中间结点值均为-1,结尾结点值为该字符串的下标索引
int index;
Node[] next;
public Node(){
this.index = -1;
this.next = new Node[26];
}
}
// 插入逆置后的单词
public void insertWord(String str, int index){
Node node = root;
for(int i = str.length() - 1; i >= 0; i--){
char cur = str.charAt(i);
if(node.next[cur - 'a'] == null){
node.next[cur - 'a'] = new Node();
}
node = node.next[cur - 'a'];
if(i == 0){
node.index = index;
}
}
}
// 将回文对存入result中
public void find(String perfix,int index, List<List<Integer>> result){
List<Integer> list = new ArrayList<>();
Node node = root;
for(int i = 0; i < perfix.length(); i++){
char cur = perfix.charAt(i);
if(node.next[cur - 'a'] == null){
return;
}
node = node.next[cur - 'a'];
// word1比word2长的情况
if(i != perfix.length() - 1 && node.index != -1){
if(isPalin(perfix, i + 1, perfix.length() - 1)){
List<Integer> temp = new ArrayList<>(2);
temp.add(index);
temp.add(node.index);
result.add(temp);
}
}
}
// word1比word2短或等于的情况
dfs(node, result, index);
}
public void dfs(Node node, List<List<Integer>> result, int index){
if(node.index != -1 && node.index != index){
if(isPalin(words[node.index], 0, words[node.index].length() - words[index].length() - 1)){
List<Integer> temp = new ArrayList<>(2);
temp.add(index);
temp.add(node.index);
result.add(temp);
}
}
for(Node temp : node.next){
if(temp == null){
continue;
}
dfs(temp, result, index);
}
}
public boolean isPalin(String str, int left, int right){
while(left < right){
if(str.charAt(left++) != str.charAt(right--)){
return false;
}
}
return true;
}
Node root = new Node();
String[] words = null;
public List<List<Integer>> palindromePairs(String[] words) {
List<List<Integer>> result = new ArrayList<>();
this.words = words;
for(int i = 0; i < words.length; i++){
insertWord(words[i], i);
}
int nullIndex = -1;
for(int i = 0; i < words.length; i++){
if(words[i].length() == 0){
nullIndex = i;
continue;
}
find(words[i], i, result);
}
if(nullIndex != -1){
for(int j = 0; j < words.length; j++){
if(j == nullIndex){
continue;
}
if(isPalin(words[j], 0, words[j].length() - 1)){
List<Integer> temp1 = new ArrayList<>(2);
List<Integer> temp2 = new ArrayList<>(2);
temp1.add(nullIndex);
temp1.add(j);
temp2.add(j);
temp2.add(nullIndex);
result.add(temp1);
result.add(temp2);
}
}
}
return result;
}
}
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 一道有意思的腾讯算法面试题
- 关于 JavaScript 错误处理的最完整指南(上半部)
- 排障集锦:九九八十一难之第十六难!-------------enoent ENOENT: no such file or directory, open ‘/root/package.json‘
- 大点干!早点散----------深入剖析GFS分布式文件系统
- 大点干!早点散----------ELK企业日志分析系统理论+实战!
- 面试题系列第8篇:谈谈String、StringBuffer、StringBuilder的区别?
- HTTP协议的请求与数据抓包
- Ubuntu 18.04 LTS 通过 Netplan 配置网络教程
- 【kafka源码】kafka内部的一些术语
- TKE使用自建NFS持久化存储
- 网站 SSL 检测 PCI DSS 不合规解决办法
- leetcode链表之分割链表
- 五分钟带你读懂 TCP全连接队列(图文并茂)
- Python基础
- JDK15正式发布,新增功能预览!