当前位置: 首页 > 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可用率并不是唯一的评判标准 其实更应该关注的…...

LVGL图片资源全解析:从C数组到图标字体的高效集成方案

1. LVGL图片资源方案概述 在嵌入式GUI开发中&#xff0c;图片资源的管理直接影响产品性能和开发效率。LVGL作为轻量级图形库&#xff0c;提供了三种主流的图片集成方案&#xff1a;内部C数组、外部文件系统图片和图标字体。每种方案都有其独特的适用场景和实现方式&#xff0c;…...

如何在5分钟内免费掌握Windows风扇控制终极技巧

如何在5分钟内免费掌握Windows风扇控制终极技巧 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trending/fa/FanControl.Relea…...

基于LLM与RAG的法律AI工具:从架构解析到工程实践

1. 项目概述&#xff1a;一个法律文本智能生成与分析的AI工具最近在和一些做法律科技的朋友聊天时&#xff0c;他们反复提到一个痛点&#xff1a;处理海量的、格式固定的法律文书&#xff0c;比如起诉状、合同、律师函&#xff0c;既耗时又容易在细节上出错。人工起草一份严谨的…...

收藏!小白程序员必看:AI大模型入门指南,抓住下一个风口!

文章通过房价下跌和土木工程专业遇冷的例子&#xff0c;警示读者行业选择的重要性。随后&#xff0c;文章重点介绍了AI大模型相关岗位&#xff0c;如AI大模型训练师和AI大模型应用开发工程师&#xff0c;指出这些岗位门槛相对较低&#xff0c;适合普通人入门&#xff0c;并提供…...

【C++ 多态】虚函数 · 虚表 · 重写,一篇彻底弄明白!

C 多态详解 C多态是面向对象的核心灵魂&#xff0c;本文将由浅入深&#xff0c;带你循序渐进地掌握多态的方方面面&#xff0c;全程干货&#xff0c;坐稳发车~ ദ്ദി˶&#xff70;̀֊&#xff70;́ )✧ 文章目录C 多态详解1. 什么是多态&#xff1f;2. 运行时多态的实现前…...

BetterGI:解放双手的终极原神自动化助手,每天节省2小时游戏时间

BetterGI&#xff1a;解放双手的终极原神自动化助手&#xff0c;每天节省2小时游戏时间 【免费下载链接】better-genshin-impact &#x1f4e6;BetterGI 更好的原神 - 自动拾取 | 自动剧情 | 全自动钓鱼(AI) | 全自动七圣召唤 | 自动伐木 | 自动刷本 | 自动采集/挖矿/锄地 | 一…...

构建个人技能知识库:从Markdown管理到自动化实践

1. 项目概述&#xff1a;一个技能库的诞生与价值最近在整理个人知识体系时&#xff0c;我一直在思考一个问题&#xff1a;如何将那些零散的、跨领域的“技能点”系统化地管理起来&#xff0c;形成一个可以持续迭代、随时取用的个人工具箱&#xff1f;这不仅仅是写一份简历上的技…...

Ask your GIT:AI驱动的代码仓库智能助手,一键解析与安装

1. 项目概述&#xff1a;一个为开发者“减负”的智能代码助手在GitHub、GitLab或者Bitbucket上发现一个看起来很有潜力的开源项目&#xff0c;是每个开发者的日常。但随之而来的&#xff0c;往往是长达十几甚至几十分钟的“阅读理解”时间&#xff1a;你得先通读冗长的README&a…...

AI编程规划工具vibe-driven-dev:从模糊想法到清晰开发蓝图

1. 项目概述&#xff1a;从“感觉”到“计划”的桥梁在AI编程助手&#xff08;或者说“编码智能体”&#xff09;越来越普及的今天&#xff0c;一个常见的困境是&#xff1a;我们脑子里有一个很棒的产品想法&#xff0c;但当你试图把它交给Claude Code、Cursor或者Windsurf这类…...

动态架构跳跃:让视觉语言大模型高效适配垂直领域任务

1. 项目概述&#xff1a;从“大而全”到“快而准”的模型进化之路 在视觉语言预训练模型&#xff08;Vision-Language Pre-trained Models, VLPMs&#xff09;如CLIP、ALIGN等席卷多模态领域的今天&#xff0c;一个核心的工程与学术困境日益凸显&#xff1a;这些动辄数十亿参数…...