_Gia_Cat_Luong_
Senior Member
Hông, cách của tui cùi bắp hơn, mặc dù cũng là greedy, ý tưởng chính:Sau khi làm bài https://leetcode.com/problems/queue-reconstruction-by-height/
Mình thấy khá là hay. Nên sẽ chia sẻ lại cách mình giải bài này cho mọi người.
Input của bài này có dạng như sau:
[[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
Đây là một list chứa các list con, mỗi list con sẽ chứa 2 phần tử: mình tạm gọi là a,b.
Yêu cầu của bài này là sắp xếp lại list trên sao cho tại mỗi list con bất kỳ, thì số list con đứng trước nó có giá trị a lớn hơn hoặc bằng giá trị a của nó đúng bằng b. Nghe chỗ này hơi rối đúng k?.
Ví dụ với input là list bên trên, thì output như dưới đây được coi lại hợp lệ:
[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
Trước [5,0] không có list nào có phần tử đầu lớn hơn 5.
Trước [7,0] không có list nào có phần tử đầu lớn hơn 7.
Trước [5,2] có đúng 2 list có phần đầu lớn hơn 5.
Trước [6,1] có đúng 1 list có phần đầu lớn hơn 6.
...
Đến đây hi vọng mọi người đã hiểu được yêu cầu của bài toán.
Bài này mình sẽ giải bằng greedy. Nếu ai chưa biết greedy là gì thì có thể tự tìm hiểu hoặc tìm đọc những post của @_Gia_Cat_Luong_ có chia sẻ rồi.
Cách giải của mình trong bài này dựa trên 2 nhận xét quan trọng như sau.
- Giả sử ta đang có một list hợp lệ: l = [[a1,b1],[a2,b2],...,[an,bn]] và một list con [ax,bx] mà ax nhỏ hơn tất cả các phần tử a1,...,an.
Thì khi ta chèn [ax,bx] vào một vị trí bất kỳ trong l thì luôn cho ra một list hợp lệ.
VD: [[7,0]] ,[6,1],[9,0],[8,1]] đang hợp lệ, chèn [5,0] vào bất kỳ vị trí nào thì vẫn cho ra một list hợp lệ.- Đầu ra của bài toán sẽ luôn có dạng như sau: [[a,b1],...,[a,b2],...,[a,b3]]. mà b1,b2,b3 là dãy tăng dần. Nếu không thì sẽ vi phạm yêu cầu bài toán ngay.
Sau khi nhìn ra được 2 điểm này thì mình bắt đầu xây dựng ra solution. Đễ dễ hơn thì mình sẽ đi thẳng vào ví dụ cụ thể.
Còn đây là code C++ của mình.
- Input:
[[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]- Sort ra 1 list như sau:
[[7,0],[7,1],[6,1],[5,0],[5,2],[4,4]]
(a giảm dần, khi a bằng nhau thì b lại tăng dần)- Nếu chỉ dừng lại ở đây thì rõ ràng chưa thỏa mãn điều kiện của bài toán.
Do đó mình sẽ phải duyệt lại cái list trên.- Do list đã được sort nên một list con nằm ở vị trí idx thì sẽ luôn có có idx phần tử có a lớn hơn nó.
Do đó ta dựa vào idx và giá trị của b để xác định được một list con có cần vi phạm hay không, và nếu nó vi phạm thì sẽ biết được vị trí mới của nó.
Vd: [[7,0],[7,1],[6,1],[5,0],[5,2],[4,4]]
idx = 0, duyệt [7,0]: idx <= 0 ? -> true -> output: [[7,0]]
idx = 1, duyệt [7,1]: idx <= 1? -> true -> output: [[7,0],[7,1]]
idx = 2, duyệt [6,1]: idx <= 1? -> false -> chèn vào vị trí 1-> output: [[7,0],[6,1],[7,1]]
idx = 3, duyệt [5,0]: idx <= 0? -> false -> chèn vào vị trí 0-> output: [[5,0],[7,0],[6,1],[7,1]]
idx = 4, duyệt [5,2]: idx <= 2? -> false -> chèn vào vị trí 2-> output: [[5,0],[7,0],[5,2],[6,1],[7,1]]
idx = 5, duyệt [4,4]: idx <= 4? -> false -> chèn vào vị trí 4-> output: [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]- Đến đây là đã hoàn tất.
C++:class Solution { public: vector<vector<int>> reconstructQueue(vector<vector<int>>& people) { sort(people.begin(), people.end(), [] (auto a, auto b) { return a[0] == b[0] ? a[1] < b[1] : a[0] > b[0]; }); list<vector<int>> list_people; for(int i = 0; i < people.size(); i++){ if (i > people[i][1]){ auto it = list_people.begin(); std::advance(it, people[i][1]); list_people.insert(it, move(people[i])); } else{ list_people.push_back(move(people[i])); } } people.clear(); people.insert(people.begin(), list_people.begin(), list_people.end()); return people; } };
@_Gia_Cat_Luong_ : cách của thím có giống như t k?
- Mình sẽ tìm cách list những thằng này theo thứ tự hợp lý để append vào mảng output
- Bước đầu tiên là tìm danh sách những thằng phù hợp để insert vào vị trí tiếp theo. Ví dụ vị trí đầu tiên thì lấy ra những thằng có tallerCount = 0. Vị trí số 1 thì lấy ra những thằng có tallerCount = 1 và thấp hơn hoặc bằng thằng trước hoặc tallerCount = 0 và cao hơn thằng trước. Khá brute-force. Bước này O(nlogn)
- Sau đó insert thằng có chiều cao thấp nhất trong list lọc được ở trên vào mảng output (greedy)
- Lặp lại đến khi nào insert hết vào mảng output là xong
=> Độ phức tạp O(nlogn), faster than 20% thôi, at least it works
. Cách của ông là chuẩn rồi, sau tui vào discuss cũng thấy nhiều người làm như vậy. Good job mai fen.
Python:
from sortedcontainers import SortedList
class Solution:
def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
n = len(people)
people.sort(key=lambda pp: pp[0])
queuedIndex = set()
queuedHeights = SortedList()
queue = []
while len(queue) < n:
ppIndex = self.findSuitablePeopleIndex(people, queuedIndex, queuedHeights)
if ppIndex < 0:
raise Error('Queue is not reconstructable; current queue: ' + queue)
queue.append(people[ppIndex])
queuedIndex.add(ppIndex)
queuedHeights.add(people[ppIndex][0])
return queue
def findSuitablePeopleIndex(self, people, queuedIndex, queuedHeights):
for i, pp in enumerate(people):
if i in queuedIndex or pp[1] > len(queuedIndex):
continue
heightIndex = queuedHeights.bisect_left(pp[0])
if len(queuedHeights) - heightIndex == pp[1]:
return i
return None
Rất vui vì ông đã chia sẻ nha, có người share chung mỗi ngày thấy cũng vui chứ làm một mình mãi cũng hơi oải
.

(