String字符串
字符串是由char类型的数组组成的
代码的执行过程
内存空间可以分为栈内存和堆内存
1..java通过javac变成.class文件,通过java命令将文件加载到方法区当中
2.首先加载main方法,会将main加载到栈内存当中,两个变量也会进行加载,栈内存中存放变量名。
字符串会被存储在字符串常量池中
因此“123”存储在字符串常量池中
3.a记录字符串的地址
字符串常量池中字符串是共享的,从而减少存储字符串内存空间,解决大量的字符冗余的问题。
4.因此b记录字符串“123”的地址,a和b记录的地址值相同,因此执行结果为true
==和equals的区别与联系
例1
public class Demo {
public static void main(String[] args) {
String a="123";//创建字符串
String b="123";
String c=new String("123");//new关键字是在堆内存当中开辟一块内存空间
System.out.println(a==c);
System.out.println(b==c);
//==对于基本类型来说,==是进行值的判断
//对于引用类型(如String 是一个类)来说,==是判断地址是否相同
}
}
代码执行过程:
执行String c=new String("123");
会在堆内存当中新开辟一段内存空间,c会指向这块内存空间,因为c定义的值是“123”,所以这块内存空间会记录字符串常量池当中“123”的地址值。
例2
public class Demo {
public static void main(String[] args) {
String a="123";//创建字符串
String b="123";
String c=new String("123");//new关键字是在堆内存当中开辟一块内存空间
System.out.println(a==c);
System.out.println(b==c);
System.out.println(a.equals(c));
int a1=10;
int b1=10;
//System.out.println(a1.equals(b1));//equals方法报错,因为基本数据类型没有这个方法
//==对于基本类型来说,==是进行值的判断,基本数据来行只能用==来进行判断
//对于引用类型(如String 是一个类)来说,==是判断地址是否相同
//equals首先比较地址是否相等,如果相等返回true,如果不相等,比较值是否相等
}
}
==对于基本类型来说,==是进行值的判断,基本数据来行只能用==来进行判断
对于引用类型(如String 是一个类)来说,==是判断地址是否相同
equals首先比较地址是否相等,如果相等返回true,如果不相等,比较值是否相等
字符串中的方法
public class Demo {
public static void main(String[] args) {
String a="Hello World";//创建字符串
//length()方法------获取字符串的长度
int length=a.length();
System.out.println(length);
//charAt(index)根据位置获取指定的字符,下标从0开始
char ch=a.charAt(1);
System.out.println(ch);
//substring(index)方法,截取字符串
String b=a.substring(6);//左闭区间
System.out.println(b);
String c=a.substring(6,11);//左闭右开区间
System.out.println(c);
//判断是否有子串 contains(子串)
System.out.println(a.contains("Hel"));
//子串替换 replace
String newa=a.replace('o','x');
System.out.println(newa);
String newb=a.replace("World","aaa");
System.out.println(newb);
//字符串分割
String str="apple,banana,orange";
String[] parts=str.split(",");
for (int i=0;i<parts.length;i++){
System.out.println(parts[i]);
}
}
}
KMP算法-----大串当中找小串
在aabaabaafa中找aabaaf
解决方案1.利用双层for循环找 时间复杂度O(n^2)
解决方案2.KMP:找最长相等的前后缀组成的前缀表 O(m+n)
1.前缀和后缀
前缀:不包含最后一个字符的所有以第一个字符开头的连续字符串
后缀:不包含第一个字符的所有以最后一个字符结尾的连续字符串
2.找最长相等的前后缀组成的前缀表
3.KMP算法执行过程
第一步:
两个游标从前向后进行变量,并且比较值是否相等,如果相等执行i++j++。
如果不相等,那么则和暴力解法不—致!
第二步:
如果我们此时能够让i游标不动,同时j游标指向b是最好的。
如何指向b?
1.找前缀,后缀
2.找到最长相等前后缀的长度
3.利用前缀表重新匹配并构造next数组
很多KMP算法的实现都是使用next数组来做回退操作,那么next数组与前缀表有什么关系呢?
next数组就可以是前缀表,但是很多实现都是把前缀表统一减一(右移一位,初始位置为-1)之后作为next数组。
这并不涉及到KMP的原理,而是具体实现,next数组既可以就是前缀表,也可以是前缀表统一减一(右移一位,初始位置为-1)
next数组的构建过程(参考LeeCode有关作者)
第三步:
首先匹配串会检查之前已经匹配成功的部分中里是否存在相同的「前缀」和「后缀」。如果存在,则跳转到「前缀」的下一个位置继续往下匹配:
跳转到下一匹配位置后,尝试匹配,发现两个指针的字符对不上,并且此时匹配串指针前面不存在相同的「前缀」和「后缀」,这时候只能回到匹配串的起始位置重新开始:
代码实现:
class Solution {
public int strStr(String haystack, String needle) {
int n = haystack.length();
int m = needle.length();
if (m == 0) {
return 0;
}
// 原串和匹配串前面都加空格,使其下标从 1 开始
char[] s = haystack.toCharArray();
char[] p = needle.toCharArray();
// 构建 next 数组,数组长度为匹配串的长度(next 数组是和匹配串相关的)
int[] next = new int[m];
int j = 0;
// 构造过程 i = 1,j = 0 开始
for (int i = 1; i < m; i++) {
// 匹配不成功的话,j = next(j-1)
while (j > 0 && p[i] != p[j]){
if(j>0){
j = next[j-1];
}
}
// 匹配成功的话, j++
if (p[i] == p[j]){
j++;
}
next[i]=j;
}
j=0;
// 匹配过程
for (int i = 0; i <n; i++) {
// 匹配不成功
while (j > 0 && s[i] != p[j]){
if (j > 0) {
j = next[j - 1];
}
}
// 匹配成功的话,先让 j++,结束本次循环后 i++
if (s[i] == p[j]){
j++;
}
// 整一段匹配成功,直接返回下标
if (j == m) {
return i- m+1;
}
}
return -1;
}
}
字符串的拼接
示例
public static void main(String[] args) {
//字符串的拼接
// String s1="123";
// String s2="456";
// String s3=s1+s2;//
// System.out.println(s3);
// String s4="123456";
// System.out.println(s3==s4);
String s1="123"+"456";//自动拼接,在编译期间变为。class文件就会变为“123456”
String s2="123456";
System.out.println(s1==s2);
}
在使用append方法进行字符串拼接之后,再通过toString()方法开辟一块新的堆内存空间,使得S3记录的地址值为新的内存空间,结果为false
在转化为.class文件时,就已经实现自动拼接,因此最后地址值相同,结果为true
字符串的输入输出
Scanner in = new Scanner(System.in);
String name = in.next();
public static void main(String[] args) {
Scanner inScanner=new Scanner(System.in);
System.out.println("您的姓名?");
String name=inScanner.nextLine();
Scanner inage=new Scanner(System.in);
System.out.println("您的年龄?");
int age=inage.nextInt();
System.out.println(name+":"+age);
}
public static void main(String[] args) {
System.out.println("输入数组大小为:");
Scanner inlength = new Scanner(System.in);
int length = inlength.nextInt();
int[] arr=new int[length];
System.out.println("输入数组内容:");
for(int i=0;i<arr.length;i++){
Scanner inScanner=new Scanner(System.in);
arr[i]=inScanner.nextInt();
}
System.out.println(Arrays.toString(arr));
}
执行结果
示例:一个有趣的猜一猜小游戏
public static void main(String[] args) {
//1.通过Random类中方法nextInt(),生成一个1-100之间的随机数
int randomNum=new Random().nextInt(100);
System.out.println("随机数已生成");
//2.输入猜的数字
System.out.println("猜猜是哪个数:");
Scanner s=new Scanner(System.in);
int enterNum=s.nextInt();
//3.通过while循环,进行猜数字对错判断
//猜对,跳出循环,游戏结束
while(enterNum!=randomNum){
//猜错了,根据结果,给出提示,接着猜数字,游戏继续
if(enterNum>randomNum){
//如果猜大了,打印sorry,您猜大了!继续下一次循环
System.out.println("猜大了");
}else{
//如果猜小了,打印sorry,您猜小了!继续下一次循环
System.out.println("猜小了");
}
//输入猜的数字
System.out.println("猜猜是哪个数");
enterNum=s.nextInt();
}
System.out.println("恭喜你,答对了");
}
执行结果
欢迎大家点赞,评论,收藏和关注呦!!