LeetCode刷题-字符串
String数组和List集合之间的转化
数组转化为list
Integer [] arr={1,2,3};
List<Integer> list2 = Arrays.asList(arr2);
List<Integer> list=new ArrayList<>(list2);
list
转化为数组
List<String> list = new ArrayList<>();
list.add("guan");
list.add("bao");
String[] array = list.toArray(new String[0]);
字符
520.检测大写字母
就直接从题目出发
- 要不全小写相等
- 要不全大写相等
- 切割,第一个字母是大写,剩余的字母一定是小写
public boolean detectCapitalUse(String word) {
if (word.length()<=1){
return true;
}else {
if (word.toLowerCase().equals(word)){
return true;
}else if (word.toUpperCase().equals(word)){
return true;
}else {
String substring = word.substring(1, word.length());
char firstChar = word.charAt(0);
if (firstChar<'Z' && substring.toLowerCase().equals(substring)){
return true;
}else {
return false;
}
}
}
}
回文串
125.验证回文串
首先移除非字母和数字的字符,并且全部转化为小写。
然后就修改完的字符串,只需要比较头尾的字符是否相等即可
public boolean isPalindrome(String s) {
String cleanString = cleanString(s);
int start = 0;
int end = cleanString.length()-1;
boolean result = true;
while (start<end){
if (cleanString.charAt(start)!=cleanString.charAt(end)){
result = false;
break;
}
start++;
end--;
}
return result;
}
//用来移除非字母和数字的字符,并且全部转化为小写
public String cleanString(String str){
StringBuffer result = new StringBuffer();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if ((c>='a'&&c<='z') || (c>='A' &&c<='Z') || (c>='0' &&c<='9')){
result.append(c);
}
}
return result.toString().toLowerCase();
}
公共前缀
14.最长公共前缀
纵向遍历,用第一个字符的每个字母和别的字符的每个字母比较
如果都拥有该字母,那么添加进入公共前缀,否则立刻结束
public String longestCommonPrefix(String[] strs) {
String firstStr = strs[0];
if (strs.length==1){
return firstStr;
}else {
for (int i = 0;i<firstStr.length();i++) {
//获得第一个单词的每一个字符
char c = firstStr.charAt(i);
//从第二个字符串开始遍历
for (int j = 1;j<strs.length;j++){
//如果当前字符的长度已经超出了第一个字符的长度,停止
//或者当前字符不匹配,停止
if (i == strs[j].length() || strs[j].charAt(i) != c) {
return strs[0].substring(0, i);
}
}
}
return firstStr;
}
}
单词
434.字符串中的单词数
特别要注意是连续的多个空格,所以正则表达式要求匹配连续的一个或者多个一个以上的空格
public int countSegments(String s) {
int result = 0;
//匹配连续的一个或者多个一个以上的空格
String[] split = s.split("\\ +");
for (String str:split) {
if (str!=null && !"".equals(str)){
result++;
}
}
return result;
}
58.最后一个单词的长度
public int lengthOfLastWord(String s) {
//匹配连续的一个或者多个一个以上的空格
String[] split = s.split("\\ +");
return split[split.length-1].length();
}
字符串的反转
344.反转字符串
经典原地反转,可以利用于所有的数组
public void reverseString(char[] s) {
int start = 0;
int end = s.length-1;
while (start<end){
char temp = s[start];
s[start] = s[end];
s[end] = temp;
start++;
end--;
}
}
541.反转字符串 II
通过字符串的长度/2k
先求出哪些字符串肯定可以反转,通过字符串的长度%2k
求出哪些字符串是可能要反转的。对于前者,我们在交替反转(即0-k
反转,k-2k
不反转,2k-3k
反转……),对于后者,我们判断长度来进行反转
public String reverseStr(String s, int k) {
int length = s.length();
if (k>length){
return turn(s,0,length-1);
}
//查看是否有余数
int remainder = length%(2*k);
//得到商的长度
int quotient = length/(2*k);
//获得肯定可以翻转的字符
String newS = s.substring(0,2*k*quotient);
//得到额外需要判定的翻转字符
String canNotTurnS = s.substring(length-remainder,length);
int lengthTurn = canNotTurnS.length();
//标记反转(1要反转,-1不反转)
int flag = 1;
for (int i = 0; i < newS.length(); i++) {
if ((i+1)%k==0){
if (flag==1){
newS = turn(newS,i+1-k,i);
flag = -1;
}else {
flag = 1;
}
}
}
if (lengthTurn<=0){
return newS;
}else if (lengthTurn>0 && lengthTurn<k){
return newS+turn(canNotTurnS,0,canNotTurnS.length()-1);
}else {
return newS+turn(canNotTurnS,0,k-1);
}
}
//反转字符串的某几个字符
public String turn(String str,int start,int end){
char[] s = str.toCharArray();
while (start<end){
char temp = s[start];
s[start] = s[end];
s[end] = temp;
start++;
end--;
}
return new String(s);
}
字符的统计
387. 字符串中的第一个唯一字符
利用map
先对字符串进行字符数量的统计,然后找出value
第一个出现的为1的key
即可
public int firstUniqChar(String s) {
char[] chars = s.toCharArray();
Map<Character,Integer> map = new HashMap<>();
for (int i = 0; i < chars.length; i++) {
Character c = chars[i];
if (map.containsKey(c)){
map.put(c,map.get(c)+1);
}else {
map.put(c,1);
}
}
int result = -1;
for (int j = 0; j < chars.length; j++) {
if (map.get(chars[j])==1){
result = j;
break;
}
}
return result;
}
389. 找不同
思维爆炸,两个字符串的分别字符ascii码
相加,两者之差就是添加的字符
public char findTheDifference(String s, String t) {
int sAsc = 0,tAsc =0;
for (int i = 0; i < s.length(); i++) {
sAsc = sAsc+s.charAt(i);
}
for (int j = 0; j < t.length(); j++) {
tAsc = tAsc+t.charAt(j);
}
return (char)(tAsc-sAsc);
}
242. 有效的字母异位词
如果是异位词,那么排序之后结果就是一样
public boolean isAnagram(String s, String t) {
char[] sChars = s.toCharArray();
char[] tChars = t.toCharArray();
Arrays.sort(sChars);
Arrays.sort(tChars);
return Arrays.equals(sChars,tChars);
}
49. 字母异位词分组
- 排序,将每个字符串进行排序,那么【字母异位词】排序的结果应该是一样的
- 我们将key设置为排序的结果,value设置集合,其中存放排序结果相同的字符串
map.getOrDefault(key,default)
表示如果集合中有这个键,那么取值,否则直接将值赋值为我们自定义的默认值default
- 最后添加当前字符串更新map集合即可
public List<List<String>> groupAnagrams(String[] strs) {
Map<String,List<String>> map = new HashMap<>();
for (int i = 0; i < strs.length; i++) {
char[] chars = strs[i].toCharArray();
Arrays.sort(chars);
//获得排序好的字符串
String key = new String(chars);
//如果有key,那么直接取出 value = List<String>
//如果没有key,设置默认值为 value = new ArrayList<String>()
//将key为当前字符串排序结果的value取出来
List<String> value = map.getOrDefault(key, new ArrayList<String>());
//添加当前字符串
value.add(strs[i]);
//更新map集合
map.put(key,value);
}
return new ArrayList<List<String>>(map.values());
}
451. 根据字符出现频率排序
难点在于如何重写排序器实现字符出现的 频率 对其进行 降序排序
public String frequencySort(String s) {
Map<Character, Integer> map = calculate(s);
//重写排序器
Comparator com = new Comparator<Character>() {
@Override
public int compare(Character o1, Character o2) {
Integer one = map.get(o1);
Integer two = map.get(o2);
return two-one;
}
};
List<Character> keyList = new ArrayList<Character>(map.keySet());
//降序输出key
Collections.sort(keyList,com);
StringBuilder result = new StringBuilder();
//遍历每个字符
for (int i = 0; i < keyList.size(); i++) {
//遍历每个字符对应的次数
for (int j = 0; j < map.get(keyList.get(i)); j++) {
result.append(keyList.get(i));
}
}
return new String(result);
}
//用于字符串中每个字符的计数
public Map<Character,Integer> calculate(String str){
Map<Character,Integer> map = new TreeMap<>();
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
Character c = chars[i];
//getOrDefault()表示如果对应的key如果没有value,那么设置为0
//如果有value,取改key对应的value
map.put(c,map.getOrDefault(c,0)+1);
}
return map;
}
551. 学生出勤记录 I
public boolean checkRecord(String s) {
int late = 0;
int absent = 0;
char[] chars = s.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (chars[i]=='A'){
absent++;
if (absent>=2){
return false;
}
}
if (chars[i]=='L'){
late++;
if (late>=3){
return false;
}
}else {
//但凡不是L,就置0
late=0;
}
}
return true;
}
696. 计数二进制子串
思路实在重要,本题不需要调用任何算法
- 创建数组用于放置连续的0或者1的数量,假设为[a,b,c,d]
- a和b肯定为连续的0和1的数量,可以构造的连续的子字符数量就是min(a,b)
- 那么我们的答案就是连续两个数字的最小值min(a,b)+min(b,c)+min(c,d)累加之和
public int countBinarySubstrings(String s) {
List<Integer> list = new ArrayList<>();
int oneCount = 0, zeroCount = 0;
int length = s.length();
for (int i = 0; i < length; i++) {
char c = s.charAt(i);
//连续的数字碰到下一个和自己互异的数字就截断
if (c =='0'){
if (oneCount>0){
list.add(oneCount);
oneCount = 0;
}
zeroCount++;
}else {
if (zeroCount > 0) {
list.add(zeroCount);
zeroCount = 0;
}
oneCount++;
}
}
//把最后一段连续的0或者1加入
list.add(oneCount>0?oneCount:zeroCount);
int result = 0;
int size = list.size();
for (int i = 1; i < size; i++) {
result+=Math.min(list.get(i),list.get(i-1));
}
return result;
}
535. TinyURL 的加密与解密
public class Codec {
//利用map集合存储(id,url),每个url添加一个id到longUrl后面
//取的时候根据id将url取出来
Map<Integer,String> map = new TreeMap<>();
int id;
public String encode(String longUrl) {
id++;
map.put(id,longUrl);
return longUrl+"/"+id;
}
public String decode(String shortUrl) {
String[] split = shortUrl.split("/");
Integer id = Integer.parseInt(split[split.length-1]);
return map.get(id);
}
}