字符串简介
-
字符串的基本操作对象通常是字符串整体或者其子串 I LIKE LEETCODE 反向输出后,更希望是LEETCODE LIKE I 这时候操作对象就是这些子串
-
字符串操作比其他数据类型更复杂
-
比较函数
Java的字符串比较有三者方法 compareTo:比较的是数据的大小;equals:比较的是内容是否相等;==:比较的是是否来自统一引用
package 数组和字符串; /** * @author sandu * @create 2020-08-11 14:14 */ public class 字符串简介 { // "static void main" must be defined in a public class. public static void main(String[] args) { // initialize String s1 = "Hello World"; System.out.println("s1 is \"" + s1 + "\""); String s2 = s1; System.out.println("s2 is another reference to s1."); String s3 = new String(s1); System.out.println("s3 is a copy of s1."); // compare using '==' System.out.println("Compared by '==':"); // true since string is immutable and s1 is binded to "Hello World" System.out.println("s1 and \"Hello World\": " + (s1 == "Hello World")); // true since s1 and s2 is the reference of the same object System.out.println("s1 and s2: " + (s1 == s2)); // false since s3 is refered to another new object System.out.println("s1 and s3: " + (s1 == s3)); // compare using 'equals' System.out.println("Compared by 'equals':"); System.out.println("s1 and \"Hello World\": " + s1.equals("Hello World")); System.out.println("s1 and s2: " + s1.equals(s2)); System.out.println("s1 and s3: " + s1.equals(s3)); // compare using 'compareTo' System.out.println("Compared by 'compareTo':"); System.out.println("s1 and \"Hello World\": " + (s1.compareTo("Hello World") == 0)); System.out.println("s1 and s2: " + (s1.compareTo(s2) == 0)); System.out.println("s1 and s3: " + (s1.compareTo(s3) == 0)); System.out.println(s1.hashCode()); System.out.println(s2.hashCode()); System.out.println(s3.hashCode()); } }
-
连接操作。在Java中,字符串是不可变的,如果想修改其中的字符,需要创建一个新的字符串。在连接时首先为新字符串分配足够的空间,复制就字符串中的内容并附加到新字符串。因此,总时间复杂度为O(N²)。
-
如果你确实希望你的字符串是可变的,则可以使用
toCharArray
将其转换为字符数组。 -
如果你经常必须连接字符串,最好使用一些其他的数据结构,如
StringBuilder
-
最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""
。
输入: ["flower","flow","flight"]
输出: "fl"
输入: ["dog","racecar","car"]
输出: ""
解释: 输入不存在公共前缀。
所有输入只包含小写字母 a-z 。
方法
横向扫描
横向扫描所有的字符串,以第一个为公共前缀,层层对比并且递减,遇到空则直接退出。
递归真香,真好用
class Solution14{
public String longestCommonPrefix(String[] strs){
if (strs.length == 0 || strs == null){
return "";
}
int strsLength = strs.length;
String firstStr = strs[0];
for (int i = 1; i < strsLength; i++) {
firstStr = longestCommonPrefix(firstStr,strs[i]);
if (firstStr.equals("")){
break;
}
}
return firstStr;
}
public String longestCommonPrefix(String str1,String str2){
int minLength = Math.min(str1.length(),str2.length());
int numberCount = 0;
while (numberCount < minLength && str1.charAt(numberCount) == str2.charAt(numberCount)){
numberCount++;
}
return str1.substring(0,numberCount);
}
}
时间复杂度:O(mn)O(mn),其中 mm 是字符串数组中的字符串的平均长度,nn 是字符串的数量。最坏情况下,字符串数组中的每个字符串的每个字符都会被比较一次。
空间复杂度:O(1)O(1)。使用的额外空间复杂度为常数。
纵向扫描
横向扫描是以整个字符串作比较。纵向是将几个字符串纵向排列,从第一列开始比较,如果相同则进行第二列比较,有不同,就取当前位置为最大公共前缀的索引。
class Solution140001{
public String longestCommonPrefix(String[] strs){
if (strs.length == 0 || strs == null){
return "";
}
int strsLength = strs.length;
int firstLength = strs[0].length();
for (int i = 0; i < firstLength; i++) {
char firstChar = strs[0].charAt(i);
for (int j = 1; j < strsLength; j++) {
if (i == strs[j].length() || firstChar != strs[j].charAt(i)){// 或 前面的判断是当前串比后串数量大的时候,做比较
return strs[0].substring(0,i);
}
}
}
return strs[0];
}
}
时间复杂度:O(mn)O(mn),其中 mm 是字符串数组中的字符串的平均长度,nn 是字符串的数量。最坏情况下,字符串数组中的每个字符串的每个字符都会被比较一次。
空间复杂度:O(1)O(1)。使用的额外空间复杂度为常数。
二分法
首先选择数组里最小的一个,他可能是公共前缀的最大长度。然后以这个数来进行二分法,当公共值等于mid的时候,有可能相等或者大于;当小于的时候,就mid-1继续判断
class Solution140002{
public String longestCommonPrefix(String[] strs){
if (strs.length == 0 || strs == null){
return "";
}
int minLength = Integer.MAX_VALUE;
for (String str : strs) {
minLength = Math.min(minLength , str.length());
}
int low = 0,high = minLength;
while (low < high){
int mid = low + (high - low + 1) / 2;// 防溢出
if (isCommonPrefix(strs,mid)){
low = mid;//注意是while循环 如果公共值大于mid 则一直判断
}else {
low = mid - 1;
}
}
return strs[0].substring(0,low);
}
private boolean isCommonPrefix(String[] strs, int length) {
String str0 = strs[0].substring(0, length);
int count = strs.length;
for (int i = 1; i < count; i++) {
String str = strs[i];
for (int j = 0; j < length; j++) {
if (str0.charAt(j) != str.charAt(j)){
return false;
}
}
}
return true;
}
}
时间复杂度:O(mn log m) 其中m是字符串的最小长度,n是字符串的数量。二分查找的迭代次数是O(log m) 每次迭代最多需要比较mn个字符。
空间复杂度: O(1) 使用的额外空间复杂度为常数