当前位置: 首页 > news >正文

Leetcode 336 回文对

示例 1:

输入:words = ["abcd","dcba","lls","s","sssll"]
输出:[[0,1],[1,0],[3,2],[2,4]] 
解释:可拼接成的回文串为 ["dcbaabcd","abcddcba","slls","llssssll"]

示例 2:

输入:words = ["bat","tab","cat"]
输出:[[0,1],[1,0]] 
解释:可拼接成的回文串为 ["battab","tabbat"]

示例 3:

输入:words = ["a",""]
输出:[[0,1],[1,0]]

提示:

  • 1 <= words.length <= 5000
  • 0 <= words[i].length <= 300
  • words[i] 由小写英文字母组成

解法1:暴力数组法

我们知道要单词i和单词j能组成回文,那么单词i的第一个字符肯定和单词j的最后一个字符相等。

char(0) of word[i] == char(length-1) of word(j)

那么,我们可以把最后一个字符相同的单词放到同一个字符为下标的数组里。在遍历比较的时候,通过单词i取它的首字母为下标的列表里的值list(word[j])进行逐个比较,判断若是回文则直接输出。

代码如下:

class Solution {public List<List<Integer>> palindromePairs(String[] words) {int len = words.length;Map<String, Integer> indexMap = new HashMap<>(len * 4/3);// char list, contains ends with the characterList[] postfixList = new List[128];for (int i=0; i<len; i++) {// save word indexindexMap.put(words[i], i);int wordLen = words[i].length();// skip empty "" if (wordLen > 0) {char lastChar = words[i].charAt(wordLen-1);if (postfixList[lastChar] == null) {postfixList[lastChar] = new ArrayList<>();}postfixList[lastChar].add(words[i]);}}List<List<Integer>> result = new ArrayList<>();boolean containsEmpty = indexMap.containsKey("");for (int i=0; i<len; i++) {String word = words[i];int wordLen = word.length();// skip empty stringif (wordLen == 0) {continue;}// process postfix listchar firstChar = word.charAt(0);List<String> posts = postfixList[firstChar];if (posts != null) {for(int j=0; j<posts.size(); j++) {String candidate = posts.get(j);if(!word.equals(candidate) && isPalindrome(word + candidate)) {System.out.println("postfix word: "+ words[i]+", candidate:"+candidate);result.add(Arrays.asList(i, indexMap.get(candidate)));}}}// process empty string if existedif (containsEmpty && isPalindrome(word)) {int emptyIndex = indexMap.get("");result.add(Arrays.asList(i, emptyIndex));result.add(Arrays.asList(emptyIndex, i));}}return result;}public boolean isPalindrome(String str) {char[] chars = str.toCharArray();for (int i=0, j=chars.length-1; i<j; i++,j--) {if (chars[i] != chars[j]){return false;}}return true;}
}

运行结果:跑到第134个测试用例超时。

分析原因发现:测试用例134大部分是以相同字母结尾的,那么就退变成每个单词都要比较所有单词,所以效率低。

解法2:前缀树(字典树)

1)使用前缀树来存储逆序后的单词。

2)把单词word[i]按字母拆分 prefix:string[0,i], postfix [i+1,len-1],有下面两种情况:

i)  假如后半部分为回文,则用前半分去查询前缀树得到对于的翻转串 s' (对应的单词j)。 prefix + palindrome(postfix) + s' 那么组成的新词一定为回文,得到的结果为(i,j);

ii) 假如前半部分为回文,在用后半部分去查询前缀树得到的翻转串s' (对应的单词j)。s'+palindrome(prefix)+postifix, 得到的结果为(j, i) 

字典树的参考实现:

java - 一文搞懂字典树 - bigsai - SegmentFault 思否

Java数据结构---Trie(字典树/前缀树)_java 数据结构 trible-CSDN博客

代码如下:

class Solution {public List<List<Integer>> palindromePairs(String[] words) {// build trie tree with reversed wordint len = words.length;TrieTree tree = new TrieTree();for(int i=0; i<len; i++) {StringBuffer reversed = new StringBuffer(words[i]).reverse();// full reversetree.insert(reversed, i);}List<List<Integer>> result = new ArrayList<>();for (int i = 0; i < len; i++) {String word = words[i];for (int j=1; j<=word.length(); j++) {String prefix = word.substring(0, j);String postfix = word.substring(j);if (isPalindrome(prefix)) {// search word in the reversed trie treeint wordIndex = tree.search(postfix);if (wordIndex >= 0 && wordIndex != i) {result.add(List.of(wordIndex, i));}}if (isPalindrome(postfix)) {// search word in the reversed trie treeint wordIndex = tree.search(prefix);if (wordIndex >= 0 && wordIndex != i) {result.add(List.of(i, wordIndex));}}}// process empty stringif (word.length() == 0) {for (int j=0; j<len; j++) {if (i != j && isPalindrome(words[j])) {result.add(List.of(j, i));}}}}return result;}/*** double pointer checking palindrome.* * @param wordChars* @param candidate* @return*/public boolean isPalindrome(String str) {char[] chars = str.toCharArray();for (int i=0, j=chars.length-1; i<j; i++,j--) {if (chars[i] != chars[j]){return false;}}return true;}}class TrieTree {private TrieNode root;public TrieTree() {root = new TrieNode();}/*** build trie tree and save index into end node.* @param word* @param index*/public void insert(StringBuffer word, int index) {TrieNode current = root;int len = word.length();for (int i=0; i<len; i++) {char ch = word.charAt(i);current.children.putIfAbsent(ch, new TrieNode());current = current.children.get(ch);}current.wordIndex = index;}/*** search the word in trie tree.* @param word* @return*/public int search(String word) {TrieNode current = root;for (char ch: word.toCharArray()) {TrieNode node = current.children.get(ch);if (node == null) {return -2;}current = node;}return current.wordIndex;}public boolean isPalindrome(StringBuilder str) {int len = str.length();for (int i=0, j=len-1; i<j; i++,j--) {if (str.charAt(i) != str.charAt(j)){return false;}}return true;}public class TrieNode {// if this is a word, wordIndex >= 0, or else = -1int wordIndex = -1;Map<Character, TrieNode> children = new HashMap<>();}
}

运行结果如下:

前进了一小步,测试用例从134进步到了135,还是未通过。

分析原因:发现这里给的词都是对称的长度300,在150,151开始变化,前缀树深度很深在150~151才开始分化。

优化:既然前缀树退化成了链表,需要全部遍历才能获取结果。那么使用HashMap是不是应该很快呢?

解法3:HashMap存储逆序字符串

算法还是算法2的步骤,只不过把存储逆序的结构换成了HashMap,这个才更好理解和快速嘛。

代码如下:
 

class Solution {public List<List<Integer>> palindromePairs(String[] words) {// build trie tree with reversed wordint len = words.length;Map<String,Integer> reversedMap = new HashMap<>(len*4/3);for(int i=0; i<len; i++) {StringBuffer reversed = new StringBuffer(words[i]).reverse();reversedMap.put(reversed.toString(), i);}List<List<Integer>> result = new ArrayList<>();for (int i = 0; i < len; i++) {String word = words[i];char[] wordChars = word.toCharArray();for (int j=1; j<=wordChars.length; j++) {// prefix is palindrome, search postfixif (isPalindrome(wordChars, 0, j)) {// search word in the reversed mapInteger wordIndex = reversedMap.get(word.substring(j));if (wordIndex != null && wordIndex >= 0 && wordIndex != i) {result.add(List.of(wordIndex, i));}}// postfix is palindrome, search prefixif (isPalindrome(wordChars, j, wordChars.length)) {// search word in the reversed mapInteger wordIndex = reversedMap.get(word.substring(0, j));if (wordIndex != null && wordIndex >= 0 && wordIndex != i) {result.add(List.of(i, wordIndex));}}}// process empty stringif (word.length() == 0) {for (int j=0; j<len; j++) {char[] chars = words[j].toCharArray();if (i != j && isPalindrome(chars, 0, chars.length)) {result.add(List.of(j, i));}}}}return result;}/*** double pointer checking palindrome, not included end; [start, end)* * @param wordChars* @param candidate* @return*/public boolean isPalindrome(char[] wordChars, int start, int end) {for (int i=start, j=end-1; i<j; i++,j--) {if (wordChars[i] != wordChars[j]){return false;}}return true;}}

执行结果:

相关文章:

Leetcode 336 回文对

示例 1&#xff1a; 输入&#xff1a;words ["abcd","dcba","lls","s","sssll"] 输出&#xff1a;[[0,1],[1,0],[3,2],[2,4]] 解释&#xff1a;可拼接成的回文串为 ["dcbaabcd","abcddcba","sl…...

实现一个可配置的TCP设备模拟器,支持交互和解析配置

前言 诸位在做IOT开发的时候是否有遇到一个问题&#xff0c;那就是模拟一个设备来联调测试&#xff0c;虽然说现在的物联网通信主要是用mqtt通信&#xff0c;但还是有很多设备使用TCP这种协议交互&#xff0c;例如充电桩&#xff0c;还有一些工业设备&#xff0c;TCP这类报文交…...

算法的空间复杂度

空间复杂度 空间复杂度主要是衡量一个算法运行所需要的额外空间&#xff0c;在计算机发展早期&#xff0c;计算机的储存容量很小&#xff0c;所以空间复杂度是很重要的。但是经过计算机行业的迅速发展&#xff0c;计算机的容量已经不再是问题了&#xff0c;所以如今已经不再需…...

自定义协议

1. 问题引入 问题&#xff1a;TCP是面向字节流的&#xff08;TCP不关心发送的数据是消息、文件还是其他任何类型的数据。它简单地将所有数据视为一个字节序列&#xff0c;即字节流。这意味着TCP不会对发送的数据进行任何特定的边界划分&#xff0c;它只是确保数据的顺序和完整…...

在 Taro 中实现系统主题适配:亮/暗模式

目录 背景实现方案方案一&#xff1a;CSS 变量 prefers-color-scheme 媒体查询什么是 prefers-color-scheme&#xff1f;代码示例 方案二&#xff1a;通过 JavaScript 监听系统主题切换 背景 用Taro开发的微信小程序&#xff0c;需求是页面的UI主题想要跟随手机系统的主题适配…...

autogen框架中使用chatglm4模型实现react

本文将介绍如何使用使用chatglm4实现react&#xff0c;利用环境变量、Tavily API和ReAct代理模式来回答用户提出的问题。 环境变量 首先&#xff0c;我们需要加载环境变量。这可以通过使用dotenv库来实现。 from dotenv import load_dotenv_ load_dotenv()注意.env文件处于…...

读《Effective Java》笔记 - 条目9

条目9&#xff1a;与try-finally 相比&#xff0c;首选 try -with -resource 什么是 try-finally&#xff1f; try-finally 是 Java 中传统的资源管理方式&#xff0c;通常用于确保资源&#xff08;如文件流、数据库连接等&#xff09;被正确关闭。 BufferedReader reader n…...

【软件入门】Git快速入门

Git快速入门 文章目录 Git快速入门0.前言1.安装和配置2.新建版本库2.1.本地创建2.2.云端下载 3.版本管理3.1.添加和提交文件3.2.回退版本3.2.1.soft模式3.2.2.mixed模式3.2.3.hard模式3.2.4.使用场景 3.3.查看版本差异3.4.忽略文件 4.云端配置4.1.Github4.1.1.SSH配置4.1.2.关联…...

nextjs window is not defined

问题产生的原因 在 Next.js 中&#xff0c;“window is not defined” 错误通常出现在服务器端渲染&#xff08;Server - Side Rendering&#xff0c;SSR&#xff09;的代码中。这是因为window对象是浏览器环境中的全局对象&#xff0c;在服务器端没有window这个概念。例如&am…...

C语言实现冒泡排序:从基础到优化全解析

一、什么是冒泡排序&#xff1f; 冒泡排序&#xff08;Bubble Sort&#xff09;是一种经典的排序算法&#xff0c;其工作原理非常直观&#xff1a;通过多次比较和交换相邻元素&#xff0c;将较大的元素“冒泡”到数组的末尾。经过多轮迭代&#xff0c;整个数组会变得有序。 二…...

windows11下git与 openssl要注意的问题

看了一下自己贴文的历史&#xff0c;有一条重要的忘了写了。 当时帮有位同事配置gitlab&#xff0c;众说周知gitlab是不太好操作。 但我还是自认自己git还是相当熟的。 解决了一系列问题&#xff0c;如配置代理&#xff0c;sshkey&#xff0c;私有库&#xff0c;等等&#xff0…...

lua除法bug

故事背景&#xff0c;新来了一个数值&#xff0c;要改公式。神奇的一幕出现了&#xff0c;公式算出一个非常大的数。排查是lua有一个除法bug,1除以大数得到一个非常大的数。 function div(a, b)return tonumber(string.format("%.2f", a/b)) end print(1/73003) pri…...

Ubuntu下Docker容器java服务往mysql插入中文数据乱码

一、问题描述 1、java服务部署在ubuntu下的docker容器内&#xff0c;但是会出现部分插入中文数据显示乱码&#xff0c;如图所示&#xff1a; 二、解决方案 1、查看mysql是否支持utf8&#xff0c;登录进入Mysql 输入命令&#xff1a; mysql -u root -pshow variables like c…...

C语言根据字符串变量获取/设置结构体成员值

一、背景 在项目中需要根据从数据库中获取的字段与对应的键值付给对应结构体成员上&#xff0c;而c语言中没有类似的反射机制&#xff0c;所以需要实现类似功能。例&#xff0c;从表中查到a 10&#xff0c;在结构体t中&#xff0c;需要将 t.a 10。 二、实现 感谢ChatGPT&…...

Selenium 自动化测试demo

场景描述&#xff1a; 模拟用户登录页面操作&#xff0c;包括输入用户名、密码、验证码。验证码为算数运算&#xff0c;如下&#xff1a; 使用到的工具和依赖&#xff1a; 1. Selenium&#xff1a;pip install selenium 2. 需要安装浏览器驱动&#xff1a;这里使用的是Edge 3…...

LeetCode 111.二叉树的最小深度

题目&#xff1a; 给定一个二叉树&#xff0c;找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明&#xff1a;叶子节点是指没有子节点的节点。 思路&#xff1a;自底向上&#xff08;归&#xff09;/自顶向下&#xff08;递&#xff09; DF…...

大工C语言作业答案

前言 这里是大连理工大学新版C语言课程MOOC作业的答案。 后期我会把全部的作业答案开源出来&#xff0c;希望对大家有帮助。 第九周第一题 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int B(int i) {int sum 1;while (i > 0){sum i * sum;i--;}return su…...

【Unity踩坑】Unity中父对象是非均匀缩放时出现倾斜或剪切现象

The game object is deformed when the parent object is in non-uniform scaling. 先来看一下现象 有两个Cube, Cube1&#xff08;Scale2,1,1)&#xff0c;Cube2&#xff08;Scale1,1,1&#xff09; 将Cube2拖拽为Cube2的子对象。并且将position设置为&#xff08;-0.6,1,0&a…...

QT 跨平台实现 SSDP通信 支持多网卡

一.多网卡场景 在做SSDP通信的时候,客户端发出M-search命令后, 主机没有捕捉到SSDP的消息,你可以查看下,是不是局域网下,既打开了wifi,又连接了本地网络,mac os下很容易出现这种场景。此时,我们发送消息时,需要遍历所有网卡并发送M-search命令。 二.QT相关接口介绍 1…...

如何寻找适合的HTTP代理IP资源?

一、怎么找代理IP资源&#xff1f; 在选择代理IP资源的时候&#xff0c;很多小伙伴往往将可用率作为首要的参考指标。事实上&#xff0c;市面上的住宅IP或拨号VPS代理IP资源&#xff0c;其可用率普遍在95%以上&#xff0c;因此IP可用率并不是唯一的评判标准 其实更应该关注的…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

LabVIEW双光子成像系统技术

双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制&#xff0c;展现出显著的技术优势&#xff1a; 深层组织穿透能力&#xff1a;适用于活体组织深度成像 高分辨率观测性能&#xff1a;满足微观结构的精细研究需求 低光毒性特点&#xff1a;减少对样本的损伤…...

软件工程 期末复习

瀑布模型&#xff1a;计划 螺旋模型&#xff1a;风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合&#xff1a;模块内部功能紧密 模块之间依赖程度小 高内聚&#xff1a;指的是一个模块内部的功能应该紧密相关。换句话说&#xff0c;一个模块应当只实现单一的功能…...

解析两阶段提交与三阶段提交的核心差异及MySQL实现方案

引言 在分布式系统的事务处理中&#xff0c;如何保障跨节点数据操作的一致性始终是核心挑战。经典的两阶段提交协议&#xff08;2PC&#xff09;通过准备阶段与提交阶段的协调机制&#xff0c;以同步决策模式确保事务原子性。其改进版本三阶段提交协议&#xff08;3PC&#xf…...

游戏开发中常见的战斗数值英文缩写对照表

游戏开发中常见的战斗数值英文缩写对照表 基础属性&#xff08;Basic Attributes&#xff09; 缩写英文全称中文释义常见使用场景HPHit Points / Health Points生命值角色生存状态MPMana Points / Magic Points魔法值技能释放资源SPStamina Points体力值动作消耗资源APAction…...