In một vòng xoắn ascii trong bộ nhớ O (log n)


13

Bạn có thể viết chương trình hoặc hàm nhận số nguyên dương n , số lẻ, trong đó n >= 3, dưới dạng đối số hàm, đối số dòng lệnh hoặc trên STDIN (hoặc tương đương với hệ thống của bạn) và in ra STDOUT (hoặc tương đương hệ thống) theo hình xoắn ốc ASCII quay vào trong theo chiều kim đồng hồ, nơi cạnh trênn dài chính xác là các ký tự. Cạnh phải đầu tiên phải là n+1ký tự dài, rõ ràng. Ví dụ,

Đầu vào:

11

Đầu ra:

***********
          *
********* *
*       * *
* ***** * *
* *   * * *
* * * * * *
* * *** * *
* *     * *
* ******* *
*         *
***********

Các sản phẩm khai thác:

  • Chương trình của bạn phải sử dụng không quá O(log n)bộ nhớ .
  • Chương trình của bạn chỉ có thể in các ký tự *(ASCII 42), (ASCII 32), <CR>(ASCII 13) và <LF>(ASCII 10).
  • Chương trình của bạn phải in chuỗi, không trả lại từ hàm.
  • Hạn chế Big-O chỉ có trên bộ nhớ , không có hạn chế về thời gian chạy .
  • Một dòng mới theo dõi là tùy chọn.
  • Nếu ngôn ngữ của bạn không hỗ trợ các loại số nguyên lớn, bạn không phải hỗ trợ cao hơn những gì nó hỗ trợ, nhưng bạn không thể sử dụng điều này như một mẹo để nói "oh, tốt, tôi không phải hỗ trợ trên X vì vậy tôi chỉ có thể tạo ra một mảng lớn kích thước tối đa mỗi lần "

Sơ hở tiêu chuẩn bị cấm, như thường lệ.


2
Tôi không tin điều này là có thể. Người ta không thể lưu trữ đầu vào ntrong bộ nhớ O (1).
xnor

@xnor "O (1) tạo thành mức sử dụng bộ nhớ không đổi. Vì vậy, lượng đầu vào không đáng kể" - Nếu đầu vào n khớp với số nguyên, thì tôi chắc chắn rằng nó có thể được mã hóa thành mức sử dụng bộ nhớ không đổi.
André

1
Lưu trữ đầu vào nmất log nbit. Khi nlớn hơn, không gian cần thiết để lưu trữ nó. Có lẽ bạn đang nói để làm điều này với một số lượng hạn chế?
xnor

Hoặc, thay vào đó, có một giới hạn về n?
Sp3000

Tôi nghĩ rằng anh ấy nói rằng bạn không thể lưu trữ toàn bộ đầu ra cùng một lúc, sau đó chỉ cần in tất cả cùng một lúc vì điều đó sẽ lớn hơn. Bạn có thể phải in đệ quy nó.
Jacob

Câu trả lời:


9

C, 125 121 byte

Phiên bản chơi gôn Điều này không có biến k. Biến kđược sử dụng trong phiên bản không có mục đích chỉ để hỗ trợ khả năng đọc. Ngoài ra các forđiều kiện vòng lặp được sắp xếp lại và một bộ {}loại bỏ không cần thiết . Một bộ khác {}có thể được loại bỏ bằng cách di chuyển puts("")bên trong dấu ngoặc của jvòng lặp ở vị trí khởi tạo, nhưng điều này có nghĩa là một dòng mới ở đầu ra, vì vậy tôi đã không thực hiện nó.

f(n){int i,j;n/=2;for(i=-n-2;i++-n-1;){if(i){for(j=-n-1;j++-n;)putchar(32+10*(n+(j*j<i*i?i:j+(i!=j|i>0))&1));puts("");}}}

In một hình nrộng bằng hình n+1xoắn ốc cao như ví dụ.

Giải trình

Về cơ bản tôi giảm một nửa giá trị của n(làm tròn xuống) và chạy hai vòng: một vòng bên ngoài itừ -n/2-1để n/2+1in các hàng ( i=0đang bị đàn áp vì vậy chúng tôi có được n+1hàng) và một bên jtừ ( -n/2để n/2Chúng tôi sử dụng để in các ký tự.) expression & 1Để in sọc và điều kiện j*j<i*iđể quyết định nên in các sọc dọc hay ngang (dọc ở các cạnh có cường độ tuyệt đối lớn ihơn và ngang ở trên cùng và dưới cùng.) +nCần phải điều chỉnh để giúp chấm dứt chính xác tùy thuộc vào n/2số lẻ hay cũng.

kthường là 1 và cung cấp một điều chỉnh cho thực tế là các giá trị tuyệt đối của iphạm vi từ 1 đến n/2+1trong khi các giá trị tuyệt đối của jphạm vi từ 0 đến n/2. Nếu kluôn luôn là 1, chúng ta sẽ có các hình chữ nhật đồng tâm, nhưng nó bị đảo ngược về 0 khi i==j&i<=0một hàng các ô chéo được đảo ngược, tạo ra hình xoắn ốc.

vô dụng trong chương trình thử nghiệm

f(n){
  int i,j,k;
  n/=2;
  for(i=-n-1;i<=n+1;i++){
    if(i){
       for(j=-n;j<=n;j++){
           k=i!=j|i>0;
           putchar(32+10*(n+(j*j<i*i?i:k+j)&1));
         }
       puts("");
     }
  }
} 

int m;
main(){
  scanf("%d",&m);
  f(m);
}

Đầu ra

11
***********
          *
********* *
*       * *
* ***** * *
* *   * * *
* * * * * *
* * *** * *
* *     * *
* ******* *
*         *
***********

9
*********
        *
******* *
*     * *
* *** * *
* * * * *
* *   * *
* ***** *
*       *
*********

3
***
  *
* *
***

1
*
*

Đánh bại tôi một chút ... +1 này thật là điên rồ!
sudo rm -rf chém


7

C, 118 byte

m,p,x,y,d;f(n){for(m=n++/2;p<n*n;x=p%n-m,y=p++/n-m,d=y==x+1&x<0,y-=y>0,d+=x*x>y*y?x:y,putchar(x>m?10:(d+m)%2?32:42));}

Mã trước khi chơi golf cuối cùng:

#include <stdio.h>

int m, p, x, y, d;

int f(int n) {
    for (m = n++ / 2; p < n * n; ) {
        x = p % n - m;
        y = p++ / n - m;
        d = y == x + 1 && x < 0;
        y -= y > 0;
        d += x * x > y * y ? x : y;
        if (x > m) {
            putchar(10);
        } else if ((d + m) % 2) {
            putchar(32);
        } else {
            putchar(42);
        }
    }

    return 0;
}

Quan sát chính là mô hình gần như là một loạt các hình vuông đồng tâm. Với một vài nếp nhăn nhẹ:

  • Kích thước y lớn hơn kích thước x. Điều này được sửa bằng cách trừ 1 từ y cho nửa dưới, về cơ bản lặp lại hàng giữa.
  • Để biến các hình chữ nhật thành một hình xoắn ốc, các pixel dọc theo y = x + 1đường chéo cần phải được đảo ngược lên đến giữa hình.

Đối với phần còn lại, mã chỉ đơn giản là lặp qua tất cả các vị trí, tính toán khoảng cách Ch Quashev từ tâm cho mỗi vị trí và phát ra một trong hai ký tự tùy thuộc vào khoảng cách là chẵn hoặc lẻ. Và phát ra một dòng mới cho vị trí cuối cùng của mỗi dòng.

Vì chỉ có một vài biến vô hướng và các ký tự được phát ra từng cái một, nên việc sử dụng bộ nhớ rõ ràng là không đổi.


Câu trả lời tuyệt vời, nhưng khi bạn không khởi tạo, ptôi nghĩ rằng bạn đã phạm lỗi với meta.codegolf.stackexchange.com/q/4939/15599 . Tôi cũng không chắc chắn về việc khai báo các biến toàn cục khi gửi hàm. Rõ ràng câu trả lời của tôi sẽ ngắn hơn 4 byte nếu tôi làm điều này. Tôi đã bắt đầu một bài đăng meta meta.codegolf.stackexchange.com/q/5532/15599
Level River St

Vâng, tôi nghĩ rằng có lẽ tôi nên khởi tạo p.
Reto Koradi 04/07/2015

3

C ++, 926 byte

#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;}

Điều này không thanh lịch, nhưng nó không chiếm nhiều bộ nhớ cho n lớn. Hơn nữa, có (gần như chắc chắn) khoảng 20 nhân vật có thể được đánh gôn thêm, nhưng tôi không thể đứng nhìn nó nữa.

Giải thích ngắn gọn:

Thao tác này sẽ chia các dòng trong hình xoắn ốc thành hai loại: loại có ****** ở giữa và loại có \ s \ s \ s \ s \ s ở giữa. Sau đó, rõ ràng là mỗi dòng bao gồm một số "*", giữa và một số "*". Chỉ ra chính xác có bao nhiêu điều là đơn giản nếu bạn nhìn vào mẫu đủ lâu. Điều khó khăn là in trung tâm của hình xoắn ốc mà về cơ bản tôi đã mã hóa cứng bằng cách sử dụng một điều kiện. Điều này cuối cùng có ích vì chuyển đổi dòng *** và \ s \ s \ s là số lẻ / thậm chí ở đó.

Các xét nghiệm:

Đầu vào: 55 (Tôi nghĩ rằng những cái lớn trông ngầu nhất)

Đầu ra:

****** / TÌM KIẾM *****
                                                      *
****** / TÌM KIẾM *** *
* * *
* ****** / TÌM KIẾM * *
* * * * *
* * ****** / TÌM HIỂU * * * * * * * * * * * * * *
* * * * * * *
* * * ****** / TÌM HIỂU * * * * * * * * * * * * * * * *
* * * * * * * * * *
* * * * ****** / TÌM HIỂU * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * *
* * * * * ****** / TÌM HIỂU * * * * * * * *
* * * * * * * * * * * * * *
* * * * * * ****** / TÌM HIỂU * * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * ****** / TÌM HIỂU * * * * * * * * *
* * * * * * * * * * * * * * * * *
* * * * * * * * ****** / 4/8/8/8 * * * * * * * * * * *
Th * *
* * * * * * * * * ****** / 4/4 * * * * * * * * * * * *
Th * * * * * * * * * * * cái *
* * * * * * * * * * ****** / 4/4 * * * * * * * * * * * * *
B * *
* * * * * * * * * * * ****** * * * * * * * * * * * * * * * *
Sẽ có * * * * *
| * * * * * * * * * * * * ***** * * * * * * * * * * * * * * * *
| * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * {- chương trình của tôi thêm một khoảng trắng ở đây btw
| * * * * * * * * * * * * * *** * * * * * * * * * * * * * * * *
| * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * ****** * * * * * * * * * * * * * * *
Sẽ có * * * *
* * * * * * * * * * * ****** / 4 * * * * * * * * * * * * *
Th * *
* * * * * * * * * * ****** / 4/4 * * * * * * * * * * * * *
Thỉnh thoảng
* * * * * * * * * ****** / TÌM HIỂU * * * * * * * * * *
Th * *
* * * * * * * * ****** / TÌM HIỂU * * * * * * * * *
* * * * * * * * * * * * * * * * *
* * * * * * * ****** / TÌM HIỂU * * * * * * * *
* * * * * * * * * * * * * * *
* * * * * * ****** / TÌM HIỂU * * * * * * *
* * * * * * * * * * * * *
* * * * * ****** / TÌM HIỂU * * * * * * * * * * * * * *
* * * * * * * * * * *
* * * * ****** / TÌM HIỂU * * * * * * * * * * * * * * * * * *
* * * * * * * * *
* * * ****** / TÌM HIỂU * * * * * * * * * * * * * * * * * * *
* * * * * *
* * ****** / TÌM HIỂU * *
* * * *
* ****** / TÌM KIẾM ** *
* *
****** / TÌM KIẾM *****

Đầu vào: 3

Đầu ra:

***
  *
* * 
***

Lưu ý: Tôi không phải là nhà khoa học máy tính / sinh viên CS và tôi không biết làm thế nào để chứng minh rằng điều này sử dụng bộ nhớ O (log n). Tôi chỉ có thể tìm ra những việc cần làm dựa trên các liên kết trong câu hỏi. Tôi sẽ biết ơn nếu ai đó có thể xác nhận / từ chối nếu câu trả lời này là hợp lệ. Logic của tôi cho tính hợp lệ của câu trả lời này là nó không bao giờ lưu trữ bất kỳ biến kích thước nào dựa trên n ngoại trừ chính đầu vào. Thay vào đó, một vòng lặp for chạy n lần tính các giá trị nguyên dựa trên n. Có cùng số lượng các giá trị đó bất kể đầu vào.

Lưu ý2: Điều này không hoạt động với n = 1 vì phương pháp xử lý giữa của tôi. Điều này sẽ dễ dàng sửa chữa với các điều kiện, vì vậy nếu có ai trong một vài ký tự trong câu trả lời của tôi, tôi sẽ sửa nó;)

Chơi với nó trên ideone.


Tôi tin rằng nó hợp lệ, mặc dù mã C ++ nhiều trên một dòng này là loại phải đọc. ;) Sự am hiểu của bạn đa đung đăn. Bạn không thể sử dụng bất kỳ bộ nhớ với kích thước phụ thuộc vào n. Một ví dụ điển hình không đáp ứng yêu cầu sẽ là một loại chuỗi / bộ đệm / mảng chứa một dòng đầu ra hoàn chỉnh.
Reto Koradi

Vì câu trả lời duy nhất này, tôi đã điều chỉnh câu hỏi để không yêu cầu xử lý n=1, vì tôi không coi vỏ bọc đặc biệt đó thú vị như vậy.
durron597

3

Haskell, 151 byte

(#)=mod
f n=[[if y<= -(abs$x+1)||y>abs x then r$y#2/=n#2 else r$x#2==n#2|x<-[-n..n]]|y<-[-n-1..n+1],y/=0]
r b|b='*'|1<2=' '
p=putStr.unlines.f.(`div`2)

Ví dụ sử dụng:

*Main> p 9
*********
        *
******* *
*     * *
* *** * *
* * * * *
* *   * *
* ***** *
*       *
*********

*Main> p 11
***********
          *
********* *
*       * *
* ***** * *
* *   * * *
* * * * * *
* * *** * *
* *     * *
* ******* *
*         *
***********

Nhờ sự lười biếng của Haskell, nó chạy trong bộ nhớ không đổi. Nó sử dụng cách tiếp cận rõ ràng, tức là lặp qua yxvà lựa chọn giữa *, tùy thuộc vào

  • nếu vị trí hiện tại ở trên hoặc dưới một đường chéo
  • xtôn trọng. ylà chẵn hoặc lẻ
  • n/2 là chẵn hoặc lẻ

2

Lisp thường gặp - 346

(lambda(n &aux(d 0))(tagbody $ #6=(#7=dotimes(i n)#4=(princ"*"))#2=(#7#(i d)#5=(princ" ")#4#)#3=(terpri)#1=(#7#(i d)#4##5#)(when(> n 0)(#7#(i(1- n))#5#)#4#)#2##3#(when(> n 3)#1##4##4#(incf d)(decf n 4)(go $))(go /)@(decf d)(incf n 4)(when(> n 3)#2##5##4##3#)/ #1#(when(> n 0)#4#)(when(> n 1)(#7#(i(- n 2))#5#)#4#)#2##3##1##6#(when(> d 0)(go @))))

Giải pháp lặp với việc sử dụng bộ nhớ liên tục. Ở trên làm cho việc sử dụng nặng nề #n=#n#các biến độc giả. Mặc dù có nhiều cách tiếp cận trực tiếp hơn, ở đây tôi đã bắt đầu với một hàm đệ quy và sửa đổi nó để mô phỏng đệ quy vớigoto câu lệnh: điều này có lẽ không thể đọc được.

Đầu ra cho tất cả các giá trị đầu vào từ 0 đến 59 .

Phiên bản đệ quy gốc, với thông tin gỡ lỗi

(lưu ý: terpricó nghĩa là newline)

(defun spiral (n &optional (d 0) )
  (flet ((prefix ()
           (format t "~4d~4d | " n d)
           (dotimes (i d)
             (princ "a ")))
         (postfix ()
           (dotimes (i d)
             (princ " b"))))
    (when (= d 0) (prefix))
    (dotimes (i n) (princ "c"))
    (postfix)
    (terpri)

    (prefix)
    (when (> n 0)
      (dotimes (i (1- n)) (princ " "))
      (princ "d"))
    (postfix)
    (terpri)

    (when (> n 3)
      (prefix)
      (princ "**")
      (spiral (- n 4) (1+ d))
      (postfix)
      (princ " f")
      (terpri))

    (prefix)
    (when (> n 0)
      (princ "g"))

    (when (> n 1)
      (dotimes (i (- n 2)) (princ " "))
      (princ "h"))
    (postfix)
    (terpri)

    (prefix)
    (dotimes (i n) (princ "i"))
    ))

Ví dụ:

(spiral 8)

   8   0 | cccccccc
   8   0 |        d
   8   0 | **cccc b
   4   1 | a    d b
   4   1 | a ** b b
   0   2 | a a  b b
   0   2 | a a  b b
   0   2 | a a  b f
   4   1 | a g  h b
   4   1 | a iiii f
   8   0 | g      h
   8   0 | iiiiiiii

Xem thêm dán này với tất cả các kết quả từ 0 đến 59 (không giống như trên, cái này dài dòng hơn).

Phiên bản lặp, với thông tin gỡ lỗi

(defun spiral (n &aux (d 0) )
  (flet ((prefix ()
           (format t "~4d~4d | " n d)
           (dotimes (i d)
             (princ "a ")))
         (postfix ()
           (dotimes (i d)
             (princ " b"))))
    (tagbody
     step-in
       (when (= d 0) (prefix))
       (dotimes (i n) (princ "c"))
       (postfix)
       (terpri)

       (prefix)
       (when (> n 0)
         (dotimes (i (1- n)) (princ " "))
         (princ "d"))
       (postfix)
       (terpri)

       (when (> n 3)
         (prefix)
         (princ "**")

         (incf d)
         (decf n 4)
         (go step-in))

       (go skip)

     step-out
       (decf d)
       (incf n 4)
       (when (> n 3)
         (postfix)
         (princ " f")
         (terpri))

     skip
       (prefix)
       (when (> n 0)
         (princ "g"))

       (when (> n 1)
         (dotimes (i (- n 2)) (princ " "))
         (princ "h"))
       (postfix)
       (terpri)

       (prefix)
       (dotimes (i n) (princ "i"))
       (when(> d 0)(go step-out)))))

Bạn có thể giải thích làm thế nào điều này đáp ứng hạn chế bộ nhớ? Tôi chỉ thấy một điểm đệ quy, điều này là tốt, nhưng bạn có thể chỉ đi vào chi tiết hơn một chút không?
durron597

@ durron597 Vâng, tôi đang làm việc này. Đây hiện là O (n) vì chúng ta gọi hàm theo cách đệ quy một số thời gian tỷ lệ thuận nvà ngăn xếp cuộc gọi phát triển tương ứng, nhưng trong trường hợp này, chúng ta có thể mô phỏng đệ quy với hai vòng: một vòng ngiảm và dtăng (cho đến khi n <= 3 ) và một số khác dgiảm dần về không. Tôi không có nhiều thời gian để làm việc này ngay bây giờ, nhưng tôi sẽ cố gắng cập nhật câu trả lời cho phù hợp. Btw, có nhiều cách trực tiếp hơn để in xoắn ốc, nhưng thật vui khi cố gắng định nghĩa nó một cách đệ quy.
coredump

2

CJam, 72 byte

li_2/:M;)__*{1$mdM-\M-_2$)=2$0<*@_*@_0>-_*e>mQ_M>2*@@+M+2%+'#S+N+N+=o}/;

Đây là chuyển đổi khá trực tiếp của giải pháp C của tôi sang CJam. Không ngắn như bạn thường mong đợi từ một giải pháp CJam, nhưng giải pháp này thực sự bị hạn chế bộ nhớ. Những lợi ích chung của việc xây dựng kết quả trên ngăn xếp được tự động kết xuất vào cuối và sử dụng các hoạt động danh sách / chuỗi ưa thích, tất cả đều đi ra ngoài cửa sổ. Điều này tạo và xuất ra giải pháp một ký tự tại một thời điểm. Ngăn xếp chỉ chứa một vài số nguyên trong thời gian chạy và trống ở cuối.

Mặc dù nó không phải là một màn hình tuyệt vời khi sử dụng ngôn ngữ chơi gôn, nó vẫn ngắn hơn đáng kể so với mã C chỉ vì ký hiệu nhỏ gọn hơn.

Giải trình:

li    Get input n.
_2/   Calculate n/2.
:M;   Store it in variable M
)__*  Calculate (n+1)*(n+1), which is the total number of output characters.
      Also keep a copy of n+1 on the stack.
{     Start loop over output character positions.
  1$md  Calculate divmod of position with n+1. This gives y and x of position.
  M-    Subtract M from x.
  \M-   Subtract M from y.
  _     Copy y.
  2$)   Calculate x+1.
  =     Check if y == x+1
  2$0<  Check if x < 0.
  *     Multiply the two check results. This is the result of the flip
        condition for the top-left diagonal to turn the rectangles into a spiral.
  @_*   Calculate x*x.
  @_    Get y to top of stack, and copy it.
  0>-   Subtract 1 from y if it is in the bottom half.
  _*    Calculate y*y.
  e>    Take maximum of x*x and y*y...
  mQ    ... and calculate the square root. This is the absolute value of the
        larger of the two.
  _M>   Check if the value is greater M, which means that this is the
        position of a line end.
  2*    Multiply by 2 so that we can add another condition to it later.
  @     Get result of diagonal flip condition to the stack top.
  @     Get max(x,y) to the top.
  +M+   Add the two, and add M to the whole thing. This value being even/odd
        determines if the output is a # or a space.
  2%    Check if value is odd.
  +     Add to line end condition to get a single ternary condition result.
  '#S+N+N+
        Build string "# \n\n".
  =     Use the condition result to pick the output character out of the string.
  o     Output the character.
}/    End loop over output characters.
;     Pop n+1 value off stack, to leave it empty.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.