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

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...