有关字符串类型的题目都会总结记录在此,方便自己日后查看。
文章目录
1002.查找常用字符
给定仅有小写字母组成的字符串数组A,返回列表中的每个字符串中都显示的全部字符(包括重复字符)组成的列表。例如,如果一个字符在每个字符串中出现 3 次,但不是 4次,则需要在最终答案中包含该字符 3 次。你可以按任意顺序返回答案。
- 个人解题思路:
个人的一般思路(不得不说官方还是巧妙的很),用一个二维数组map[words][26](输入有多少个单词,就有多少行,每列对应a-z)存储每个单词各个字母的出现次数。之后遍历map,判断每列是否都不为0(有出现0说明此列对应的字母并非所有单词都包含,应当舍弃),是的话就取每列最小值,即重复次数,并保存对应字母到列表里。如下图所示:
- JAVA代码
import java.util.LinkedList;
import java.util.List;
public class 查找常用字符1002 {
static class Solution {
public List<String> commonChars(String[] words) {
List<String> list=new LinkedList<String>();
int map[][]=new int[words.length][26];
for (int i = 0; i < words.length; i++) {
char c[]=words[i].toCharArray();
for (int j = 0; j < c.length; j++) {
map[i][c[j]-'a']+=1;
}
}
//打印看看map保存的对不对
// for (int i = 0; i < map[0].length; i++) {
// System.out.print(""+(char)('a'+i)+" ");
// }
// System.out.println("");
// for (int i = 0; i < map.length; i++) {
// for (int j = 0; j < map[0].length; j++) {
// System.out.print(map[i][j]+" ");
// }
// System.out.println(":"+words[i]);
// }
for (int i = 0; i < map[0].length; i++) {
int min=Integer.MAX_VALUE;
int j=0;
for (j = 0; j < map.length; j++) {
if (map[j][i]<min) {
min=map[j][i];
if (min==0) {
break;
}
}
}
for (int k = 0; k < min; k++) {
list.add(""+(char)('a'+i));
}
}
return list;
}
}
public static void main(String[] args) {
String string[]= {"bella","label","roller"};
Solution solution=new Solution();
List<String> list=solution.commonChars(string);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
- C++
不得不说,C++数组是真的麻烦
#include<iostream>
#include<vector>
#include<string>
using namespace std;
class Solution {
public:
vector<string> commonChars(vector<string>& words) {
vector<string> list;
vector<vector<int>> map(words.size());
for (int i = 0; i < map.size(); i++) {
map[i].resize(26);
}
for (int i = 0; i < words.size(); i++) {
for (int j = 0; j < words[i].length(); j++) {
map[i][words[i][j] - 'a'] += 1;
}
}
for (int i = 0; i < map[0].size(); i++) {
int min = INT_MAX;
int j = 0;
for (j = 0; j < map.size(); j++) {
if (map[j][i] < min) {
min = map[j][i];
if (min == 0) {
break;
}
}
}
for (int k = 0; k < min; k++) {
//用emplace_back效率高,且参数不必是对象
list.emplace_back(1, i+'a');
}
}
return list;
}
};
- C++代码(官方)
class Solution {
public:
vector<string> commonChars(vector<string>& words) {
vector<int> minfreq(26, INT_MAX);
vector<int> freq(26);
for (const string& word : words) {
fill(freq.begin(), freq.end(), 0);
for (char ch : word) {
++freq[ch - 'a'];
}
for (int i = 0; i < 26; ++i) {
minfreq[i] = min(minfreq[i], freq[i]);
}
}
vector<string> ans;
for (int i = 0; i < 26; ++i) {
for (int j = 0; j < minfreq[i]; ++j) {
//用emplace_back效率高,且参数不必是对象
ans.emplace_back(1, i + 'a');
}
}
return ans;
}
};
5.最长回文子串
给你一个字符串 s,找到 s 中最长的回文子串
-
个人解题思路
第一时间还是想到暴力,采用双指针,从字符串第一个字母开始,以其为中心向两边扫,一旦发现不是回文串,则退出,然后以字符串第二个字母为中心,以此类推,直至扫完整个串,中途不断保存最长的串就可以了。主要需要注意的是回文串有两种类型,aba和baab,加个flag分情况就行了。
发现这个暴力法也是可以AC的嘿嘿,虽然击败的人比较少。
-
JAVA代码
public class 最长回文子串5 {
static class Solution {
static String getlongest(String s,int flag) {
String string="";
char c[]=s.toCharArray();
for (int pos = 0; pos < c.length; pos++) {
//用flag标志是aba型还是baab型。
int left=pos,right=pos+flag;
String roll="";
while (true) {
if(left<0||right>=c.length)break;
if (c[left]==c[right]) {
left-=1;
right+=1;
}
else break;
}
int begin=left+1;
int end=right-1;
for (int j = begin; j <= end; j++) {
roll+=c[j];
}
if(roll.length()>string.length()) {
string=roll;
}
}
return string;
}
public String longestPalindrome(String s) {
String s1=getlongest(s, 0);
String s2=getlongest(s, 1);
return s1.length()>s2.length()?s1:s2;
}
}
public static void main(String[] args) {
Solution s=new Solution();
System.out.println(s.longestPalindrome("abbacd"));
}
}
记录一下正解吧,动态规划方法。
- 用 P(i,j)表示字符串 s 的第i到j个字母组成的串(即 S[i:j])是否为回文串。
- 可以发现,若s[i:j]为回文串,则S[i+1:j-1]一定也为回文串,可以写出动态规划的状态转移方程:
P(i,j)=P(i+1,j−1)∧(Si==Sj)- 边界条件:对于长度为 1 的子串,它显然是个回文串;对于长度为 2 的子串,只要它的两个字母相同,它就是一个回文串。
P(i,i)=true,P(i,i+1)=(Si==Si+1)
JAVA和C++代码如下:
public class Solution {
public String longestPalindrome(String s) {
int len = s.length();
if (len < 2) {
return s;
}
int maxLen = 1;
int begin = 0;
// dp[i][j] 表示 s[i..j] 是否是回文串
boolean[][] dp = new boolean[len][len];
// 初始化:所有长度为 1 的子串都是回文串
for (int i = 0; i < len; i++) {
dp[i][i] = true;
}
char[] charArray = s.toCharArray();
// 递推开始
// 先枚举子串长度
for (int L = 2; L <= len; L++) {
// 枚举左边界,左边界的上限设置可以宽松一些
for (int i = 0; i < len; i++) {
// 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
int j = L + i - 1;
// 如果右边界越界,就可以退出当前循环
if (j >= len) {
break;
}
if (charArray[i] != charArray[j]) {
dp[i][j] = false;
} else {
if (j - i < 3) {
dp[i][j] = true;
} else {
dp[i][j] = dp[i + 1][j - 1];
}
}
// 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
if (dp[i][j] && j - i + 1 > maxLen) {
maxLen = j - i + 1;
begin = i;
}
}
}
return s.substring(begin, begin + maxLen);
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zui-chang-hui-wen-zi-chuan-by-leetcode-solution/
来源:力扣(LeetCode)
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Solution {
public:
string longestPalindrome(string s) {
int n = s.size();
if (n < 2) {
return s;
}
int maxLen = 1;
int begin = 0;
// dp[i][j] 表示 s[i..j] 是否是回文串
vector<vector<int>> dp(n, vector<int>(n));
// 初始化:所有长度为 1 的子串都是回文串
for (int i = 0; i < n; i++) {
dp[i][i] = true;
}
// 递推开始
// 先枚举子串长度
for (int L = 2; L <= n; L++) {
// 枚举左边界,左边界的上限设置可以宽松一些
for (int i = 0; i < n; i++) {
// 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
int j = L + i - 1;
// 如果右边界越界,就可以退出当前循环
if (j >= n) {
break;
}
if (s[i] != s[j]) {
dp[i][j] = false;
} else {
if (j - i < 3) {
dp[i][j] = true;
} else {
dp[i][j] = dp[i + 1][j - 1];
}
}
// 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
if (dp[i][j] && j - i + 1 > maxLen) {
maxLen = j - i + 1;
begin = i;
}
}
}
return s.substr(begin, maxLen);
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zui-chang-hui-wen-zi-chuan-by-leetcode-solution/
来源:力扣(LeetCode)