题目
因为是String 类型故而能够存下很长的数据进行计算,因此不可以转换数据类型计算,而是从乘法的本质进行循环计算:相当于把两个数字的每两位之间进行计算并放在合适的的位置上储存它,因此设定num1、num2两者长度加起来那么长得到数组存储计算结果,并在存储规范化后输出结果。
JAVA实现
class Solution {
public String multiply(String num1, String num2) {
if(num1=="0"||num2=="0")
return "0";
int [] result=new int[num1.length()+num2.length()];//自动初始置0
for(int i=num1.length()-1;i>=0;i--){
for(int j=num2.length()-1;j>=0;j--){
result[result.length-1-(num1.length()-1-i)-(num2.length()-1-j)]+=(num1.charAt(i)-'0')*(num2.charAt(j)-'0');
}
}
for(int i=result.length-1;i>0;i--){
result[i-1]+=result[i]/10;
result[i]=result[i]%10;
}
String a="";
int flag=0;
for(int i=0;i<result.length;i++){
if(result[i]>0){
flag=1;
a+=(result[i]+"");
}
if(result[i]==0&&flag==1){
a+=(result[i]+"");
}
}
return a;
}
};
问题出现在"0""0"的情况,eclipse结果是“0”但是这个编译器就很奇怪。换种方法吧,先把nums1,num2的值换成int 判断一下是否为零。。。暂且把锅丢给编译器吧
本来打算就此打住,幸运的是在下午JAVA的学习中,我发现了问题所在:
num1=="0"本身就存在问题,与之相似的是num1.equals("0")
这里十分感谢(https://www.cnblogs.com/enjong/articles/8543982.html)
让我了解了JAVA中String的特点
String使用的equals方法和==的区别
equals方法和==的区别
首先大家知道,String既可以作为一个对象来使用,又可以作为一个基本类型来使用。这里指的作为一个基本类型来使用只是指使用方法上的,比如String s = "Hello",它的使用方法如同基本类型int一样,比如int i = 1;,而作为一个对象来使用,则是指通过new关键字来创建一个新对象,比如String s = new String("Hello")。但是它的内部动作其实还是创建了一个对象,这点稍后会说到。
其次,对String对象的比较方法需要了解。Java里对象之间的比较有两种概念,这里拿String对象来说:一种是用"=="来比较,这种比较是针对两个String类型的变量的引用,也就是说如果两个String类型的变量,它们所引用同一个String对象(即指向同一块内存堆),则"=="比较的结果是true。另一种是用Object对象的equals()方法来比较,String对象继承自Object,并且对equals()方法进行了重写。两个String对象通过equals()方法来进行比较时,其实就是对String对象所封装的字符串内容进行比较,也就是说如果两个String对象所封装的字符串内容相同(包括大小写相同),则equals()方法将返回true。
现在开始将对String对象的创建做具体的分析:
1、/
String s1 = new String("Hello");
String s2 = new String("Hello");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
以上代码段的打印结果是:
false
true
这个结果相信大家很好理解,两个String类型的变量s1和s2都通过new关键字分别创建了一个新的String对象,这个new关键字为创建的每个对象分配一块新的、独立的内存堆。因此当通过"=="来比较它们所引用的是否是同一个对象时,将返回false。而通过equals()方法来比较时,则返回true,因为这两个对象所封装的字符串内容是完全相同的。
2、//
String s1 = new String("Hello");
String s2 = s1;
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
以上代码段的打印结果是:
true
true
这个结果应该更好理解,变量s1还是通过new关键字来创建了一个新的String对象,但这里s2并没有通过new关键字来创建一个新的String对象,而是直接把s1赋值给了s2,即把s1的引用赋值给了s2,所以s2所引用的对象其实就是s1所引用的对象。所以通过"=="来比较时,返回true。既然它们引用的都是同一个对象,那么通过equals()方法来比较时,肯定也返回true,这里equals()方法其实在对同一个对象进行比较,自己肯定等于自己咯。
3、//
String s1 = "Hello";
String s2 = "Hello";
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
以上代码段的打印结果是:
true
true
为什么这个结果?那么来分析一下。首先这两个String对象都是作为一个基本类型来使用的,而不是通过new关键字来创建的,因此虚拟机不会为这两个String对象分配新的内存堆,而是到String缓冲池中来寻找。
首先为s1寻找String缓冲池内是否有与"Hello"相同值的String对象存在,此时String缓冲池内是空的,没有相同值的String对象存在,所以虚拟机会在String缓冲池内创建此String对象,其动作就是new String("Hello");。然后把此String对象的引用赋值给s1。
接着为s2寻找String缓冲池内是否有与"Hello"相同值的String对象存在,此时虚拟机找到了一个与其相同值的String对象,这个String对象其实就是为s1所创建的String对象。既然找到了一个相同值的对象,那么虚拟机就不在为此创建一个新的String对象,而是直接把存在的String对象的引用赋值给s2。
这里既然s1和s2所引用的是同一个String对象,即自己等于自己,所以以上两种比较方法都返回ture。
到这里,对String对象的基本概念应该都已经理解了。现在我来小结一下:
针对String作为一个基本类型来使用:
1。如果String作为一个基本类型来使用,那么我们视此String对象是String缓冲池所拥有的。
2。如果String作为一个基本类型来使用,并且此时String缓冲池内不存在与其指定值相同的String对象,那么此时虚拟机将为此创建新的String对象,并存放在String缓冲池内。
3。如果String作为一个基本类型来使用,并且此时String缓冲池内存在与其指定值相同的String对象,那么此时虚拟机将不为此创建新的String对象,而直接返回已存在的String对象的引用。
针对String作为一个对象来使用:
1。如果String作为一个对象来使用,那么虚拟机将为此创建一个新的String对象,即为此对象分配一块新的内存堆,并且它并不是String缓冲池所拥有的,即它是独立的。
理解了以上内容后,请看以下代码段:
4、/
String s1 = "Hello";
String s2 = new String("Hello");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
以上代码段的打印结果是:
false
true
根据上面的小结来进行分析。第一行是把String作为一个基本类型来使用的,因此s1所引用的对象是属于String缓冲池内的。并且此时String缓冲池内并没有与其值相同的String对象存在,因此虚拟机会为此创建一个新的String对象,即new String("Hello");。第二行是把String作为一个对象来使用的,因此s2所引用的对象不属于String缓冲池内的,即它是独立的。通过new关键字,虚拟机会为此创建一个新的String对象,即为它分配了一块新的内存堆。因此"=="比较后的结果是false,因为s1和s2所引用的并不是同一个对象,它们是独立存在的。而equals()方法所返回的是true,因为这两个对象所封装的字符串内容是完全相同的。
现在,相信大家已经完全搞清楚String对象是怎么一回事了:)但是到此并没有结束,因为String对象还有更深层次的应用。
这里我将分析一下String对象的intern()方法的应用:
intern()方法将返回一个字符串对象的规范表示法,即一个同该字符串内容相同的字符串,但是来自于唯一字符串的String缓冲池。这听起来有点拗口,其实它的机制有如以下代码段:
String s = new String("Hello");
s = s.intern();
以上代码段的功能实现可以简单的看成如下代码段:
String s = "Hello";
你一定又开始疑惑了?那么你可以先看第二个代码段。第二个代码段的意思就是从String缓冲池内取出一个与其值相同的String对象的引用赋值给s。如果String缓冲池内没有与其相同值的String对象存在,则在其内为此创建一个新的String对象。那么第一段代码的意思又是什么呢?我们知道通过new关键字所创建出的对象,虚拟机会为它分配一块新的内存堆。如果平凡地创建相同内容的对象,虚拟机同样会为此分配许多新的内存堆,虽然它们的内容是完全相同的。拿String对象来说,如果连续创建10个相同内容的String对象(new String("Hello")),那么虚拟机将为此分配10块独立的内存堆。假设所创建的String对象的字符串内容十分大,假设一个Stirng对象封装了1M大小的字符串内容,那么如果我们创建10个此相同String对象的话,我们将会毫无意义的浪费9M的内存空间。我们知道String是final类,它所封装的是字符串常量,因此String对象在创建后其内部(字符串)值不能改变,也因此String对象可以被共享。所以对于刚才提到的假设,我们所创建的10个相同内容的String对象,其实我们只需为此创建一个String对象,然后被其它String变量所共享。要实现这种机制,唯一的、简单的方法就是使用String缓冲池,因为String缓冲池内不会存在相同内容的String对象。而intern()方法就是使用这种机制的途径。在一个已实例化的String对象上调用intern()方法后,虚拟机会在String缓冲池内寻找与此Stirng对象所封装的字符串内容相同值的String对象,然后把引用赋值给引用原来的那个String对象的String类型变量。如果String缓冲池内没有与此String对象所封装的字符串内容相同值的String对象存在,那么虚拟机会为此创建一个新的String对象,并把其引用赋值给引用原来的那个String对象的String类型变量。这样就达到了共享同一个String对象的目的,而原先那个通过new关键字所创建出的String对象将被抛弃并被垃圾回收器回收掉。这样不但降低了内存的使用消耗,提高了性能,而且在String对象的比较上也同样更方便了,因为相同的String对象将被共享,所以要判断两个String对象是否相同,则只需要使用"=="来比较,而无需再使用equals()方法来比较,这样不但使用起来更方便,而且也提高了性能,因为String对象的equals()方法将会对字符串内容拆解,然后逐个进行比较,如果字符串内容十分大的话,那么这个比较动作则大大降低了性能。
说到此,大家可能对具体应用还有点模糊,那么我来举个简单的示例,以便阐述以上概念:
假设有一个类,它有一个记录消息的方法,这个方法记录用户传来的消息(假设消息内容可能较大,并且重复率较高),并且把消息按接收顺序记录在一个列表中。我想有些朋友会这样设计:
import java.util.*;
public class Messages {
ArrayList messages = new ArrayList();
public void record(String msg) {
messages.add(msg);
}
public List getMessages() {
return messages;
}
}
这种设计方案好吗?假设我们重复的发送给record()方法同一个消息(消息来自不同的用户,所以可以视每个消息为一个new String("...")),并且消息内容较大,那么这个设计将会大大浪费内存空间,因为消息列表中记录的都是新创建的、独立的String对象,虽然它们的内容都相同。那么怎么样可以对其进行优化呢,其实很简单,请看如下优化后的示例:
import java.util.*;
public class Messages {
ArrayList messages = new ArrayList();
public void record(String msg) {
messages.add(msg.intern());
}
public List getMessages() {
return messages;
}
}
正如你所看到的,原先record()方法中的messages.add(msg);代码段变成了messages.add(msg.intern());,仅仅对msg参数调用了intern()方法,这样将对重复的消息进行共享机制,从而降低了内存消耗,提高了性能。
这个例子的确有点牵强,但是这里只是为了阐述以上概念!
至此,String对象的迷雾都被消除了,大家只要牢记这些概念,以后再复杂的String应用都可以建立在此基础上来进行分析。
所学知识汇总
Java 中int、String的类型转换
int -> String
int i=12345;
String s=""; /*必须初始化或有内容之后,另外String的赋值只能用“ ”而不能用' ',由此可见在java中的char[[与 String并不像c中的联系密切*/
第一种方法:s=i+"";
第二种方法:s=String.valueOf(i);
这两种方法有什么区别呢?作用是不是一样的呢?是不是在任何下都能互换呢?String -> int
s="12345";
int i;
第一种方法:i=Integer.parseInt(s);
第二种方法:i=Integer.valueOf(s).intValue();
这两种方法有什么区别呢?作用是不是一样的呢?是不是在任何下都能互换呢?以下是答案:
第一种方法:s=i+""; //会产生两个String对象
第二种方法:s=String.valueOf(i); //直接使用String类的静态方法,只产生一个对象第一种方法:i=Integer.parseInt(s);//直接使用静态方法,不会产生多余的对象,但会抛出异常
第二种方法:i=Integer.valueOf(s).intValue();//Integer.valueOf(s) 相当于 new Integer(Integer.parseInt(s)),也会抛异常,但会多产生一个对象--------------------------------------------------------------------
1如何将字串 String 转换成整数 int?
A. 有两个方法:
1). int i = Integer.parseInt([String]); 或
i = Integer.parseInt([String],[int radix]);
2). int i = Integer.valueOf(my_str).intValue();
注: 字串转成 Double, Float, Long 的方法大同小异.2 如何将整数 int 转换成字串 String ?
A. 有叁种方法:
1.) String s = String.valueOf(i);
2.) String s = Integer.toString(i);
3.) String s = "" + i;
注: Double, Float, Long 转成字串的方法大同小异.
http://blog.sina.com.cn/s/blog_4f9d6b1001000bfo.html
回头才发现数组result可以用length求长度,但是String是个对象,并不是数组故而要用num1.length()
因此特地学习JAVA中String的知识(https://www.cnblogs.com/cisum/p/8011485.html)
Java String 类
字符串广泛应用 在Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。
创建字符串
创建字符串最简单的方式如下:
String greeting = "菜鸟教程";
在代码中遇到字符串常量时,这里的值是 "菜鸟教程"",编译器会使用该值创建一个 String 对象。
和其它对象一样,可以使用关键字和构造方法来创建 String 对象。
String 类有 11 种构造方法,这些方法提供不同的参数来初始化字符串,比如提供一个字符数组参数:
StringDemo.java 文件代码:
public class StringDemo{ public static void main(String args[]){ char[] helloArray = { 'r', 'u', 'n', 'o', 'o', 'b'}; String helloString = new String(helloArray); System.out.println( helloString ); } }
以上实例编译运行结果如下:
runoob
注意:String 类是不可改变的,所以你一旦创建了 String 对象,那它的值就无法改变了(详看笔记部分解析)。
如果需要对字符串做很多修改,那么应该选择使用 StringBuffer & StringBuilder 类。
字符串长度
用于获取有关对象的信息的方法称为访问器方法。
String 类的一个访问器方法是 length() 方法,它返回字符串对象包含的字符数。
下面的代码执行后,len变量等于14:
StringDemo.java 文件代码:
public class StringDemo { public static void main(String args[]) { String site = "www.runoob.com"; int len = site.length(); System.out.println( "菜鸟教程网址长度 : " + len ); } }
以上实例编译运行结果如下:
菜鸟教程网址长度 : 14
连接字符串
String 类提供了连接两个字符串的方法:
string1.concat(string2);
返回 string2 连接 string1 的新字符串。也可以对字符串常量使用 concat() 方法,如:
"我的名字是 ".concat("Runoob");
更常用的是使用'+'操作符来连接字符串,如:
"Hello," + " runoob" + "!"
结果如下:
"Hello, runoob!"
下面是一个例子:
StringDemo.java 文件代码:
public class StringDemo { public static void main(String args[]) { String string1 = "菜鸟教程网址:"; System.out.println("1、" + string1 + "www.runoob.com"); } }
以上实例编译运行结果如下:
1、菜鸟教程网址:www.runoob.com
创建格式化字符串
我们知道输出格式化数字可以使用 printf() 和 format() 方法。
String 类使用静态方法 format() 返回一个String 对象而不是 PrintStream 对象。
String 类的静态方法 format() 能用来创建可复用的格式化字符串,而不仅仅是用于一次打印输出。
如下所示:
System.out.printf("浮点型变量的值为 " + "%f, 整型变量的值为 " + " %d, 字符串变量的值为 " + "is %s", floatVar, intVar, stringVar);
你也可以这样写
String fs; fs = String.format("浮点型变量的值为 " + "%f, 整型变量的值为 " + " %d, 字符串变量的值为 " + " %s", floatVar, intVar, stringVar);
String 方法
下面是 String 类支持的方法,更多详细,参看 Java String API 文档:
Java StringBuffer 和 StringBuilder 类
笔记列表
String 类是不可改变的解析,例如:
String s = "Google"; System.out.println("s = " + s); s = "Runoob"; System.out.println("s = " + s);
输出结果为:
Google Runoob
从结果上看是改变了,但为什么门说String对象是不可变的呢?
原因在于实例中的 s 只是一个 String 对象的引用,并不是对象本身,当执行 s = "Runoob"; 创建了一个新的对象 "Runoob",而原来的 "Google" 还存在于内存中。
length()方法,length属性和size()的方法的区别:
- 1.length()方法是针对字符串来说的,要求一个字符串的长度就要用到它的length()方法;
- 2.length属性是针对Java中的数组来说的,要求数组的长度可以用其length属性;
- 3.java中的size()方法是针对泛型集合说的,如果想看这个泛型有多少个元素,就调用此方法来查看!
这个例子来演示这两个方法和一个属性的用法:
public static void main(String[] args) { String []list={"ma","cao","yuan"}; String a="macaoyuan"; System.out.println(list.length); System.out.println(a.length()); List array=new ArrayList(); array.add(a); System.out.println(array.size()); }
输出的值为:
3 9 1
1.对整数进行格式化:%[index$][标识][最小宽度]转换方式
格式化字符串由4部分组成,特殊的格式常以%index$开头,index从1开始取值,表示将第index个参数拿进来进行格式化,[最小宽度]的含义也很好理解,就是最终该整数转化的字符串最少包含多少位数字。剩下2个部分的含义:
标识:
- '-' 在最小宽度内左对齐,不可以与"用0填充"同时使用
- '#' 只适用于8进制和16进制,8进制时在结果前面增加一个0,16进制时在结果前面增加0x
- '+' 结果总是包括一个符号(一般情况下只适用于10进制,若对象为BigInteger才可以用于8进制和16进制)
- ' ' 正值前加空格,负值前加负号(一般情况下只适用于10进制,若对象为BigInteger才可以用于8进制和16进制)
- '0' 结果将用零来填充
- ',' 只适用于10进制,每3位数字之间用","分隔
- '(' 若参数是负数,则结果中不添加负号而是用圆括号把数字括起来(同'+'具有同样的限制)
转换方式:
d-十进制 o-八进制 x或X-十六进制
上面的说明过于枯燥,我们来看几个具体的例子。需要特别注意的一点是:大部分标识字符可以同时使用。
System.out.println(String.format("%1$,09d", -3123)); System.out.println(String.format("%1$9d", -31)); System.out.println(String.format("%1$-9d", -31)); System.out.println(String.format("%1$(9d", -31)); System.out.println(String.format("%1$#9x", 5689)); //结果为: //-0003,123 // -31 //-31 // (31) // 0x1639
2.对浮点数进行格式化:%[index$][标识][最少宽度][.精度]转换方式
我们可以看到,浮点数的转换多了一个"精度"选项,可以控制小数点后面的位数。
标识:
- '-' 在最小宽度内左对齐,不可以与"用0填充"同时使用
- '+' 结果总是包括一个符号
- ' ' 正值前加空格,负值前加负号
- '0' 结果将用零来填充
- ',' 每3位数字之间用","分隔(只适用于fgG的转换)
- '(' 若参数是负数,则结果中不添加负号而是用圆括号把数字括起来(只适用于eEfgG的转换)
转换方式:
- 'e', 'E' -- 结果被格式化为用计算机科学记数法表示的十进制数
- 'f' -- 结果被格式化为十进制普通表示方式
- 'g', 'G' -- 根据具体情况,自动选择用普通表示方式还是科学计数法方式
- 'a', 'A' -- 结果被格式化为带有效位数和指数的十六进制浮点数
3.对字符进行格式化:
对字符进行格式化是非常简单的,c表示字符,标识中'-'表示左对齐,其他就没什么了。