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

Giờ thế này, fen chứng minh các số không phải power of 2, ví dụ số 37
tại sao 37 & 36 != 0
Cái này cũng dễ, thiết nghĩ fen có thể tự suy nghĩ và chứng minh được. Mình có vài gợi ý:

1. Nghĩ thêm về bản chất của phép trừ một trên số nhị phân, bit nào sẽ bị đổi thành 0 và bit nào sẽ bị đổi thành 1
2. Nhận thấy nếu số n không phải là power of 2 thì phép trừ 1 chắc chắn sẽ để lại ít nhất 1 bit = 1 không đổi.
3. Chính vì cả n và n - 1 đều có bit 1 không đổi này nên n & (n - 1) chắc chắn sẽ lớn hơn 0
 
Giờ thế này, fen chứng minh các số không phải power of 2, ví dụ số 37
tại sao 37 & 36 != 0
Khổ quá, biểu diễn nhị phân thì các số power of 2 phải là: bắt đầu bằng bit 1, sau đó toàn là bit 0. Ví dụ:
1
10
100
1000
10000
...

Ngoài ra thì chắc chắn không phải là power of 2. Khi đó thì sẽ có ít nhất 2 bit 1 trong biểu diễn nhị phân.
Ví dụ số đó là n = 10001000 -> n-1 = 10000111 -> khi AND lại chắc chắn sẽ khác 0.
 
faster than 100.00% :smile:

JavaScript:
function reorderedPowerOf2(n: number): boolean {

    const order = n.toString().split('').sort().join();



    for(let i = 0; i < 30; i++) {

        if((1 << i).toString().split('').sort().join() === order) return true;

    }

    return false;

};
 
Cho em góp tí code PHP. Hơi dài dòng tí nhưng dễ hiểu.
class Solution
{
protected $preCached = [];

protected function numberToDigits($n) {
$digits = array_fill(0, 10, 0);
while ($n > 0) {
$lastDigit = $n % 10;
$digits[$lastDigit]++;

$n = ($n - $lastDigit) / 10;
}

$rs = '';
for ($i = 0; $i < 9; $i++) {
$rs .= $i.'|'.$digits[$i].'.';
}

return $rs;
}

/**
* @param Integer $n
* @return Boolean
*/
function reorderedPowerOf2($n)
{
// Get List of Power of 2 less than 10^9.
$powerOf2 = 1;
while ($powerOf2 < 1000000000) {
// Save the digits and frequence need to construct the number.
$this->preCached[$powerOf2] = $this->numberToDigits($powerOf2);
$powerOf2*=2;
}

// Try to hash the digits need to construct the number.
$digits = $this->numberToDigits($n);

// Compare with all the valid power of 2 numbers.
foreach($this->preCached as $number => $digits2) {
if ($digits2 === $digits) {
return true;
}
}
return false;
}
}
 
code như này thì optimize theo hướng nào các fen nhỉ? đọc solution của mấy bài beat 100% cũng tương tự mà của mình thì lại chậm

Code:
class Solution {
    public boolean reorderedPowerOf2(int n) {
        char[] digits = String.valueOf(n).toCharArray();
        Arrays.sort(digits);
        n = 0;
     
        for (int i = digits.length - 1; i >= 0; i--) {
            n += Character.getNumericValue(digits[i]) * Math.pow(10, i);
        }
     
        return Arrays.asList(
            1, 2, 4, 8, 61, 32, 64, 821, 652, 521, 4210, 8420, 9640, 9821, 86431, 87632, 66553, 732110, 644221, 885422, 8765410,
            9752210, 9444310, 8888630, 77766211, 55443332, 88766410, 877432211, 866554432, 987653210, 184497518, 186509729
        ).contains(n);
    }
}
 
Last edited:
code như này thì optimize theo hướng nào các fen nhỉ? đọc solution của mấy bài beat 100% cũng tương tự mà của mình thì lại chậm

Code:
class Solution {
    public boolean reorderedPowerOf2(int n) {
        char[] digits = String.valueOf(n).toCharArray();
        Arrays.sort(digits);
        n = 0;
   
        for (int i = digits.length - 1; i >= 0; i--) {
            n += Character.getNumericValue(digits[i]) * Math.pow(10, i);
        }
   
        return Arrays.asList(
            1, 2, 4, 8, 61, 32, 64, 821, 652, 521, 4210, 8420, 9640, 9821, 86431, 87632, 66553, 732110, 644221, 885422, 8765410,
            9752210, 9444310, 8888630, 77766211, 55443332, 88766410, 877432211, 866554432, 987653210, 184497518, 186509729
        ).contains(n);
    }
}

Chưa đọc mấy bài 100% nhưng với code này thì có một số vấn đề sau:
  • Dùng thuật toán sort() generic, độ phức tạp là O(n logn). Trong khi đó với input như này thì có thể dùng Counting sort O(n),
  • Dùng Math.pow() để tính lũy thừa 10. Đây là hàm generic nên khả năng bên dưới nó dùng khai triển Taylor, rồi phải làm việc với số thực, tốn thêm thời gian chuyển đổi qua lại với số nguyên. Có thể đổi sang lưu một biến pow rồi nhân 10 sau mỗi lần lặp,
  • Ở phần tìm kiếm cuối cùng dùng kiểu vét cạn O(n). Có thể đổi sang binary search O(log n) hoặc hash O(1) thử xem, tất nhiên phải build trước khi chạy các test case.
 
với lại cái leetcode nó đo tốc độ cũng ko chính xác nữa, nhứt là mấy bài có tốc độ lẹ, có lúc 4ms, có lúc nộp lại còn 0ms
ghXpJrI.png
 
Bài này phải xem giải lun :cry:
Python:
class Solution:
        def maxSumSubmatrix(self, matrix: List[List[int]], k: int) -> int:
            def maxSumSubarray(arr):
                sub_s_max = float('-inf')
                s_curr = 0
                prefix_sums = [float('inf')]
                for x in arr:
                    bisect.insort(prefix_sums, s_curr)
                    s_curr += x
                    i = bisect.bisect_left(prefix_sums, s_curr - k)
                    sub_s_max = max(sub_s_max, s_curr - prefix_sums[i])
                return sub_s_max
        
            m, n = len(matrix), len(matrix[0])
            for x in range(m):
                for y in range(n - 1):
                    matrix[x][y+1] += matrix[x][y]
            res = float('-inf')
            for y1 in range(n):
                for y2 in range(y1, n):
                    arr = [matrix[x][y2] - (matrix[x][y1-1] if y1 > 0 else 0) for x in range(m)]
                    res = max(res, maxSumSubarray(arr))
            return res


Đoạn code dưới copy của 1 đứa nó làm O(n^2) nhưng vẫn pass, mặc dù solution hướng dẫn cách tìm maxsum không vượt quá K trong 1D array bằng order set nhưng python lại không có. Thím nào biết cách code lại đoạn này bằng python mà O(nlogn) k


Python:
           def maxSumSubarray(arr):
                sub_s_max = float('-inf')
                s_curr = 0
                prefix_sums = [float('inf')]
                for x in arr:
                    bisect.insort(prefix_sums, s_curr)
                    s_curr += x
                    i = bisect.bisect_left(prefix_sums, s_curr - k)
                    sub_s_max = max(sub_s_max, s_curr - prefix_sums[i])
                return sub_s_max
 
Bài hôm nay thì cơ bản của prefix sum + sorted set thôi, không có gì đặc biệt. O(mmn logn). Nếu m > n thì transpose trước.
Nhưng thời gian vẫn gấp 6 lần bài top. Có ai có cách hay hơn không?
 
bài hôm nay vừa khó vừa phải tìm buit-in data structure đủ performance để chạy, mém phải lên github chôm source ordered set về nhét vào rồi
yBBewst.png


Code:
defmodule Solution do
  def max_sum_submatrix(matrix, k) do
    {row, col, matrix} = to_map(matrix, 0, 0, %{})

    for c1 <- 0..(col - 1), reduce: -100_001 do
      result ->
        for c2 <- c1..0, reduce: {[], result} do
          {rows, result} ->
            rows =
              case rows do
                [] ->
                  for r <- 0..(row - 1), do: Map.get(matrix, {r, c2})

                rs ->
                  calculate_presum(rs, 0, c2, matrix, [])
              end

            case larget_close_to_k(rows, :gb_sets.singleton(0), 0, nil, k) do
              nil -> {rows, result}
              res -> {rows, max(result, res)}
            end
        end
        |> elem(1)
    end
  end

  defp to_map([], row, col, map), do: {row, col, map}
  defp to_map([[x]], row, col, map), do: {row + 1, col + 1, Map.put(map, {row, col}, x)}
  defp to_map([[] | rest], row, _col, map), do: to_map(rest, row + 1, 0, map)

  defp to_map([[x | r_rest] | rest], row, col, map),
    do: to_map([r_rest | rest], row, col + 1, Map.put(map, {row, col}, x))

  defp calculate_presum([], _row, _col, _matrix, res), do: Enum.reverse(res)

  defp calculate_presum([x | rest], row, col, matrix, res),
    do:
      calculate_presum(rest, row + 1, col, matrix, [
        x + Map.get(matrix, {row, col}) | res
      ])

  defp larget_close_to_k([], _sums, _sum, res, _k), do: res

  defp larget_close_to_k([x | rest], sums, sum, res, k) do
    sum = sum + x

    iter = :gb_sets.iterator_from(sum - k, sums)

    res =
      case :gb_sets.next(iter) do
        {val, _} ->
          if res == nil do
            sum - val
          else
            max(res, sum - val)
          end

        _ ->
          res
      end

    larget_close_to_k(rest, :gb_sets.add(sum, sums), sum, res, k)
  end
end
 
Last edited:
O(m^2 n^2) mà tạo cái mảng 101x101 là O(mn) mem ~ 40KB nó ko fit L1 data cache (32KB) thì chậm hơn code O(m^3 n) xài O(m) mem
KV0XGIA.gif


à hình như có thể do cách xài O(m) mem nó tính ít phép +- hơn nữa
zQU2cJa.png
 
Last edited:
Lần đầu tiên làm contest leetcode mà giải được 4 bài hehe

Python:
graph1 = {1: [], 2: [1], 3: [1]}
graph2 = {1: [2], 2: [3], 3: [1]}


def toposort(graph):
    visited = [False for _ in range(len(graph)+1)]
    result = []

    def DFS(node):
        if visited[node]:
            return
        visited[node] = True

        for adj in graph[node]:
            DFS(adj)
        result.append(node)

    for i in graph:
        DFS(i)

    return result


print(toposort(graph1)[::-1])
print(toposort(graph2)[::-1])


Python:
# graph1 [3, 2, 1]
# graph2 [1, 2, 3]

Tui định dùng cái toposort, mà không biết sửa code như nào để toposort phát hiện được cycle và return None hoặc -1 gì đó. Như trên thì graph2 có cycle rùi mà nó vẫn ra kết quả:

ai biết sửa sao ko
 
Tui định dùng cái toposort, mà không biết sửa code như nào để toposort phát hiện được cycle và return None hoặc -1 gì đó. Như trên thì graph2 có cycle rùi mà nó vẫn ra kết quả:

ai biết sửa sao ko

visited cần có 3 trạng thái.
0: chưa visit
1: đánh dấu tạm thời, khi mà dfs bắt đầu ở vertex đó
2: kết thúc tất cả các path bắt đầu từ vertex
Nếu trong quá trình dfs phát hiện visited = 1 thì tức là có cycle
 
Back
Top