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++:
class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        int ans = 0, l = 0;
        // l ở đây có thể hiểu như index của interval tạm thời cuối cùng
        // mà không bị xóa
        sort(intervals.begin(),intervals.end());
        // sort theo tăng dần của start
        for (int i = 1; i < intervals.size(); i++){
            if (intervals[l][1] <= intervals[i][0]){
                l = i;
                // trường hợp end_l <= start_i thì không cần phải xóa gì cả
            } else{
                ans++;
                if (intervals[l][1] > intervals[i][1]) l = i;
                // trường hợp này cần lưu ý nếu như end_l > end_i thì ta nên xóa l
                // và lúc này chọn i làm l mới
            }
        }
        return ans;
    }
};
 
Chỉ làm đc dp, không nghĩ ra greedy :cry:
Python:
class Solution:
    def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
        intervals = sorted(intervals, key=lambda x:x[1])
        result = 0
        previous_end = -inf

        for start, end in intervals:
            if start >= previous_end:
                previous_end = end
            else:
                result += 1
        
        return result
 
Chỉ làm đc dp, không nghĩ ra greedy :cry:
Python:
class Solution:
    def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
        intervals = sorted(intervals, key=lambda x:x[1])
        result = 0
        previous_end = -inf

        for start, end in intervals:
            if start >= previous_end:
                previous_end = end
            else:
                result += 1
       
        return result
same, mấy bài greedy nghĩ ra cách làm mà không chứng minh nổi
Python:
class Solution:
    def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
        intervals = sorted(intervals, key = lambda x:x[1])
        last = -123456789
        ans = 0
        for x, y in intervals:
            if last > x: ans += 1
            else: last = y
        return ans
 
JavaScript:
var eraseOverlapIntervals = function(intervals) {
  intervals.sort((u, v) => u[1] - v[1]);
  let lastEnd = -Infinity, ans = intervals.length;

  for (const [start, end] of intervals) {
    if (lastEnd <= start) {
      lastEnd = end;
      ans--;
    }
  }
  
  return ans;
};
 
Ngồi tìm cách học thấy mấy videos với lại course bên Neetcode hay vãi. Tác giả vừa quit Google để dành toàn bộ thời gian. Đang nghèo nhưng chắc mua cái PRO lifetime xài luôn cho nó máu :D
 
Ngồi làm memorization/dp mãi mà bị TLE, thì ra greedy
C-like:
impl Solution {
    pub fn erase_overlap_intervals(mut intervals: Vec<Vec<i32>>) -> i32 {
        intervals.sort_by_key(|x| x[1]);
        let (mut res, mut last_end) = (0, intervals[0][1]);
        for interval in intervals[1..].iter() {
            if last_end > interval[0] {
                res += 1;
            } else {
                last_end = interval[1];
            }
        }
        res
    }
}
 
Bài hôm nay chính là DP đó chứ sao mọi người lại bảo greedy nhỉ. Hiểu đề 1 cách khác là tìm tập con lớn nhất của intervals mà không overlap lẫn nhau
 
C++:
struct Data
{
    Data() = default;
    Data(int s, int e) : start{s}, end{e}
    {}
    int start{};
    int end{};
};

class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        std::vector<Data> lst;
        for (const auto& v : intervals)
        {
            lst.emplace_back(v[0], v[1]);
        }

        std::sort(lst.begin(), lst.end(), [](Data& lhs, Data& rhs){return lhs.end < rhs.end;});
        int count{};
        int cur_end = lst[0].start;

        int result = intervals.size();

        for (const auto& d : lst)
        {
            if (d.start >= cur_end)
            {
                result--;
                cur_end = d.end;
            }
        }

        return result;
    }
};

Bài hôm nay chính là DP đó chứ sao mọi người lại bảo greedy nhỉ. Hiểu đề 1 cách khác là tìm tập con lớn nhất của intervals mà không overlap lẫn nhau
Bài này không có subproblem, chỉ chạy 1 lượt duy nhất và thêm interval i gần nhất có
start_i >= end hiện tại và end_i là nhỏ nhất vào result thôi.
 
Bài hôm nay chính là DP đó chứ sao mọi người lại bảo greedy nhỉ. Hiểu đề 1 cách khác là tìm tập con lớn nhất của intervals mà không overlap lẫn nhau
Thì dùng DP cũng giải được thôi nhưng mà độ phức tạp của DP cao hơn. Khả năng cao k phải là polynomial time, mà input ntn: 1 <= intervals.length <= 10^5
thì timeout chắc rồi.
Còn greedy thì với bài này nó cũng giải đc và độ phức tạp thấp hơn O(nlog(n)) thì dùng greedy hợp lý rồi, :matrix:
 
Thì dùng DP cũng giải được thôi nhưng mà độ phức tạp của DP cao hơn. Khả năng cao k phải là polynomial time, mà input ntn: 1 <= intervals.length <= 10^5
thì timeout chắc rồi.
Còn greedy thì với bài này nó cũng giải đc và độ phức tạp thấp hơn O(nlog(n)) thì dùng greedy hợp lý rồi, :matrix:
Độ phức tạp vẫn thế vì mỗi lần lấy trạng thái trc chỉ mất logn nếu dùng binary search. Greedy vẫn phải sort nên đều là nlogn thôi
Python:
class Solution:
    def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
        n = len(intervals)
        intervals = sorted(intervals, key=lambda x:x[1])
        ends = [end for start, end in intervals]
        dp = [1 for interval in intervals]
        
        for current_index in range(1, n):
            start, end = intervals[current_index]
            previous_index = bisect_right(ends, start, 0, current_index) - 1
            
            if previous_index >= 0:
                dp[current_index] += dp[previous_index]
                
            dp[current_index] = max(dp[current_index], dp[current_index - 1])

        return n - dp[-1]
 
C++:
struct Data
{
    Data() = default;
    Data(int s, int e) : start{s}, end{e}
    {}
    int start{};
    int end{};
};

class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        std::vector<Data> lst;
        for (const auto& v : intervals)
        {
            lst.emplace_back(v[0], v[1]);
        }

        std::sort(lst.begin(), lst.end(), [](Data& lhs, Data& rhs){return lhs.end < rhs.end;});
        int count{};
        int cur_end = lst[0].start;

        int result = intervals.size();

        for (const auto& d : lst)
        {
            if (d.start >= cur_end)
            {
                result--;
                cur_end = d.end;
            }
        }

        return result;
    }
};


Bài này không có subproblem, chỉ chạy 1 lượt duy nhất và thêm interval i gần nhất có
start_i >= end hiện tại và end_i là nhỏ nhất vào result thôi.
Có subproblem mà. Sort intervals theo end để đảm bảo thứ tự duyệt tăng dần theo end time.

Dùng mảng stacks lưu các end time của các intervals sẽ được giữ lại.

Xét interval ở index thứ i = [startTime, endTime] , ta có 2 trường hợp:

  • Quyết định dùng interval thứ i này và đẩy nó vào stacks, chỉ làm thế khi startTime của interval đang được xét lớn hơn last(stacks). Vì nếu không mà vẫn cố đẩy interval đang được xét vào sẽ phải pop stacks cho đến khi last(stacks) <= startTime; dẫn đến stacks mới có ít hơn hoặc bằng stacks tại (i-1)
  • Không dùng interval này. stacks tại (i) bằng stacks tại (i-1)

JavaScript:
var eraseOverlapIntervals = function(intervals) {
  const stack = [];
  intervals = _.sortBy(intervals, '1');

  for (const [start, end] of intervals) {
    if (!stack.length || stack[stack.length-1] <= start) {
      stack.push(end);
    }
  }

  return intervals.length - stack.length;
};
 
ôn leetcode để phỏng vấn Junior backend cần ôn những algorithm nào các bác nhỉ? Còn data structure chắc ôn hết
 
Có subproblem mà. Sort intervals theo end để đảm bảo thứ tự duyệt tăng dần theo end time.

Dùng mảng stacks lưu các end time của các intervals sẽ được giữ lại.

Xét interval ở index thứ i = [startTime, endTime] , ta có 2 trường hợp:

  • Quyết định dùng interval thứ i này và đẩy nó vào stacks, chỉ làm thế khi startTime của interval đang được xét lớn hơn last(stacks). Vì nếu không mà vẫn cố đẩy interval đang được xét vào sẽ phải pop stacks cho đến khi last(stacks) <= startTime; dẫn đến stacks mới có ít hơn hoặc bằng stacks tại (i-1)
  • Không dùng interval này. stacks tại (i) bằng stacks tại (i-1)

JavaScript:
var eraseOverlapIntervals = function(intervals) {
  const stack = [];
  intervals = _.sortBy(intervals, '1');

  for (const [start, end] of intervals) {
    if (!stack.length || stack[stack.length-1] <= start) {
      stack.push(end);
    }
  }

  return intervals.length - stack.length;
};
sol này là greedy mà, có phải dp đâu
 
Ngồi tìm cách học thấy mấy videos với lại course bên Neetcode hay vãi. Tác giả vừa quit Google để dành toàn bộ thời gian. Đang nghèo nhưng chắc mua cái PRO lifetime xài luôn cho nó máu :D
mình cũng hay xem ông này, web ông đó hay cái là có roadmap nên làm dạng nào trước dạng nào để dễ hiểu, kiểu như 2 pointers trước sliding windows hay backtracking trước DP ấy :D. Với cả có cái lightnight review cũng khá hữu dụng 👌. Thích hợp cho gà con như mình 😂
 
Python:
class Solution:
    def asteroidCollision(self, asteroids: List[int]) -> List[int]:
        result = []
        stack = []

        for asteroid in asteroids:
            if asteroid > 0:
                stack.append(asteroid)
                continue
            
            while len(stack) > 0 and stack[-1] < abs(asteroid):
                stack.pop()

            if len(stack) == 0:
                result.append(asteroid)
                continue
            
            if stack[-1] == abs(asteroid):
                stack.pop()

        result += stack
        return result
 
Ý tưởng sử dụng stack của bài toán hôm nay khá rõ ràng. Nhét các hành tinh vào trong stack, check với từng hành tinh khác, nếu nổ thì đẩy ra khỏi stack.
JavaScript:
function asteroidCollision(asteroids: number[]): number[] {
    let stack = [asteroids[0]];
    for (let i = 1; i < asteroids.length; i++) {
        if (stack.length === 0) {
            stack.push(asteroids[i])
        } else if (stack[stack.length - 1] * asteroids[i] > 0 || stack[stack.length - 1] < 0) {
            stack.push(asteroids[i])
        } else {
            if (Math.abs(asteroids[i]) > Math.abs(stack[stack.length - 1])) {
                stack.pop()
                i--;
            } else if (Math.abs(asteroids[i]) === Math.abs(stack[stack.length - 1])) {
                stack.pop()
            }
        }
    }
    return stack
};
 
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.784
Quay lại
Lên đầu trang