thảo luận Leetcode mỗi ngày

  • Người tạo chủ đề Người tạo chủ đề _Gia_Cat_Luong_
  • Ngày bắt đầu Ngày bắt đầu
Trạng thái
Không mở để trả lời thêm.
Câu 4 hôm nay ntn vậy ae? Làm 3 câu đầu chưa đến 30p, chưa kịp đọc đề câu 4 thì bị con vợ kéo đi, cay vkl
câu 4 mãi còn 20p cuối ms nghĩ ra union find, kiểu trong 1 cây mà tất cả các node có val <= m chẳng hạn thì số path mà startNode và endNode bằng m trong cây đó là cnt * (cnt - 1) / 2 (cnt là số node có val = m trong cây)
 
Java:
class MyCircularQueue {
    private Node head;
    private Node tail;
    private int size;
    private int LIMIT;
    public MyCircularQueue()
    {
        head = null;
        tail = null;
        size = 0;
        LIMIT = 0;
    }
    public MyCircularQueue(int k) {
        head = null;
        tail = null;
        size = 0;
        LIMIT = k;
    }
    
    public boolean enQueue(int value) {
        if(size >= LIMIT)
        {
            return false;
        }
        Node newNode = new Node(value, head);
        if(head == null)
        {
            head =  newNode;
            tail = newNode;
            
        }
        else
        {
            tail.next = newNode;
            tail = tail.next;
        }
        size++;
        return true;
    }
    
    public boolean deQueue() {
        if(size == 0)
        {
            return false;
        }
        if(size == 1)
        {
            head = null;
            tail = null;
            size--;
            return true;
        }
        head = head.next;
        tail.next = head;
        size--;
        return true;
    }
    
    public int Front() {
        return (size != 0) ? head.val : -1;
    }
    
    public int Rear() {
        return (size != 0) ? tail.val : -1;
    }
    
    public boolean isEmpty() {
        return size == 0;
    }
    
    public boolean isFull() {
        return size >= LIMIT;
    }
}

class Node
{
    public int val;
    public Node next;
    public Node()
    {
        val = 0;
        next = null;
    }
    public Node(int v)
    {
        val = v;
        next = null;
    }
    public Node(int v, Node n)
    {
        val = v;
        next = n;
    }
}

/**
 * Your MyCircularQueue object will be instantiated and called as such:
 * MyCircularQueue obj = new MyCircularQueue(k);
 * boolean param_1 = obj.enQueue(value);
 * boolean param_2 = obj.deQueue();
 * int param_3 = obj.Front();
 * int param_4 = obj.Rear();
 * boolean param_5 = obj.isEmpty();
 * boolean param_6 = obj.isFull();
 */
 
NdcH1rq.png
nay chắc mỗi tôi vẫn try hard daily leetcode
O5Et4Xf.png
 
câu 4 mãi còn 20p cuối ms nghĩ ra union find, kiểu trong 1 cây mà tất cả các node có val <= m chẳng hạn thì số path mà startNode và endNode bằng m trong cây đó là cnt * (cnt - 1) / 2 (cnt là số node có val = m trong cây)

Cũng nghĩ ra cách kiểu kiểu vậy nhưng code phức tạp quá làm không kịp.
Riêng việc phân nhóm các node thuộc một khoảng thành từng cây riêng đã không dễ rồi.
 
Dạo này lười làm leetcode nên hnay contest ngáo vc. Xong c3 còn có 10p, ngồi f5 xem c4 có nhiều ng làm đc ko :D
Cũng may contest hnay khó :shame:
 
OG0lsXv.png
hình như đấy là kiểu hash map mà đúng không?

Không, array bình thường thôi.
Nhưng vì queue bị giới hạn kích thước nên có thể alloc trước max phần tử. Dùng 2 index dành cho first, last. Enqueue thì tăng last lên, dequeue thì tăng first. Access vào array thì lấy modulo của maxSize trước.

Làm như này thì không cần phải move data, tất cả thao tác đều O(1).
 
Bài ko có gì mà ngồi viết cái GenServer hết mẹ cả buổi
KV0XGIA.gif


Mã:
defmodule Queue do
  use GenServer
  defstruct container: nil, capacity: nil, count: nil

  def start(k) do
    GenServer.start(__MODULE__, k, name: __MODULE__)
  end

  def reset(k), do: GenServer.call(__MODULE__, {:reset, k})

  @impl GenServer
  def init(k) do
    {:ok, %__MODULE__{container: :queue.new(), capacity: k, count: 0}}
  end

  @impl GenServer
  def handle_call(:front, _, %__MODULE__{count: 0} = state),
    do: {:reply, -1, state}

  @impl GenServer
  def handle_call(:front, _, %__MODULE__{container: q} = state),
    do: {:reply, :queue.get(q), state}

  @impl GenServer
  def handle_call(:rear, _, %__MODULE__{count: 0} = state),
    do: {:reply, -1, state}

  @impl GenServer
  def handle_call(:rear, _, %__MODULE__{container: q} = state),
    do: {:reply, :queue.get_r(q), state}

  @impl GenServer
  def handle_call({:in, _}, _, %__MODULE__{capacity: cap, count: cap} = state),
    do: {:reply, false, state}

  @impl GenServer
  def handle_call({:in, item}, _, %__MODULE__{container: q, count: c} = state),
    do: {:reply, true, %__MODULE__{state | container: :queue.in(item, q), count: c + 1}}

  @impl GenServer
  def handle_call(:drop, _, %__MODULE__{count: 0} = state),
    do: {:reply, false, state}

  @impl GenServer
  def handle_call(:drop, _, %__MODULE__{container: q, count: c} = state),
    do: {:reply, true, %__MODULE__{state | container: :queue.drop(q), count: c - 1}}

  @impl GenServer
  def handle_call(:is_empty, _, %__MODULE__{} = state),
    do: {:reply, state.count == 0, state}

  @impl GenServer
  def handle_call(:is_full, _, %__MODULE__{} = state),
    do: {:reply, state.count == state.capacity, state}

  @impl GenServer
  def handle_call({:reset, k}, _, _),
    do: {:reply, :ok, %__MODULE__{container: :queue.new(), count: 0, capacity: k}}
end

defmodule MyCircularQueue do
  def init_(k) do
    case GenServer.whereis(Queue) do
      nil ->
        Queue.start(k)

      _ ->
        Queue.reset(k)
    end
  end

  def en_queue(value), do: GenServer.call(Queue, {:in, value})
  def de_queue(), do: GenServer.call(Queue, :drop)
  def front(), do: GenServer.call(Queue, :front)
  def rear(), do: GenServer.call(Queue, :rear)
  def is_empty(), do: GenServer.call(Queue, :is_empty)
  def is_full(), do: GenServer.call(Queue, :is_full)
end
 
One of the benefits of the circular queue is that we can make use of the spaces in front of the queue. In a normal queue, once the queue becomes full, we cannot insert the next element even if there is a space in front of the queue. But using the circular queue, we can use the space to store new values.


Câu này nghĩa là sao vậy mn, chưa hiểu ý nghĩa lắm
 
One of the benefits of the circular queue is that we can make use of the spaces in front of the queue. In a normal queue, once the queue becomes full, we cannot insert the next element even if there is a space in front of the queue. But using the circular queue, we can use the space to store new values.


Câu này nghĩa là sao vậy mn, chưa hiểu ý nghĩa lắm
:doubt: chắc ý bảo queue bình thường implement theo kiểu singly linked list, có con trỏ tail để push và con trỏ head để lấy phần tử top
-> khi xóa phần tử top của queue thì chỉ có thể head = head.next -> không thể tham chiếu lại cái node đấy sau khi delete
 
:doubt: chắc ý bảo queue bình thường implement theo kiểu singly linked list, có con trỏ tail để push và con trỏ head để lấy phần tử top
-> khi xóa phần tử top của queue thì chỉ có thể head = head.next -> không thể tham chiếu lại cái node đấy sau khi delete
nó bảo queue full nhưng sao lại có space in front là sao nhỉ
 
nó bảo queue full nhưng sao lại có space in front là sao nhỉ
h1kRuMc.jpg
queue full ở đây là không thể allocate node mới ấy

Ví dụ đây là hình ảnh của linear buffer (singly linked list):
1920px-Circular_buffer_-_XX123XX_with_pointers.svg.png


giả sử anh insert thêm 2 phần tử nữa thì nó sẽ full, trong khi còn 2 ô trống trước phần tử 1 vẫn không hề đụng tới -> không tận dụng được các node "in front of"


9RSod1W.png
Trong khi ring buffer nó có tail refer tới head:

1920px-Circular_buffer_-_XX123XX.svg.png


Khi insert tới cuối cái buffer thì nó sẽ tự động refer lại những phần tử đầu -> hình ảnh của ring buffer sau khi insert 4, 5, 6, 7, 8 nó sẽ như này:

1920px-Circular_buffer_-_6789345.svg.png
 
h1kRuMc.jpg
queue full ở đây là không thể allocate node mới ấy

Ví dụ đây là hình ảnh của linear buffer (singly linked list):
1920px-Circular_buffer_-_XX123XX_with_pointers.svg.png


giả sử anh insert thêm 2 phần tử nữa thì nó sẽ full, trong khi còn 2 ô trống trước phần tử 1 vẫn không hề đụng tới -> không tận dụng được các node "in front of"


9RSod1W.png
Trong khi ring buffer nó có tail refer tới head:

1920px-Circular_buffer_-_XX123XX.svg.png


Khi insert tới cuối cái buffer thì nó sẽ tự động refer lại những phần tử đầu -> hình ảnh của ring buffer sau khi insert 4, 5, 6, 7, 8 nó sẽ như này:

1920px-Circular_buffer_-_6789345.svg.png
https://www.cs.usfca.edu/~galles/visualization/QueueArray.html


tại sao cái ring buffer nó ko cho phép đẩy full vòng tròn mà cứ phải dư ra 1 ô cuối làm gì vậy
 
k ô sát cuối ấy
ví dụ

[4][5, tail][][6, head][1][2][3]

nó để thừa ra một ô giữa tail và head, tui ko insert vào đc trong cái animation ý
OG0lsXv.png
thì đúng là phần tử front() rồi mà

Untitled.png


Nếu mà anh insert vào ô số 3, tức là ô mà tail đang trỏ tới thì theo thuật toán, tail sẽ phải trỏ tới ô head, head trỏ tới ô tiếp theo -> sai

OG0lsXv.png
trừ khi anh implement kiểu nếu không đủ ô nhớ thì override cái phần tử front() thì không nói, nhưng ở đây người ta không implement kiểu đó
 
Trạng thái
Không mở để trả lời thêm.

Thống kê chủ đề

Ngày tạo
_Gia_Cat_Luong_,
Người trả lời cuối
Vipluckystar,
Trả lời
17.755
Lượt xem
1.212.553
Quay lại
Lên đầu trang