【算法面试题汇总】LeetBook列表的算法面试题汇总---字符串题目及答案

2024-03-06 21:40

本文主要是介绍【算法面试题汇总】LeetBook列表的算法面试题汇总---字符串题目及答案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

如果有错的还请各位大佬指出呀
有些是copy的还望不要介意
本人只做学习记录

字符串

      • 验证回文串
      • 分割回文串
      • 单词拆分
      • 单词拆分Ⅱ
      • 实现Trie(前缀树)
      • *单词搜索Ⅱ
      • 有效的字母异位词
      • 字符串中的第一个唯一的字符
      • 反转字符串

验证回文串

题目描述:如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。字母和数字都属于字母数字字符。给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false 。

示例:

输入: s = "A man, a plan, a canal: Panama"
输出:true
解释:"amanaplanacanalpanama" 是回文串。输入:s = " "
输出:true
解释:在移除非字母数字字符之后,s 是一个空字符串 "" 。
由于空字符串正着反着读都一样,所以是回文串。
直接在原字符串中动手
  • 代码实现
class Solution {public boolean isPalindrome(String s) {int n = s.length();int left = 0, right = n - 1;while (left < right) {//isLetterOrDigit判断是否是字母或数字while (left < right && !Character.isLetterOrDigit(s.charAt(left))) {++left;}while (left < right && !Character.isLetterOrDigit(s.charAt(right))) {--right;}if (left < right) {//toLowerCase转换为小写if (Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))) {return false;}++left;--right;}}return true;}
}
  • 不用isLetterOrDigit
class Solution {public boolean isPalindrome(String s) {char[] c = s.toLowerCase().toCharArray();int i=0, j=c.length-1;while(i<j){while(!isValid(c[i]) && i<j){++i;}while(!isValid(c[j]) && i<j){--j;}if(c[i] != c[j]){return false;}++i;--j;}return true;}private boolean isValid(char c){return (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9');}
}

分割回文串

题目描述:给你一个字符串 `s`,请你将 `s` 分割成一些子串,使每个子串都是 **回文串** 。返回 `s` 所有可能的分割方案。**回文串** 是正着读和反着读都一样的字符串。

示例:

输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]
  此处用到回溯回溯需要注意的操作:1.深度遍历时,保存所需变量,往深处走则在path尾部添加,往回走则删除尾部的2.若此时的变量满足条件,则需要添加到结果集,注意添加时要new,在java中参数传递是值传递,对象类型变量在传参的过程中,复制的是变量的地址。所以path所指向的列表只有一份,如果不new回到根节点便会成为空列表

在这里插入图片描述

  • 代码实现
class Solution {List<List<String>> ans = new ArrayList<>();public List<List<String>> partition(String s) {dfs(s.toCharArray(),0,new ArrayList());return ans;}//回溯方法void dfs(char[]s,int startIndex,List<String> path){if(startIndex == s.length){ans.add(new ArrayList(path));return;}for(int i=startIndex;i<s.length;i++){if(check(s,startIndex,i)){//此处一定要new,在java中参数传递是值传递,对象类型变量在传参的过程中,复制的是变量的地址。所以path所指向的列表只有一份,如果不new回到根节点便会成为空列表path.add(new String(s,startIndex,i-startIndex+1));dfs(s,i+1,path);//删除上一步才是回溯操作,往深处走便在尾部添加,返回则删除尾部的path.remove(path.size()-1);}}}boolean check(char[]s ,int start,int end){while(start<=end){if(s[start++] != s[end--]){return false;}}return true;}
}

单词拆分

题目描述:给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

示例:

输入: s = "applepenapple", wordDict = ["apple", "pen"]
输出: true
解释: 返回 true 因为 "applepenapple" 可以由 "apple" "pen" "apple" 拼接成。注意,你可以重复使用字典中的单词。

用到动态规划

  • 代码实现
class Solution {public boolean wordBreak(String s, List<String> wordDict) {//法一int n = s.length();//存储0-i的子串能否匹配,长度包括 0 ,因此状态数组的长度为 n + 1boolean[] dp = new boolean[n+1];//空字符串也能匹配dp[0] = true;for(int i=1;i<=n;i++){for(String word : wordDict){int len = word.length();if(len <= i && word.equals(s.substring(i-len,i))){dp[i] = dp[i] || dp[i-len];}}}return dp[n];//法二Set<String> set = new HashSet<>(wordDict);int n = s.length();//f[i]表示以i结尾的0~i的字符串能否在wordDict匹配boolean f[] = new boolean[n + 1];//空串可以匹配f[0] = true;for (int i = 1; i <= n; i ++ ) {for (int j = 0; j < i; j ++ ) {//如果j可以匹配,并且子串[j, i]存在的话,在字符串下标要减一if (f[j] && set.contains(s.substring(j, i))) {f[i] = true;break;}}}return f[n];}
}

单词拆分Ⅱ

题目描述:给定一个字符串 s 和一个字符串字典 wordDict ,在字符串 s 中增加空格来构建一个句子,使得句子中所有的单词都在词典中。以任意顺序 返回所有这些可能的句子。注意:词典中的同一个单词可能在分段中被重复使用多次。

示例:

输入:s = "pineapplepenapple", wordDict = ["apple","pen","applepen","pine","pineapple"]
输出:["pine apple pen apple","pineapple pen apple","pine applepen apple"]
解释: 注意你可以重复使用字典中的单词。
  • 代码实现
class Solution {//存储结果集List<String> res = new ArrayList<>();//存储路径LinkedList<String> track = new LinkedList<>();public List<String> wordBreak(String s, List<String> wordDict) {backtrack(s,0,wordDict);return res;}/*** 回溯* i:起始位置*/void backtrack(String s,int i,List<String>wordDict){//已经拼出整个sif(i == s.length()){//用指定分隔符分割字符串res.add(String.join(" ",track));return;}if(i>s.length()){return;}for(String word:wordDict){int len = word.length();if(i+len > s.length()) continue;//单词太长跳过String subStr = s.substring(i,i+len);if(!subStr.equals(word)) continue;//无法匹配跳过track.addLast(word);backtrack(s,i+len,wordDict);track.removeLast();//回溯}}
}

实现Trie(前缀树)

题目描述:Trie(发音类似 "try")或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。请你实现 Trie 类:Trie() 初始化前缀树对象。void insert(String word) 向前缀树中插入字符串 word 。boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。

示例:

输入
["Trie", "insert", "search", "search", "startsWith", "insert", "search"]
[[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
输出
[null, null, true, false, true, null, true]解释
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple");   // 返回 True
trie.search("app");     // 返回 False
trie.startsWith("app"); // 返回 True
trie.insert("app");
trie.search("app");     // 返回 True

在这里插入图片描述

  • 代码实现
class Trie {private Trie[] children;private boolean isEnd; //设置该字母的后置位是否为单词的结尾public Trie() {//26个英文字母children = new Trie[26];//区分这个字母是否是单词的结尾isEnd = false;}public void insert(String word) {Trie node = this;for(int i=0;i<word.length();i++){char w = word.charAt(i);int index = w - 'a';//如果还没有以这个字母开头的一个分支则创建if(node.children[index] == null){node.children[index] = new Trie();}node = node.children[index];}//遍历到这个单词的最后一个字母要将后置位设置为true表示是一个完整的单词node.isEnd = true;}public boolean search(String word) {Trie trie = searchPrefix(word);return trie!=null && trie.isEnd;}public boolean startsWith(String prefix) {return searchPrefix(prefix) != null;}private Trie searchPrefix(String word){Trie trie = this;for(int i = 0;i<word.length();i++){char w = word.charAt(i);int index = w - 'a';if(trie.children[index] == null){return null;}trie = trie.children[index];}return trie;}
}/*** Your Trie object will be instantiated and called as such:* Trie obj = new Trie();* obj.insert(word);* boolean param_2 = obj.search(word);* boolean param_3 = obj.startsWith(prefix);*/

*单词搜索Ⅱ

题目描述:给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words, 返回所有二维网格上的单词 。单词必须按照字母顺序,通过 相邻的单元格 内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。

在这里插入图片描述

输入:board = [["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]],words = ["oath","pea","eat","rain"]
输出:["eat","oath"]

前缀树+DFS+回溯+剪枝

  • 代码实现
class Solution {//上下左右移动方向int[][] dirs = new int[][]{{-1,0},{1,0},{0,-1},{0,1}};public List<String> findWords(char[][] board, String[] words) {//结果集List<String> res = new ArrayList<>();//构造前缀树TrieNode trie = buildTrie(words);int m = board.length;int n = board[0].length;//记录沿途遍历到的元素StringBuilder s = new StringBuilder();for(int i = 0;i<board.length;i++){for(int j=0;j<board[i].length;j++){//从每个元素开始遍历dfs(res,s,board,i,j,trie,trie);}}return res;}private void dfs(List<String> res,StringBuilder s,char[][] board,int i,int j,TrieNode root,TrieNode node){//判断越界,或者访问过,或者不在字典树,直接返回if(i<0 || j<0 || i>=board.length || j>=board[0].length|| board[i][j] == '#'|| node == null || node.children[board[i][j] - 'a'] == null){return;}//记录当前字符char curr = board[i][j];s.append(curr);//如果有结束字符则加入结果集if(node.children[board[i][j] - 'a'].isEnd){String word = s.toString();res.add(word);deleteWordFromTrie(root,word);}//记录当前元素被访问过board[i][j] = '#';//按四个方向遍历for(int[] dir:dirs){dfs(res,s,board,i+dir[0],j+dir[1],root,node.children[curr - 'a']);}//还原状态board[i][j] = curr;s.deleteCharAt(s.length()-1);}private void deleteWordFromTrie(TrieNode root,String word){//已经找过的从前缀树中删除,相当于剪枝优化//先找到最后一个字符,从后往前删delete(root,word,0);}//返回true表示可以将沿途节点删除private boolean delete(TrieNode root,String word,int i){if(i == word.length()-1){//如果后面还有单词则不能直接删除,比如dog和dogs在同一个分支上TrieNode curr = root.children[word.charAt(i) - 'a'];if(hasChildren(curr)){curr.isEnd = false;return false;}else{root.children[word.charAt(i) - 'a'] = null;return true;}}else{//有dog和dig两个单词时,删除dog返回到d时d是不能删除的,也就是没有其他子节点//后面没有节点了,也就是不能删除dogs中的dogif(delete(root.children[word.charAt(i) - 'a'],word,i+1)&& !root.children[word.charAt(i) - 'a'].isEnd&& !hasChildren(root.children[word.charAt(i) - 'a'])){root.children[word.charAt(i) - 'a'] = null;return true;}return false;}}private boolean hasChildren(TrieNode curr){for(TrieNode child:curr.children){if(child != null){return true;}}return false;}private TrieNode buildTrie(String[] words){TrieNode root = new TrieNode();for(String word: words){char[] arr = word.toCharArray();TrieNode curr = root;for(char c:arr){if(curr.children[c - 'a'] == null){curr.children[c - 'a'] = new TrieNode();}curr = curr.children[c - 'a'];}curr.isEnd = true;}return root;}class TrieNode{TrieNode[] children = new TrieNode[26];boolean isEnd = false;}
}

有效的字母异位词

题目描述:给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。提示:1 <= s.length, t.length <= 5 * 104s 和 t 仅包含小写字母进阶: 如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?
输入: s = "anagram", t = "nagaram"
输出: true
  • 代码实现
class Solution {public boolean isAnagram(String s, String t) {if(s.length() != t.length()){return false;}//对于进阶问题,Unicode 中可能存在一个字符对应多个字节(字符是离散未知的),//所以用hash表维护对应字符的频次便可Map<Character,Integer> map = new HashMap<>();for(int i=0;i<s.length();i++){char ch = s.charAt(i);//getOrDefault(Object key, V defaultValue),如果有这个key则用对应的值,如果没有则用defaultValuemap.put(ch,map.getOrDefault(ch,0) + 1);}for(int j=0;j<t.length();j++){char ch = t.charAt(j);map.put(ch,map.getOrDefault(ch,0) - 1);if(map.get(ch)<0){return false;}}return true;}
}

字符串中的第一个唯一的字符

题目描述:给定一个字符串 `s` ,找到 *它的第一个不重复的字符,并返回它的索引* 。如果不存在,则返回 `-1` 
输入: s = "leetcode"
输出: 0
  • hashmap代码实现
class Solution {public int firstUniqChar(String s) {Map<Character,Integer> map = new HashMap<>();for(int i=0;i<s.length();i++){char ch = s.charAt(i);map.put(ch,map.getOrDefault(ch,0)+1);}for(int j = 0;j<s.length();j++){if(map.get(s.charAt(j)) == 1){return j;}}return -1;}
}
  • 字符串的api

    当它的某个字符的第一次出现的位置和最后一次出现的位置下标相同则表示该字符只出现了一次

class Solution {public int firstUniqChar(String s) {for(int i=0;i<s.length();i++){if(s.indexOf(s.charAt(i))==s.lastIndexOf(s.charAt(i))){return i;}}return -1;}
}
  • int数组(最优)
class Solution {public int firstUniqChar(String s) {//每个字母出现的次数int[] count = new int[26];//char数组比字符串遍历更快char[] charArr = s.toCharArray();for(char c:charArr){count[c - 'a']++;}for(char c:charArr){if(count[c-'a'] == 1){return s.indexOf(c);}}return -1;}
}

反转字符串

题目描述:编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
输入:s = ["h","e","l","l","o"]
输出:["o","l","l","e","h"]
  • 代码实现
class Solution {public void reverseString(char[] s) {int n = s.length;int left = 0,right = n-1;while(left<right){char temp = s[right];s[right] = s[left];s[left] = temp;left++;right--;}}
}

这篇关于【算法面试题汇总】LeetBook列表的算法面试题汇总---字符串题目及答案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/781448

相关文章

Python实现字典转字符串的五种方法

《Python实现字典转字符串的五种方法》本文介绍了在Python中如何将字典数据结构转换为字符串格式的多种方法,首先可以通过内置的str()函数进行简单转换;其次利用ison.dumps()函数能够... 目录1、使用json模块的dumps方法:2、使用str方法:3、使用循环和字符串拼接:4、使用字符

深入理解Mysql OnlineDDL的算法

《深入理解MysqlOnlineDDL的算法》本文主要介绍了讲解MysqlOnlineDDL的算法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小... 目录一、Online DDL 是什么?二、Online DDL 的三种主要算法2.1COPY(复制法)

Python 常用数据类型详解之字符串、列表、字典操作方法

《Python常用数据类型详解之字符串、列表、字典操作方法》在Python中,字符串、列表和字典是最常用的数据类型,它们在数据处理、程序设计和算法实现中扮演着重要角色,接下来通过本文给大家介绍这三种... 目录一、字符串(String)(一)创建字符串(二)字符串操作1. 字符串连接2. 字符串重复3. 字

Pandas处理缺失数据的方式汇总

《Pandas处理缺失数据的方式汇总》许多教程中的数据与现实世界中的数据有很大不同,现实世界中的数据很少是干净且同质的,本文我们将讨论处理缺失数据的一些常规注意事项,了解Pandas如何表示缺失数据,... 目录缺失数据约定的权衡Pandas 中的缺失数据None 作为哨兵值NaN:缺失的数值数据Panda

Java 字符串操作之contains 和 substring 方法最佳实践与常见问题

《Java字符串操作之contains和substring方法最佳实践与常见问题》本文给大家详细介绍Java字符串操作之contains和substring方法最佳实践与常见问题,本文结合实例... 目录一、contains 方法详解1. 方法定义与语法2. 底层实现原理3. 使用示例4. 注意事项二、su

Java实现将HTML文件与字符串转换为图片

《Java实现将HTML文件与字符串转换为图片》在Java开发中,我们经常会遇到将HTML内容转换为图片的需求,本文小编就来和大家详细讲讲如何使用FreeSpire.DocforJava库来实现这一功... 目录前言核心实现:html 转图片完整代码场景 1:转换本地 HTML 文件为图片场景 2:转换 H

Java使用正则提取字符串中的内容的详细步骤

《Java使用正则提取字符串中的内容的详细步骤》:本文主要介绍Java中使用正则表达式提取字符串内容的方法,通过Pattern和Matcher类实现,涵盖编译正则、查找匹配、分组捕获、数字与邮箱提... 目录1. 基础流程2. 关键方法说明3. 常见场景示例场景1:提取所有数字场景2:提取邮箱地址4. 高级

Python进阶之列表推导式的10个核心技巧

《Python进阶之列表推导式的10个核心技巧》在Python编程中,列表推导式(ListComprehension)是提升代码效率的瑞士军刀,本文将通过真实场景案例,揭示列表推导式的进阶用法,希望对... 目录一、基础语法重构:理解推导式的底层逻辑二、嵌套循环:破解多维数据处理难题三、条件表达式:实现分支

Python 字符串裁切与提取全面且实用的解决方案

《Python字符串裁切与提取全面且实用的解决方案》本文梳理了Python字符串处理方法,涵盖基础切片、split/partition分割、正则匹配及结构化数据解析(如BeautifulSoup、j... 目录python 字符串裁切与提取的完整指南 基础切片方法1. 使用切片操作符[start:end]2

MyBatis的xml中字符串类型判空与非字符串类型判空处理方式(最新整理)

《MyBatis的xml中字符串类型判空与非字符串类型判空处理方式(最新整理)》本文给大家介绍MyBatis的xml中字符串类型判空与非字符串类型判空处理方式,本文给大家介绍的非常详细,对大家的学习或... 目录完整 Hutool 写法版本对比优化为什么status变成Long?为什么 price 没事?怎