LeetCode字符串专题
------------恢复内容开始------------
String 方法
下面是 String 类支持的方法,更多详细,参看 Java String API 文档:
------------恢复内容结束------------
1.编程之美 3.1
没有书。。。
4. 两个字符串包含的字符是否完全相同
242. Valid Anagram (Easy)
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
示例 1:
输入: s = "anagram", t = "nagaram"
输出: true
答案:
可以用 HashMap 来映射字符与出现次数,然后比较两个字符串出现的字符数量是否相同。
由于本题的字符串只包含 26 个小写字符,因此可以使用长度为 26 的整型数组对字符串出现的字符进行统计,不再使用 HashMap。
用到了上面的39号方法
public boolean isAnagram(String s, String t) { int[] cnts = new int[26];//26个0 for (char c : s.toCharArray()) { cnts[c - 'a']++;//比如a-a=0,c-a=2这是对应索引...所以cnts里面是int数组 其实是字母们的索引对应的26个0
这一步意思是对应26个索引值对应的0++中。。。就是出现1次就是,出现2次就是2.没出现就还是0 } for (char c : t.toCharArray()) { cnts[c - 'a']--;//同上,统计字母的出现次数 但是这个是把前面++过的次数降下来 若t和s相等 则还是26个0 } for (int cnt : cnts) { if (cnt != 0) { return false; } } return true; }
5. 计算一组字符集合可以组成的回文字符串的最大长度
409. Longest Palindrome (Easy)
给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。
在构造过程中,请注意区分大小写。比如 "Aa"
不能当做一个回文字符串。
答案:
使用长度为 256 的整型数组来统计每个字符出现的个数,每个字符有偶数个可以用来构成回文字符串。
因为回文字符串最中间的那个字符可以单独出现,所以如果有单独的字符就把它放到最中间。
public int longestPalindrome(String s) { int[] cnts = new int[256];//这次直接把ascii码的256个char的索引搬过来 for (char c : s.toCharArray()) { cnts[c]++;//这里放的也是对应索引的次数,只是这个索引不像上面考虑从0开始了,在ascii码中索引是几这里就是几,然后还是存的该索引对应的字符出现次数 } int palindrome = 0; for (int cnt : cnts) { palindrome += (cnt / 2) * 2;//这个得出的是可以组成的最大长度。如果该字符有偶数个,则正好可以构成,若有奇数个,则需要减去1个多余的 } if (palindrome < s.length()) {//发生了减去了多余的话,允许加上1个放中间 palindrome++; // 这个条件下 s 中一定有单个未使用的字符存在,可以把这个字符放到回文的最中间 } return palindrome; }
完全没想到的妙啊。。。看题目完全不会做觉得怎么会是简单题。。。原来只要是次数为偶数就可以,如果有奇数则/2*2就去掉多余的那个了。若发生了去掉,不管发生几次,加1放中间就行。
6. 字符串同构
205. Isomorphic Strings (Easy)
给定两个字符串 s 和 t,判断它们是否是同构的。
如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。
所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。
我的想法是两个计次数的256长度的数组排序以后看是否相等。。感觉会超时。。而且该方法次数顺序好像保证不了。。。不排序,剔除=0的即拿出不为0的,这样呢?
答案是在两个分别计数的同时就可以判断!!因为对应于字符串的索引i在0到lengrh内,s的i索引对应元素出现次数要等于t的i索引对应元素的出现次数。
public boolean isIsomorphic(String s, String t) { int[] preIndexOfS = new int[256]; int[] preIndexOfT = new int[256]; for (int i = 0; i < s.length(); i++) { char sc = s.charAt(i), tc = t.charAt(i);//从字符串们中对应位置取的char,可以分别做各自次数数组中的索引!!!!!!! if (preIndexOfS[sc] != preIndexOfT[tc]) { return false; } preIndexOfS[sc] = i + 1;//这是换了一种遍历字符串的方法,前面是变成数组遍历,这里使用charAt(index)方法取char遍历。
因为我们要用到i索引保证sc和tc是字符串同一索引处取出的字符! preIndexOfT[tc] = i + 1;//也不是从0开始计次数了,而是s的索引值加1,
有重复的char自动替换最新的,重点是对比sc和tc两个索引对应的元素即次数是否相等。 } return true; }
震惊1!数组中还可以用char类型做索引!因为与int一一对应吧可能,比如a就是97
7. 回文子字符串个数
647. Palindromic Substrings (Medium)
给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。
emmm我真的是不会做字符串的题。。感觉要用128题hashset那个跳来做。。
答案都好难理解。。。
class Solution { int counts = 0; public int countSubstrings(String s) { for(int i=0;i<s.length();i++){ //奇数个数的回文子串,以自身为两边扩展子串保证还是奇数 extendSubstrings(s,i,i); //偶数个数的回文子串,以两个相邻的索引向两边扩展保证子串还是偶数 extendSubstrings(s,i,i+1); } return counts; } private void extendSubstrings(String s,int start,int end){//对于一个字符串s,指定两个初始位置,判断两个位置的字母是否相同,
//然后逐渐向两边扩展,每次扩展都记录counts数,直到不满足要求为止(有一边到头了或者两边字母不一样了) while(start>=0 && end<s.length() && s.charAt(start)==s.charAt(end)){ //往两边扩展字符串 start--; end++; //回文子串计数加一 counts++; } } }
评论区都在cue第5题
5. 最长回文子串
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
class Solution { public String longestPalindrome(String s) { int len = s.length(); if (len < 2) { return s; } int maxLen = 1; String res = s.substring(0, 1); for (int i = 0; i < s.length(); i++) { 以s的索引遍历 String oddStr=extendSubstrings(s, i, i); // 奇数长度 String evenStr=extendSubstrings(s, i, i + 1); // 偶数长度 String maxLenStr = oddStr.length() > evenStr.length() ? oddStr : evenStr;//选长的 if (maxLenStr.length() > maxLen) { maxLen = maxLenStr.length(); res = maxLenStr;//存住每次最长的那个 } } return res; } private String extendSubstrings(String s, int start, int end) { while (start >= 0 && end < s.length() && s.charAt(start) == s.charAt(end)) { start--; end++; } // 这里要小心,跳出 while 循环时,恰好满足 s.charAt(i) != s.charAt(j),因此不能取 i,不能取 j return s.substring(start + 1, end);//返回一个该start和end下往两边扩展的最长的子序列!! } }
评论区这两题还用动态规划做。。。不会。。。看不懂。。。
8. 判断一个整数是否是回文数
9. Palindrome Number (Easy)
我的想法上一题加equals方法,但是这里输入的是个int,需要int转String.
int类型转String类型的三种方法:
1.String str = Integer.toString(num); (最快)
2.String str = String.valueOf(num); (一般)
3.String str = num + ""; (最慢)
class Solution { public boolean isPalindrome(int x) { String s = Integer.toString(x); if(s.length()==1){ return true; } int len = s.length(); if(len%2==0){ return extendSubstrings(s,len/2-1,len/2); }else{ return extendSubstrings(s,len/2,len/2); } } private boolean extendSubstrings(String s,int start,int end){ while(start>=0 && end<s.length() && s.charAt(start)==s.charAt(end)){ //往两边扩展字符串 start--; end++; } if(s.equals(s.substring(start+1, end))){ return true; } return false; } }
9. 统计二进制字符串中连续 1 和连续 0 数量相同的子字符串个数
696. Count Binary Substrings (Easy)
给定一个字符串 s,计算具有相同数量0和1的非空(连续)子字符串的数量,并且这些子字符串中的所有0和所有1都是组合在一起的。
重复出现的子串要计算它们出现的次数。
示例 1 :
输入: "00110011"
输出: 6
解释: 有6个子串具有相同数量的连续1和0:“0011”,“01”,“1100”,“10”,“0011” 和 “01”。
请注意,一些重复出现的子串要计算它们出现的次数。
另外,“00110011”不是有效的子串,因为所有的0(和1)没有组合在一起。
emmmm???不会。。。
两种解法
1.中心扩展(类似回文子串的判断)
看完题目给的示例,如果将0与1看成对应,那么符合题目要求的子串就关于其中心(中间两个元素的中间)成轴对称。就如同回文字符串关于中心轴对称。不过有一点不同,就是在本问题中对称中心只能是两个字符的中间,而回文字符串的中心可以是某一个字母
所以这个题也可以类似于统计回文字符串的数目那样,用中心扩展的方法。本问题中对称中心只能是两个字符的中间,可以用整形序列[1, s.length() - 1]来表示回文中心的位置,那么left = i - 1, right = i 就是最中心的两个字符。
比如i = 1时left = 0, right = 1 ,就是第一个可能的满足题目要求的子串。由原字符串中第一,第二个字符构成。
所以遍历每一个回文中心的循环为for(int i = 1; i < s.length(); i++)
在循环中首先要保证,回文中心左右的两个字符char leftChar = chars[left], rightChar = chars[right];一个是0,另外一个是1。
如果都是1或者都是0,那么没有以这个为中心的符合要求的字串,后续就不用从中心向外扩展了if(leftChar == rightChar) continue;。
如果leftChar != rightChar,就以此为中心,使用一个while循环来计数这个中心有多少个符合题意的子串。循环条件首先保证索引不越界,其次leftChar左边的字符都要和它相等,rightChar右边的字符都要和它相等。不断向外扩展就是left--; right++
时间复杂度为O(n+k),其中k为符合条件的子串的数目。空间复杂度为O(1)。
public int countBinarySubstrings(String s) { int result = 0; char[] chars = s.toCharArray(); for(int i = 1; i < s.length(); i++){ int left = i - 1, right = i;//直接在遍历里面写之前放到另一个方法里的取子序列操作,因为这里不分奇偶,一定是偶 char leftChar = chars[left], rightChar = chars[right];//之前直接是s.charAt(left)。啊啊啊这里只能是这样!!原因见下面!! if(leftChar == rightChar) continue; while(left >= 0 && right < s.length() && chars[left] == leftChar && chars[right] == rightChar){
//因为这里他需要这样判断,左边的都一样,右边的也得都一样。而不是之前的相等或者不相等 left--; right++; result++; } } return result; } 作者:ustcyyw 链接:https://leetcode-cn.com/problems/count-binary-substrings/solution/696java-zhong-xin-kuo-zhan-yu-hui-wen-chuan-xiang-/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
就得这样写,不能和之前那个start,end那样判断扩展相等。
我怕明天就会忘了。。。。