Nhờ góp ý thuật toán: Dịch xoay vòng k lần các phần tử trong mảng 1 chiều
Xin chào mọi người.
Mình có 1 bài tập như sau: Cho người dùng nhập vào 1 mảng số nguyên. Sau đó dịch trái hoặc phải xoay vòng k lần (với k là số do người dùng nhập vào, t là ký tự để phân biệt dịch trái hoặc phải). Xuất mảng sau khi dịch.
VD: Mảng ban đầu là 1 2 3 4 5
Dịch trái xoay vòng 1 lần => 2 3 4 5 1
Dịch trái xoay vòng 2 lần => 3 4 5 1 2
Dịch trái xoay vòng 3 lần => 4 5 1 2 3
Dịch trái xoay vòng 4 lần => 5 1 2 3 4
Dịch trái xoay vòng 5 lần => 1 2 3 4 5
Dịch trái xoay vòng 6 lần => trở về giống như dịch trái xoay vòng 1 lần
Dịch trái xoay vòng 7 lần => trở về giống như dịch trái xoay vòng 2 lần
Source code:
void DichXoayVong(int a[], int n, int k, char t) // char t dùng để xác định dịch xoay vòng bên trái hay phải
{ // k là số lần dịch xoay vòng
while (k >= 5) // Nếu k >= 5 thì trừ k cho 5 vì bản chất, dịch xoay vòng 6 giống như dịch xoay vòng 1, dịch 7 giống dịch 2, ...
k -= 5;
for (int x = 0; x < k; x++)
{
if (t == 't') // t là trái (t)
{
int bienphu = a[0];
int Solan = 0;
for (int i = 0; i < n; i++)
{
if (Solan == n)
break;
if (i == n - 1)
a[i] = bienphu;
else
a[i] = a[i + 1];
Solan++;
}
}
else // ngược lại là phải (p)
{
int bienphu = a[n - 1];
int Solan = 0;
for (int i = n - 1; i >= 0; i--)
{
if (Solan == n)
break;
if (i == 0)
a[i] = bienphu;
else
a[i] = a[i - 1];
Solan++;
}
}
}
}
Mình xin nhờ mọi ngưới góp ý và cải thiện thuật toán của mình với bài toán trên cho ngắn gọn - tối ưu hơn (vì code của mình trong có vẻ dài dòng và lưa thưa)
Xin cảm ơn mọi người nhiều !
Bạn xem cách của mình thử:
Gọi rev(A) là reverse của mảng A. Ví dụ k = 3:
rev (A) = 5 4 3 2 1
rev (A [ 0 … (n - 1- k) ]) = 4 5 3 2 1
rev (A [ (n - k) … (n - 1) ] = 4 5 1 2 3
Gọi n là số lượng phần tử của arr, k là số lần xoay. Đầu tiên chúng ta phải chia lấy dư k với n, vì sao?
Giả sử k = 6 và n = 5, k % n == 1 -> chỉ cần xoay vòng 1 lần -> hợp lý. Sau khi mod xong thì k chắc chắn sẽ nhỏ hơn n, dễ dàng tính toán hơn.
k = k % n
Tiếp theo là thực hiện xoay, tùy theo giá trị k mà xoay bấy nhiêu lần thôi:
P.S. Mình quên đọc tới phần dịch phải, nhưng cũng tương tự dịch trái thôi. Bạn nên bỏ mấy câu comment đi, đặt tên biến rõ nghĩa ra chứ đừng có k, n, t này nọ. Chỉ đặt tên biến 1 ký tự khi viết loop, còn lại nên viết đầy đủ, cái tên biến phải giải thích được vai trò của nó chứ không phải dùng comment để giải thích.
Mấy bài dạng này có nhiều đề rất thú vị, ví dụ như bài này:
codereview.stackexchange.com
100 gunmen in a circle kill next person
This post was flagged by the community and is temporarily hidden.
nhưng cấp phát động cho mảng mới thì khá chậm
This post was flagged by the community and is temporarily hidden.
Perfect
Mục đích mình để mấy comments là để cho mấy người đọc / xem code sẽ dễ hiểu hoặc hiểu nhanh hơn, vì nó có phần hơi “dài” nên sợ có người đọc rồi nản.
Chứ khi code, mình không bao giờ để comments đâu bạn !
OK, làm biếng quá !!!
Thanks everyone
Code update Nhờ mọi người góp ý và cải thiện tiếp !
Còn một cách nữa, đó là chỉ xoay một lần duy nhất tại vị trí k sau khi lấy k mod n, cần chia trường hợp khi k và n chẵn hoặc lẻ. Mình đang đi du lịch nên không có máy test… =))
Cách này thì hơi lằng nhằng với các bác tí nhưng được cái độ phức tạp nhỏ.
Bài này kết hợp đồng dư với nhân đôi mảng =)))
Xoay mảng có thể thực hiện trong Theta(n) và O(1) mem.
Chắc thế :V