将一个字符串逆序,若逆序后的字符串与原字符串完全一样,则两个字符串互为回文字符串。
【算法题】
给定一个字符串,验证它是否是回文字符串。 说明:只考虑字母和数字字符,可以忽略字母的大小写。 例如,"A man, a plan, a canal: Panama"是一个回文字符串。 例如,"Hello World"不是一个回文字符串。
通过前后两个指针分别从字符串首尾比较字符是否相等,若遇到首尾不等的字符,则证明不是回文字符串,否则同时移动前后两个指针,直至前后两个指针相遇。上述算法题的解法如下:
创建测试类用于验证回文算法的功能,测试类如下:
执行测试代码,执行结果如下:
A man, a plan, a canal: Panama是不是回文字符串?true Hello World是不是回文字符串?false
【算法题】
对于给定的一个字符串,将其分割成一些子串,使每个子串都是回文串,返回所有可能的分割方案。 例如,给定一个字符串"aab",其可能的分割方案如下: [ ["aa","b"], ["a","a","b"] ]
此题可以使用回溯算法进行求解。回溯算法是一种系统地搜索问题解的方法。回溯算法是在搜索尝试的过程中寻找问题的解。当发现某一条路径出现不满足的条件而造成无法得到最优解时,就返回这条路径的起点,尝试其他的路径。这种走不通就退回起点再选择走别的路径的技术为回溯法,而满足回溯条件的某个状态的点称为回溯点。许多复杂的,规模较大的问题都可以使用回溯法。
上述算法题的解法如下:
创建测试类用于验证分割回文字符串的功能,测试类如下:
执行测试代码,执行结果如下:
aab分割回文字符串结果: [a, a, b] [aa, b]
【算法题】
给定一个非空字符串和一个包含非空单词列表的字典,判定非空字符串是否可以被空格拆分为一个或多 个在字典中出现的单词。 例如,给定字符串"HelloWorld"和字典["Hello", "World"],返回true,因为"HelloWorld" 可以被分为"Hello World"。 例如,给定字符串"JavaInterviewJava"和字典["Java", "Interview"],返回true,因为字 符串"JavaInterviewJava"可以被分为"Java Interview Java",其中每个单词都出现在字典中。 例如,给定字符串"catsandog"和字典["cats", "dog", "sand", "and", "cat"],返回false, 因为字符串"catsandog"无论如何拆分都不能保证每个单词都出现在字典中。
此题可以使用动态规划算法求解。动态规划是运筹学的一个分支,动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应一个值。动态规划算法的基本思想是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。可以用一个表来记录所有已解的子问题的答案。无论这个子问题以后是否被用到,只要这个子问题被计算过,就将其结果填入表中。这就是动态规划法的基本思路。
上述算法题的解法如下:
创建测试类用于验证单词拆分的功能,测试类如下:
执行测试代码,执行结果如下:
测试HelloWorld,字典=[Hello, World],结果=true 测试JavaInterviewJava,字典=[Java, Interview],结果=true 测试catsandog,字典=[sand, cats, and, cat, dog],结果=false
前缀树即字典树,又称单词查找树或键树,是一种树形结构。前缀树典型的应用场景是用于统计和排序大量的字符串(但不仅限于字符串)。前缀树经常被搜索引擎系统用于文本词频统计。前缀树的优点是最大限度地减少无谓的字符串比较。
前缀树的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高查询效率的目的。
给出一组单词:inn、int、ate、age、adv、ant,可以得到如图3-1所示的前缀树。
图3-1 前缀树示意图
【算法题】
实现一棵前缀树
前缀树的实现如下:
创建测试类用于验证前缀树的功能,测试类如下:
执行测试代码,执行结果如下:
abc是否存在于前缀树中:true abdc是否存在于前缀树中:true acdb是否存在于前缀树中:false
【算法题】
给定两个字符串string1和string2,编写一个函数来判断string1和string2是否互为字母异 位词。假设只考虑小写字母。 例如,string1="animal",string2="naimal",返回true。 例如,string1="cat",string2="car",返回false。
此题只要统计每个字符串的每个字符出现的频率即可。统计完成后,比较两个字符串每个字符出现的频率,如果完全相同,就证明两者是有效的字母异位词,否则就不是有效的字母异位词。上述算法题的解法如下:
创建测试类用于验证字母异位词的功能,测试类如下:
执行测试代码,执行结果如下:
animal和naimal是否是异位词:true cat和car是否是异位词:false
【算法题】
给定一个字符串,找出其中不含有重复字符的最长子串的长度。 例如,字符串"abcabcbb",输出3,因为无重复字符的最长子串是 "abc"。 例如,字符串"bbbbb",输出1,因为无重复字符的最长子串是 "b"。
本题可以使用一个Map结构存储第一个不重复的字符的位置,并用一个变量记录最长子串的长度。上述算法题的解法如下:
创建测试类用于验证无重复字符的最长子串的功能,测试类如下:
执行测试代码,执行结果如下:
abcabcbb无重复字符的最长子串=3 bbbbb无重复字符的最长子串=1 pwwkew无重复字符的最长子串=3
【算法题】
从电话拨号的键盘上选取任意数字组成一个字符串,返回所有它能表示的字母组合。电话拨号键盘如图 3-2所示。
图3-2 电话拨号键盘示意图
本题可以使用递归算法,此题的解法如下:
创建测试类用于验证电话号码的字母组合的功能,测试类如下:
执行测试代码,执行结果如下:
电话号码23的字母组合是: [ad, ae, af, bd, be, bf, cd, ce, cf]
【算法题】
给定一个字符串和一些长度相同的单词组成的字典,找出字符串中恰好可以由单词中所有单词串联形成 的子串的起始位置。 例如,字符串"barfoothefoobarman"和单词字典["foo","bar"],返回0和9,因为字符串 "barfoothefoobarman"从索引0和9开始的子串分别是"barfoor"和"foobar",这两个子串都可以使 用单词字典中的所有单词串联形成。
本题可以使用一个滑窗来求解。扫描原字符串,如果新增单词是单词集words中的单词,那么滑窗增长(滑窗right指针增加),否则滑窗缩小(滑窗left指针增加)。当滑窗满足需求时,记录滑窗左侧(left)的位置,继续扫描,直至无法再生成满足需求的滑窗为止。
上述算法题的解法如下:
创建测试类用于验证串联所有单词的子串的功能,测试类如下:
执行测试代码,执行结果如下:
字符串barfoothefoobarman串联所有单词的子串为:[0, 9] 字符串wordgoodstudentgoodword串联所有单词的子串为:[]
除了本节介绍的相关字符串算法外,常见的字符串算法还有很多,如将语句翻转、重构字符串、压缩字符串、打乱字符串和删除字符串中的元音字母等。感兴趣的读者可以到互联网上搜索更多有关字符串的算法。