2

Imagine you loop n times, and every iteration you create a string of space n with scope only within that iteration (thus it is no longer accessible in the next iteration). I would look and say that I use O(n^2) space because for n iterations, I use n space.

However, logically, if every loop you destroy the previous iteration's string (of n space) and overwrite it with this iteration's string (of n space), throughout the entire loop, you would only be using O(n) space. I am confused about whether to confirm O(n) or O(n^2) space?

Take this example:

s = "hello"
for _ in range(len(s)):
    newString = s[:]
return newString
wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • 1
    Note that Stack Overflow is for questions about the _practice_ of software development. For the _theory_, [cs.se] exists. – Charles Duffy Jan 04 '22 at 01:18
  • 1
    ...if this were a _practical_ question, you would know what practical problem led you to need the analysis, so you would know if taking garbage collection into account was appropriate based on that practical context. (Calculating the smallest possible amount of memory your algorithm can run in? Calculating the largest possible amount of memory your algorithm can allocate if garbage collection is deferred? Those are both valuable things; which one is valuable at a given time is informed by whatever caused you to have a reason to do the analysis at all). – Charles Duffy Jan 04 '22 at 01:19
  • I’m voting to close this question because it belongs on http://cs.stackexchange.com – Chris Jan 04 '22 at 01:22
  • 2
    The questions in the title and body don't match, so I answered the question in the body because it's relatively straightforward, but the question in the title would too broad for SO on its own, so I recommend you change it. For reference: ["If you can imagine an entire book that answers your question, you’re asking too much."](/help/dont-ask) – wjandrea Jan 04 '22 at 01:56

3 Answers3

3

You only measure the maximum amount of space that you need at any one time. Your loop requires O(n) space, because as you say, only one iteration is in scope at any one time.

In garbage-collected languages where you don't explicitly free memory, it's reasonable to trust the implementation of whatever language you're using to ensure that the amount of space you use in reality is at most proportional to the amount you need, so it doesn't affect your space complexity.

It's also reasonable to ignore issues like memory fragmentation for asymptotic space complexity analysis in most cases, even though problems like that can actually change the real-world asymptotic complexity.

Matt Timmermans
  • 53,709
  • 3
  • 46
  • 87
1

Your question does not really have an answer, because dynamic allocation has an unknown cost, both in terms of time and of space !

Algorithm analysis usually assumes that an infinite memory space is available, in a way "globally allocated", and with constant access cost. This model has no concept of dynamic allocation.

You might invent a model that does integrate dynamic allocation, with well-selected time and space costs. If allocation is assumed "on the stack", constant time and O(n) space (counted just once as memory is released upon return) is reasonable. For "heap" allocation, you are in the mist.

-2

In theory, worst-case space usage is O(n^2) as you mentioned: n copies of n-length strings.

But in practice, it'll be lower due to implementation details like garbage collection (i.e. reference counting) and string interning (i.e. s[:] can return the same object as s). For example in CPython 3.8.12:

>>> s = 'hello'
>>> s is s[:]
True
wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • I'm not sure why this is being downvoted. Could anyone let me know? I'm not super familiar with under-the-hood stuff and algorithm theory, so I easily could have gotten something wrong. I'd love to learn. – wjandrea Jan 04 '22 at 21:16