Pattern · Tham lamTrung bình
Đoạn Con Tổng Lớn NhấtMaximum Subarray
Hiểu bài
Cho mảng nums (có thể có số âm). Tìm đoạn con liền kề (subarray) có tổng lớn nhất, trả về tổng đó.
Ví dụ:
ts
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
// đoạn [4, -1, 2, 1] có tổng 6 — lớn nhất
output = 6Đoạn con phải liền nhau (không được bỏ phần tử ở giữa) và có ít nhất 1 phần tử.
Xem cách cơ bản (chậm hơn)
Cách cơ bản
O(n²) time, O(1) spacets
function maxSubArray(nums: number[]): number {
let best = -Infinity
for (let i = 0; i < nums.length; i++) {
let sum = 0
for (let j = i; j < nums.length; j++) {
sum += nums[j]
best = Math.max(best, sum)
}
}
return best
}Vì sao cách này chậm:
Thử mọi điểm bắt đầu i và cộng dồn tới mọi điểm kết thúc j.
Đúng nhưng với n=10⁵ thì n² = 10¹⁰ phép cộng — quá chậm.
Lời giải tối ưu
Tối ưu
O(n) time, O(1) spacets
function maxSubArray(nums: number[]): number {
let curr = nums[0] // tổng đoạn tốt nhất KẾT THÚC tại i
let best = nums[0]
for (let i = 1; i < nums.length; i++) {
curr = Math.max(nums[i], curr + nums[i])
best = Math.max(best, curr)
}
return best
}Mấu chốt:
Giải thuật tối ưu dùng thuật toán Kadane.
- Tại mỗi vị trí, hỏi: nên nối tiếp đoạn phía trước (
curr + nums[i]) hay bắt đầu lại từ chínhnums[i]? Nếucurrđang âm thì nó chỉ làm tổng giảm → bỏ đi, bắt đầu mới.bestghi lại giá trị lớn nhất từng thấy. - Tư duy tham lam: loại bỏ ngay tiền tố có tổng âm.
Chạy thử từng bước
Chạy thử qua từng bước — bấm vào một bước để xem dòng code tương ứng
1function maxSubArray(nums: number[]): number {2let curr = nums[0] // tổng đoạn tốt nhất KẾT THÚC tại i3let best = nums[0]4for (let i = 1; i < nums.length; i++) {5curr = Math.max(nums[i], curr + nums[i])6best = Math.max(best, curr)7}8return best9}
Trường hợp biên phải nhớ
Mảng toàn số âm ([-3, -1, -2]) → đáp án là số âm lớn nhất (−1), KHÔNG phải 0.
Vì vậy khởi tạo bằng nums[0], đừng khởi tạo best = 0.
Mảng 1 phần tử → trả chính phần tử đó.
Khởi tạo
curr = 0rồi cộng là bẫy: với mảng toàn âm sẽ trả 0 sai.Phải so
Math.max(nums[i], curr + nums[i]).Số 0 xen kẽ không reset đoạn — chỉ tổng âm mới khiến nên bắt đầu lại.