C ++, 926 bytes
#include<iostream>
#include<string>
#include<math.h>
#define S string
using namespace std;S N(S x,int y){S z="";for(int q=0;q<y;q++){z+=x;}return z;}int main(){int n=0,t=0,g=0,fi=1;cin>>n;int t1[]={0,0,n,0};int t2[]={0,n-2,n-2,1};for(int k=0;k<n+1;k++){if((k>(n-2)/2)&&(k<(n+5)/2)){if(g==0){S d,e;if(!((n+1)%4)){cout<<N("* ",t2[0])<<" *"<<N(" *",t2[0])<<endl<<N("* ",(n+1)/2)<<endl<<N("* ",t2[0])<<"***"<<N(" *",t2[0])<<endl;t2[2]=n-8-(n-11);t1[2]=n-4-(n-11);t1[0]--;t2[3]--;t1[3]-=2;}else{cout<<N("* ",t1[0])<<"***"<<N(" *",t2[0])<<endl<<N("* ",(n+1)/2)<<endl<<N("* ",t1[0])<<"* "<<N(" *",t2[0])<<endl;t2[0]--;t1[2]+=2;t2[2]+=6;t1[3]--;t2[1]-=2;t2[3]-=2;}fi=0;}g=5;}else{t=1-t;int*tR;tR=t?t1:t2;cout<<N("* ",tR[0])<<N(t?"*":" ",tR[2])<<N(" *",tR[3])<<endl;if(fi){if(t){t1[0]+=k==0?0:1;t1[2]-=k==0?2:4;t1[3]++;}else{t2[0]++;t2[2]-=4;t2[3]++;}}else{if(t){t1[0]--;t1[2]+=4;t1[3]--;}else{t2[0]--;t2[2]+=4;t2[3]--;}}}}return 0;}
Isso não é elegante, mas não ocupa muita memória para grandes n. Além disso, existem (quase certamente) cerca de 20 caracteres que podem ser jogados ainda mais, mas eu não aguento mais olhar para ele.
Breve explicação:
Isso divide as linhas nas espirais em dois tipos: aqueles com ****** no meio e aqueles com \ s \ s \ s \ s \ s no meio. Então fica claro que cada linha é composta por vários "*" s, o meio e alguns "*". Descobrir exatamente quantas coisas é simples se você observar o padrão por tempo suficiente. O difícil era imprimir o centro da espiral que eu basicamente codifiquei usando uma condicional. Isso acabou sendo útil porque as linhas *** e \ s \ s \ s alternam sendo ímpares / pares.
Testes:
Entrada: 55
(Eu acho que os grandes parecem mais legais)
Resultado:
**************************************************** *****
*
**************************************************** ***
* * *
* *************************************************** * *
* * * * *
* * ********************************************* * * *
* * * * * * *
* * * ***************************************** * * * *
* * * * * * * * *
* * * * ************************************* * * * * *
* * * * * * * * * * *
* * * * * ********************************* * * * * * *
* * * * * * * * * * * * *
* * * * * * ***************************** * * * * * * * *
* * * * * * * * * * * * * * *
* * * * * * * ************************* * * * * * * * * *
* * * * * * * * * * * * * * * * *
* * * * * * * * ********************* * * * * * * * * * *
* * * * * * * * * * * * * * * * * * *
* * * * * * * * * ***************** * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * ************* * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * ********* * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * ***** * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * {- meu programa adiciona um espaço aqui entre
* * * * * * * * * * * * *** * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * ******* * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * *********** * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * *************** * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * *
* * * * * * * * * ******************* * * * * * * * * * *
* * * * * * * * * * * * * * * * * *
* * * * * * * * *********************** * * * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * ***************************** * * * * * * *
* * * * * * * * * * * * * *
* * * * * * ******************************* * * * * * *
* * * * * * * * * * * *
* * * * * *********************************** * * * * *
* * * * * * * * * *
* * * * *************************************** * * * *
* * * * * * * *
* * * ******************************************* * * *
* * * * * *
* * *********************************************** * *
* * * *
* *************************************************** ** *
* *
**************************************************** *****
Entrada: 3
Resultado:
***
*
* *
***
Nota: Eu não sou um cientista da computação / estudante de CS e não sei como provar que isso usa memória O (log n). Só consigo descobrir o que fazer com base nos links da pergunta. Ficaria muito grato se alguém pudesse confirmar / negar se esta resposta é válida. Minha lógica para a validade dessa resposta é que ela nunca armazena nenhuma variável de tamanho com base em n, exceto na própria entrada. Em vez disso, um loop for que executa n vezes calcula valores inteiros com base em n. Há o mesmo número desses valores, independentemente da entrada.
Nota2: Isso não funciona para n = 1 por causa do meu método de lidar com o meio. Isso seria fácil de corrigir com condicionais; portanto, se alguém tiver alguns caracteres da minha resposta, eu o corrigirei;)
Brinque com ele no ideone.
n
na memória O (1).