优选算法---字符串
1.最长公共前缀
题目链接:14. 最长公共前缀 - 力扣(LeetCode)
题目解析:返回最长公共前缀
算法讲解:
解法一:两两比较
先将第一个字符串和第二个字符串的最长公共前缀获取到,假设这个最长前缀为str,然后再拿这个str和第三个字符串比较,知道将所有字符串都两两比较一遍
此时代码的核心就变成了提取两个字符串的最长公共前缀
提取两个字符串的最长公共前缀的思路:当两个字符串对应的字符相同且i在两个字符串之间不越界的情况下,让i++即可
时间复杂度分析:
假设字符串的平均长度为m,假设有n个字符串,此时最坏的情况下字符串中的每个字符都要比较,则此时时间复杂度为O(N)
代码实现:
class Solution {public String longestCommonPrefix(String[] strs) {String ret=strs[0];for(int i=1;i<strs.length;i++){ret=findCommon(ret,strs[i]);}return ret;}public String findCommon(String ret,String str){int i=0;while(i<Math.min(ret.length(),str.length()) && ret.charAt(i)==str.charAt(i)){i++;}return ret.substring(0,i);}
}
解法二:统一比较
统一比较就是一个字符一个字符一次比较,假设先去判断第一个字符时,就去所有的字符串里面比较,看所有的字符串是否有这个第一个字符,r如果有就去判断第二个字符,第二字符的比较也是以此类推,如果让i一直顺利的走到最后,说明所有的字符串都是相同的字符串,此时直接返回任意一个字符串即可
代码实现:
class Solution {public String longestCommonPrefix(String[] strs) {String str=strs[0];for(int i=0;i<str.length();i++){char tmp=str.charAt(i);for(int j=1;j<strs.length;j++){String s=strs[j];if(i==s.length() || s.charAt(i) != tmp){return str.substring(0,i);}}}return str;}
}
2.最长回文子串
题目链接:5. 最长回文子串 - 力扣(LeetCode)
题目解析:返回字符串s中的最长回文子串
算法讲解:中心扩展算法
遍历字符串s,每次都已遍历到的字符串为中心,定义两个指针left和right,一开始都让他们指向中心,如果s[left]==s[right]且left和right都没越界,此时就让left和right越界或者s[left]!=s[right]
但是以上面的那种方案,只考虑了回文子串的长度为奇数的情况,没有考虑到回文子串长度为偶数的情况,如果考虑偶数的情况下,一开始只要让right在中心的下一个位置或者让left处于中心位置的前一个位置
因为题目要求的是回文子串,无论回文子串长度是偶数还是奇数,最终left指向的位置就是恰好不为回文子串的位置,所以left-1就是为最长回文子串的开始位置
代码实现:
class Solution {public String longestPalindrome(String _s) {char[] s = _s.toCharArray();int start=0;int n=s.length;int maxLength=1;for(int i=0;i<n;i++){int left=i;int right=i;//奇数while(left>=0&&right<n&&s[left]==s[right]){left--;right++;}if(maxLength<right-left-1){maxLength=right-left-1;start=left+1;}//偶数left=i;right=i+1;while(left>=0&&right<n&&s[left]==s[right]){left--;right++;}if(maxLength<right-left-1){maxLength=right-left-1;start=left+1;}}return _s.substring(start,start+maxLength);}
}
3.二进制求和
题目链接:67. 二进制求和 - 力扣(LeetCode)
算法讲解:模拟列竖式运算
由于列竖式运算是从后往前计算,所以我们从后往前遍历字符串a和字符串b,将每次遍历到的数字提取出来,创建一个变量t来记录进位情况,此时还要创建一个字符串ret来记录每一位相加的结果,每次让ret.appned(t%2),t%2是因为只需要相加结果的个为即可
一个小细节:遍历字符串a和字符串b时,有可能会出现越界的情况,此时只要将越界的字符串对应的数字弄为0即可
有ret.append一直是尾插,所以最终返回时要先对ret逆序一下再返回
代码实现:
class Solution {public String addBinary(String a, String b) {int lenA=a.length();int lenB=b.length();int aa=0;int bb=0;int t=0;StringBuffer ret = new StringBuffer();while(lenA-1>=0 || lenB-1>=0 || t!=0){if(lenA-1<0){aa=0;}else{aa=a.charAt(lenA-1)-'0';}if(lenB-1<0){bb=0;}else{bb=b.charAt(lenB-1)-'0';}t+=aa;t+=bb;ret.append(t%2);t/=2;lenA--;lenB--;}return ret.reverse().toString();}
}
4.字符串相乘
题目链接:43. 字符串相乘 - 力扣(LeetCode)
算法讲解:先无进位相乘,最后再处理进位
首先对两个字符串进行逆序处理,然后进行相乘。
相乘的时候,假设m为num1的长度,n为num2的长度,创建一个空间大小为[m+n-1]的数组tmp,tmp用来存储每一位相乘的结果,此时tmp中记录的结果恰好可以对应到逆序后的num1和逆序后的num2每一位相乘的结果
什么意思呢?
tmp[0]中记录就是逆序后num1和num2中第0个数字字符相乘的结果,tmp[1]就是num1[1]*num2[0]+num1[0]*num2[1]的结果,然后以此类推下去
处理完无进位相乘后,此时再按照两数相加的做法去处理tmp
最后再处理一下前导0的情况即可
class Solution {public String multiply(String num1, String num2) {int len1=num1.length();int len2=num2.length();int[] tmp = new int[len1+len2-1];StringBuffer ret = new StringBuffer();//逆序String s1=new StringBuffer(num1).reverse().toString();String s2=new StringBuffer(num2).reverse().toString();//无进位相乘for(int i=0;i<s1.length();i++){int first = s1.charAt(i)-'0';for(int j=0;j<s2.length();j++){int second = s2.charAt(j)-'0';int sum=first*second;tmp[i+j]+=sum;}}//处理进位int t=0;for(int i=0;i<tmp.length;i++){t+=tmp[i];ret.append(t%10);t/=10;}if(t!=0) ret.append(t);//处理前导0while(ret.length()>1&&ret.charAt(ret.length()-1)=='0'){ret.deleteCharAt(ret.length()-1);}return ret.reverse().toString();}
}