kotlin中Int.toString()的时间复杂性

kotlin中Int.toString()的时间复杂性,kotlin,time-complexity,Kotlin,Time Complexity,我想知道kotlin中默认方法toString()的时间复杂度。是O(1)还是O(n)。我做了一些搜索,但没有找到任何答案。例如: 如果要将int数组转换为字符串,我使用了: var s = "" array.forEach{ s+= it.toString() } 但是如果数组大小是10^4,我会得到TLE。如果我不使用toString(),那么我就不会得到TLE。我知道还有其他方法可以将Int数组转换为String。但我想知道kotlin中default toStr

我想知道kotlin中默认方法toString()的时间复杂度。是O(1)还是O(n)。我做了一些搜索,但没有找到任何答案。例如: 如果要将int数组转换为字符串,我使用了:

var s = ""
array.forEach{
  s+= it.toString()
}

但是如果数组大小是10^4,我会得到TLE。如果我不使用toString(),那么我就不会得到TLE。我知道还有其他方法可以将Int数组转换为String。但我想知道kotlin中default toString()方法的时间复杂性。TIA

Kotlin不保证产品的复杂性

它可能因对象而异;每个对象都必须实现它,因此它可能取决于对象的结构及其字符串表示。  在很多情况下,我猜它的长度很可能是线性的,但你不应该依赖它。  但这确实意味着使用短字符串表示的对象可能只需要很少的时间,因此不值得担心

特别是,对于
Int
s,字符串的大小很可能是线性的(因此与数字的对数成正比)。  但这对于任何现实世界的项目来说都不太重要

然而,可能重要的是构造的
字符串
对象的数量,因为这些对象占用内存,然后加速下一次垃圾收集。  (即使对于占用相同时间的垃圾收集器,不管“死”对象的数量如何,拥有大量临时对象也会使它们运行得更频繁。  在高通量系统中,这可能非常重要。)

这当然是问题中代码的一个问题,每次循环都会创建两个新的
String
实例!  一个是调用
toString()
的结果;另一个是将其附加到
s
的结果。  (虽然前者总是很小,但后者每次都会不断增长,这使得空间需求呈二次型。)  这就是为什么在循环中进行字符串连接通常不是一个好主意

当然,
String
是不可变的,但是它有一个可变的助手类。  因此使用
StringBuilder
来累积结果,然后在末尾创建
字符串(如果需要)几乎总是更好的:

val sb = StringBuilder()
array.forEach {
  sb.append(it.toString())
}
val s = sb.toString()
在这种情况下,您可以做得更好,因为
StringBuilder
重载
append()
。  因此,您可以直接附加
Int
,而无需创建中间
字符串

val sb = StringBuilder()
array.forEach {
  sb.append(it)
}
val s = sb.toString()
创建的唯一临时对象是
StringBuilder
的内部数组;随着内容的不断增长,它将需要重新分配其数组来容纳它们。  如果可以估计最终结果的大小,则可以预先调整
StringBuilder
的大小,以避免这种开销

但实际上,您可能根本不会使用循环;您可以使用,它可以为您完成所有这些:

val s = array.joinToString("")
这一版本更短、更简单、更容易阅读,而且可能与手工编码版本一样好用。  Kotlin有很多有用的扩展函数;很值得去熟悉他们


如果您需要自己尽可能高效地构造复杂的字符串表示,而不是使用
toString()
来创建每个部分,每个相关类都可以有一个方法,该方法将
StringBuilder
作为参数,并将其部分附加到该参数上。  这可以让您构建任意复杂的字符串,而不需要任何
字符串
实例

Kotlin不保证问题的复杂性

它可能因对象而异;每个对象都必须实现它,因此它可能取决于对象的结构及其字符串表示。  在很多情况下,我猜它的长度很可能是线性的,但你不应该依赖它。  但这确实意味着使用短字符串表示的对象可能只需要很少的时间,因此不值得担心

特别是,对于
Int
s,字符串的大小很可能是线性的(因此与数字的对数成正比)。  但这对于任何现实世界的项目来说都不太重要

然而,可能重要的是构造的
字符串
对象的数量,因为这些对象占用内存,然后加速下一次垃圾收集。  (即使对于占用相同时间的垃圾收集器,不管“死”对象的数量如何,拥有大量临时对象也会使它们运行得更频繁。  在高通量系统中,这可能非常重要。)

这当然是问题中代码的一个问题,每次循环都会创建两个新的
String
实例!  一个是调用
toString()
的结果;另一个是将其附加到
s
的结果。  (虽然前者总是很小,但后者每次都会不断增长,这使得空间需求呈二次型。)  这就是为什么在循环中进行字符串连接通常不是一个好主意

当然,
String
是不可变的,但是它有一个可变的助手类。  因此使用
StringBuilder
来累积结果,然后在末尾创建
字符串(如果需要)几乎总是更好的:

val sb = StringBuilder()
array.forEach {
  sb.append(it.toString())
}
val s = sb.toString()
在这种情况下,您可以做得更好,因为
StringBuilder
重载
append()
。  因此,您可以直接附加
Int
,而无需创建中间
字符串

val sb = StringBuilder()
array.forEach {
  sb.append(it)
}
val s = sb.toString()
创建的唯一临时对象是
StringBuilder
的内部数组;随着内容的不断增长,它会