leetcode 38. Count and Say
题目:从“1”开始,后一个是前一个读出的数字……
1 one 1–>11
11 two 1–>21
21 one 2 one 1–>1211
1211 one 1 one 2 two 1–>111221
以此类推……
第一个思路:
递归思想,写一个say()函数,写出“1”的,然后递归n-1次,得到第n层的值,利用String
代码如下:
public String countAndSay(int n) {
String result = "";
if(n==1) {
result = 1+"";
}else{
result = say(countAndSay(n-1));//第n个输出为say第n-1个输出
}
return result;
}
public String say(String str){
String r = "";
int n1 = 1;
str = str+" ";//方便比对时的下标处理
for(int i = 0;i<str.length()-1;i++){
if(str.charAt(i)==str.charAt(i+1))
n1++;
else{
r = r + n1 + str.charAt(i);//到下标为i时的结果
n1 = 1;
}
}
return r;
}
进一步优化:使用StringBuffer或者StringBuilder
代码如下:
public String countAndSay(int n) {
StringBuffer cur = new StringBuffer("1");
StringBuffer pre;
for(int i = 1;i<n;i++){
pre = cur;
cur = new StringBuffer();
int n1 = 1;
pre = pre.append(" ");//方便比对时的下标处理
for(int j = 0;j<pre.length()-1;j++){
if(pre.charAt(j)==pre.charAt(j+1))
n1++;
else{
cur.append(n1).append(pre.charAt(j));//到下标为i时的结果
n1 = 1;
}
}
}
String result = cur.toString();
return result;
}
———————————分割线———————————
- java中数字转换成字符串的方法
方法一:直接强制转换。如:String str= (String)123;
方法二:直接通过空字符串+数字的形式转换为字符串(前后都可以用)。如:String str= “”+123;
方法三:直接通过包装类来实现。如:String str = String.valueOf(1231); - Java:String、StringBuffer和StringBuilder的区别
1). String
String:字符串常量,字符串长度不可变。
2). StringBuffer
Java.lang.StringBuffer:线程安全的可变字符序列,即字符串变量(Synchronized,即线程安全)。在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。可将字符串缓冲区安全地用于多个线程。如果要频繁对字符串内容进行修改,出于效率考虑最好使用StringBuffer,如果想转成String类型,可以调用StringBuffer的toString()方法。eg.
String z = “start”;
z.append(“le”) ;//“startle”
z.insert(4, “le”);//“starlet”
3).StringBuilder
java.lang.StringBuilder:可变的字符序列,字符串变量(非线程安全,JDK5.0新增的)。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)
三者区别
String 类型和StringBuffer的主要性能区别:String是不可变的对象, 每次对String 类型进行改变时,都会生成一个新String 对象,然后将指针指向新String 对象,所以经常改变内容的字符串最好不要用 String ,每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后,JVM的GC就会开始工作,性能就会降低。
使用StringBuffer类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。所以多数情况下推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。
在某些特别情况下, String 对象的字符串拼接其实是被 Java Compiler 编译成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,例如:
String s1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
由于在Java Compiler里,自动把上述第一条语句编译为:String s1 = “This is only a simple test”; 所以生成 String s1对象的速度并不比 StringBuffer慢。
但如果拼接的字符串来自另外的String对象的话,Java Compiler就不会自动转换了,速度也就没那么快了,例如:
String s2 = “This is only a”;
String s3 = “ simple”;
String s4 = “ test”;
String s1 = s2 + s3 + s4;
这时Java Compiler会按照原来的方式做,String的concatenation(即+)操作利用了StringBuilder(或StringBuffer)的append方法实现,此时,对于上述情况,若s2,s3,s4采用String定义,拼接时需额外创建一个StringBuffer(或StringBuilder),之后将StringBuffer转换为String;若采用StringBuffer(或StringBuilder),则不需额外创建StringBuffer。
StringBuilder类和StringBuffer类的区别:StringBuilder一般使用在方法内部来完成类似”+”功能,因为是线程不安全的,所以用完以后可以丢弃。StringBuffer主要用在全局变量中。相同情况下使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。而在现实的模块化编程中,负责某一模块的程序员不一定能清晰地判断该模块是否会放入多线程的环境中运行,因此:除非确定系统的瓶颈是在 StringBuffer 上,并且确定模块不会运行在多线程模式下,才可以采用StringBuilder;否则还是用StringBuffer。
使用策略
1). 基本原则:操作少量的数据,用String ;单线程操作大量数据,用StringBuilder ;多线程操作大量数据,用StringBuffer。
2). 不要使用String类的”+”来进行频繁的拼接,性能极差,应使用StringBuffer或StringBuilder类,这在Java的优化上是一条比较重要的原则。例如:
String result = "";
for (String s : hugeArray) {
result = result + s;
}
// 使用StringBuilder
StringBuilder sb = new StringBuilder();
for (String s : hugeArray) {
sb.append(s);
}
String result = sb.toString();
因为第一种方法,每次循环都会创建一个String result用于保存结果。
3). 为了获得更好的性能,在构造 StringBuffer 或 StringBuilder 时应尽可能指定它们的容量。当然,如果你操作的字符串长度(length)不超过 16 个字符就不用了,当不指定容量(capacity)时默认构造一个容量为16的对象。不指定容量会显著降低性能。
4). StringBuilder一般用在方法内部,用完可丢弃。StringBuffer主要用在全局变量中。
5). 在现实的模块化编程中,除非确定系统的瓶颈是在 StringBuffer 上,并且确定模块不会运行在多线程模式下,才可以采用StringBuilder;否则还是用StringBuffer。