努力努力再努力
常见算法题目
- 模拟一个trim方法,去除字符串两段的空格:
public class Test01 {
public static void main(String[] args) {
String s1=" hell o wo rl d ";
Test01 t1 = new Test01();
String s = t1.myTrim(s1);
System.out.println("---"+s+"---");
}
public String myTrim(String str){
int start =0;
int end=str.length()-1;
while(start<=end && str.charAt(start)==' '){//从左边开始寻找第一个不是空格的字符位置
start++;
}
while(start<=end && str.charAt(end)==' ' ){//从右边开始寻找第一个不是空格的字符位置
end--;
}
String s1=str.substring(start,end+1);//提取相应位置的子字符串
return s1;
}
}
- 将字符串中指定部分进行反转:
public class Test02 {
public static void main(String[] args) {
Test02 test02 = new Test02();
String reverse = test02.reverse("123456789", 2, 6);
String reverse1 = test02.reverse1("123456789", 2, 6);
String reverse2 = test02.reverse2("123456789", 3, 5);
System.out.println(reverse);//127654389
System.out.println(reverse1);//127654389
System.out.println(reverse2);//123654789
}
//方式一:转换为char[]
public String reverse(String str, int startIndex, int endIndex) {
if (str!=null) {
char[] chars = str.toCharArray();
for (int x = startIndex, y = endIndex; x < y; x++, y--) {
char temp = chars[x];
chars[x] = chars[y];
chars[y] = temp;
}
String s2 = new String(chars);
return s2;
}
return null;
}
/* 优化的部分
for (int i = startIndex; i < endIndex; i++) {
for (int j = endIndex; j > i ; j--) {
char temp=chars[j];
chars[j]=chars[j-1];
chars[j-1]=temp;
}
}
*/
//方式二:使用String的拼接
public String reverse1(String str, int startIndex, int endIndex) {
if (str!=null) {
//第一部分
String reverseStr = str.substring(0, startIndex);
//第二部分
for (int i = endIndex; i >= startIndex; i--) {
reverseStr += str.charAt(i);
}
//第三部分
reverseStr += str.substring(endIndex + 1);
return reverseStr;
}
return null;
}
//方式三:使用StringBuffer/StringBuilder 替换String
public String reverse2(String str, int startIndex, int endIndex) {
if (str!=null){
StringBuilder builder = new StringBuilder(str.length());
//第一部分
builder.append(str.substring(0,startIndex));
//第二部分
for (int i = endIndex; i >=startIndex ; i--) {
builder.append(str.charAt(i));
}
//第三部分
builder.append(str.substring(endIndex + 1));
return builder.toString();
}
return null;
}
}
- 获取一个字符串在另一个字符串中出现的次数
public class Test03 {
public static void main(String[] args) {
Test03 test03 = new Test03();
int i = test03.occurTimes("abafsbaaklnvabdjabfabvabvavbavbaab", "ab");
System.out.println(i);
}
public int occurTimes(String str,String targetStr){
int times=0;
int index=0;
if (str.contains(targetStr)) {
/* 方式一
while(str.substring(index).contains(targetStr)){
times++;
index= index+str.substring(index).indexOf(targetStr)+targetStr.length();
}
return times;
*/
//方式二
while ((index=str.indexOf(targetStr,index))!=-1){
times++;
index+=targetStr.length();
}
return times;
}
return 0;
}
}
- 获取两个字符串中最大相同的子串。
(提示:将短的那个串进行长度依次递减的子串与较长的串比较)
public class Test04 {
public static void main(String[] args) {
Test04 test04 = new Test04();
String s = test04.sameString("fqbeqqhelhloaqqf", "aqqeaehelhelheqlloqqfsfvs");
System.out.println(s);
}
public String sameString(String str1,String str2){
String longStr = str1.length()>=str2.length() ? str1 : str2;
String shortStr = str1.length()<str2.length() ? str1 : str2;
/*
if (str1.length()>=str2.length()){
longStr=str1;
shortStr=str2;
}else {
longStr=str2;
shortStr=str1;
}
*/
boolean flag=false;
if(!longStr.contains(shortStr) ){
for (int i = shortStr.length()-1; i >0 ; i--) {//子字符串长度递减
for (int j = 0; j <= shortStr.length()-i; j++) {//每一个子字符串与长字符串比较
String substr=shortStr.substring(j,j+i);
if (longStr.contains(substr)){
System.out.println(substr);//改进:用StringBuffer,添加相同的字符串
flag=true;
}
}
if (flag){//有相同字符串时,不再寻找下轮子字符串,
return "";//改进:返回 StringBuffer对象添加后的值
}
}
return null;
}
return shortStr;
}
}
- 对字符串中字符进行自然顺序排序。
//方式一:Arrays.sort()
public class Test05 {
public static void main(String[] args) {
Test05 test05 = new Test05();
String str = test05.mySort("ajbvabvaknv");
System.out.println(str);
}
public String mySort(String str){
char[] chars = str.toCharArray();
Arrays.sort(chars);
String s = new String(chars);
return s;
}
}
//方式二:选择,冒泡。。
字符串相关的类:StringBuffer、StringBuilder
String、StringBuffer、StringBuilder三者的异同
- String:不可变的字符序列;底层使用char[]存储
- StringBuffer:可变的字符序列;线程安全的,效率低;底层使用char[]存储
- StringBuilder:可变的字符序列;jdk5.0新增;线程不安全,效率高;底层使用char[]存储
源码分析
/*
源码分析
String str = new String();//char[] value = new char[0];
String str1 = new String("abc");//char[] value = new char[]{'a','b','c'};
StringBuffer sb1 = new StringBuffer();//char[] value = new char[16];底层创建了一个长度为16的数组;
sb1.append('a');//value[0] = 'a';
sb1.append('b');//value[1] = 'b';
StringBuffer sb2 = new StringBuffer("abc");//char[] value = new char["abc".length() + 16];
问题1:System.out.println(sb2.length());// 3
问题2:扩容问题:如果要添加的数据底层数组盛不下了,那就需要扩容底层的数组。
默认情况下,扩容为原来的两倍+2,同时将原有数组中的元素复制到新的数组中。
指导意义:开发中建议使用:StringBuffer(int capacity) 或 StringBuilder(int capacity) 来指定容量避免扩容。
*/
public class StringBufferBuilder01 {
public static void main(String[] args) {
StringBuffer sb1 = new StringBuffer("abc");
System.out.println(sb1);//abc
sb1.append('d');
System.out.println(sb1);//abcd
sb1.setCharAt(0,'o');
System.out.println(sb1);//obcd
System.out.println(sb1.length());//4
}
}
StringBuffer的常用方法(StringBuilder的方法也一样)
- StringBuffer append(xxx);提供了很多的append()方法,用于进行字符串拼接
- StringBuffer delete(int start,int end);删除指定位置[start,end)的内容
- StringBuffer replace(int start,int end,String str);把[start,end)位置替换成str
- StringBuffer insert(int offset,xxx);在指定位置插入xxx
- StringBuffer reverse();把当前字符序列逆转
- int indexOf(String str);str在StringBuffer首次出现的位置
- String subString(int start,int end);返回一个[start,end)的子字符串
- int length(); 源码返回值:return count,不是容量,count记录有效字符的个数。
- char charAt(int index);返回某索引处的字符
- void setCharAt(int index,char ch);将指定位置的字符改为新的字符
StringBuffer s1 = new StringBuffer("abcdf");
s1.append("1");// 1. StringBuffer append(xxx);提供了很多的append()方法,用于进行字符串拼接
s1.append(2);
System.out.println(s1);//abcdf12
s1.delete(2,4);// 2. StringBuffer delete(int start,int end);删除指定位置[start,end)的内容
System.out.println(s1);//abf12 ,左闭右开
s1.replace(2,4,"hello");// 3. StringBuffer replace(int start,int end,String str);把[start,end)位置替换成str
System.out.println(s1);//abhello2
s1.insert(3,true);// 4. StringBuffer insert(int offset,xxx);在指定位置插入xxx
System.out.println(s1);//abhtrueello2
s1.reverse();// 5. StringBuffer reverse();把当前字符序列逆转
System.out.println(s1);//2olleeurthba
//不获取返回值也可以输出,因为StringBuffer是可变序列
System.out.println(s1.indexOf("eu"));//5
// 6. int indexOf(String str);str在StringBuffer首次出现的位置
System.out.println(s1.substring(3, 7));//leeu,要返回值String,没有改变当前StringBuffer
// 7. String subString(int start,int end);返回一个[start,end)的子字符串
System.out.println(s1.length());//12
// 8. int length(); 源码返回值:return count,不是容量,count记录有效字符的个数。
System.out.println(s1.charAt(6));//u
// 9. char charAt(int index);返回某索引处的字符
s1.setCharAt(1,'d');// 10. void setCharAt(int index,char ch);将指定位置的字符改为新的字符
System.out.println(s1);//2dlleeurthba
/*总结:
增:append(xxx); 方法链:s1.append().append().append()...,原理:返回值是自身
删:delete(int start,int end)
改:setCharAt(int index,char ch) / replace(int start,int end,String str)
查:charAt(int index)
插:insert(int offset,xxx)
长度:length();
*遍历:for + charAt() / toString()
*/
三者效率对比
效率从高到低:StringBuilder > StringBuffer > String
public class Efficiency {
public static void main(String[] args) {
//初始设置
long startTime=0L;
long endTime=0L;
String text="";
StringBuffer buffer = new StringBuffer("");
StringBuilder builder = new StringBuilder("");
//开始比较
startTime = System.currentTimeMillis();
for (int i = 0; i <20000 ; i++) {
buffer.append(String.valueOf(i));
}
endTime =System.currentTimeMillis();
System.out.println("StringBuffer的执行时间:"+(endTime-startTime));
startTime = System.currentTimeMillis();
for (int i = 0; i <20000 ; i++) {
builder.append(String.valueOf(i));
}
endTime =System.currentTimeMillis();
System.out.println("StringBuilder的执行时间:"+(endTime-startTime));
startTime = System.currentTimeMillis();
for (int i = 0; i <20000 ; i++) {
text = text + i;
}
endTime =System.currentTimeMillis();
System.out.println("String的执行时间:"+(endTime-startTime));
}
}
String与StringBuffer、StringBuilder之间的转换
- String - - > StringBuffer、StringBuilder :调用StringBuffer、StringBuilder构造器
- StringBuffer、StringBuilder - - > String :①调用String构造器、 ② StringBuffer、StringBuilder 的toString()方法
JVM中字符串常量池存放位置
- jdk 1.6(jdk 6.0 ,java 6.0):字符串常量池存储在方法区(永久区)
- jdk 1.7:字符串常量池存储在堆空间
- jdk 1.8:字符串常量池存储在方法区(元空间)