Max Consecutive Ones
Bạn nhận được một mảng nums trong đó mỗi giá trị là 0 hoặc 1. Một dãy liên tiếp là một đoạn gồm các số 1 nằm cạnh nhau, không có 0 nào ở giữa. Hãy trả về độ dài của dãy liên tiếp dài nhất, hoặc 0 nếu mảng không có số 1 nào.
Hàm
- numsinteger-array
- một mảng gồm các số 0 và 1
- Trả vềinteger
- độ dài của dãy số 1 liên tiếp dài nhất
Ràng buộc
1 ≤ nums.length ≤ 2 × 104- Mỗi
nums[i]là0hoặc1.
Ví dụ
- Đầu vào
- nums = [1, 1, 0, 1, 1, 1, 0, 1]
- Đầu ra
- 3
- Giải thích
- Các số 1 tạo thành ba đoạn: từ chỉ số
0đến1(độ dài 2), từ3đến5(độ dài 3) và riêng chỉ số7(độ dài 1). Đoạn dài nhất có độ dài3.
- Đầu vào
- nums = [0, 1, 0, 1, 1]
- Đầu ra
- 2
- Giải thích
- Số 1 đơn lẻ ở chỉ số
1không lớn bằng cặp số ở các chỉ số3và4, nên đáp án là2.
- Đầu vào
- nums = [0, 0, 0]
- Đầu ra
- 0
- Giải thích
- Không có số 1 nào, nên không có đoạn liên tiếp nào và đáp án là
0.
Câu hỏi mở rộng
Bạn có thể đổi tối đa k số 0 thành số 1 không? Đoạn liên tiếp dài nhất có thể dài bao nhiêu, và bạn vẫn có thể tìm ra đoạn đó chỉ với một lượt duyệt không?
Gợi ý
Mở từng gợi ý một. Mỗi gợi ý tiết lộ thêm một chút.
Một dãy số 1 kết thúc ngay khi xuất hiện
0. Bạn cần nhớ điều gì về những giá trị mình đã đi qua?Chỉ độ dài của đoạn liên tiếp kết thúc tại chỉ số hiện tại mới quan trọng. Giá trị 1 làm đoạn này dài thêm một đơn vị, còn giá trị 0 đặt độ dài về 0.
Duyệt qua mảng một lần bằng hai số: độ dài của chuỗi liên tiếp hiện tại và độ dài tốt nhất tính đến lúc đó. Sau mỗi số 1, tăng độ dài chuỗi hiện tại rồi so sánh với độ dài tốt nhất; sau mỗi số 0, đặt lại độ dài chuỗi hiện tại.
Lời giải
Một dãy liên tiếp kết thúc ngay khi xuất hiện 0, vì vậy tại mỗi chỉ số, bạn chỉ cần độ dài của dãy kết thúc ở đó. Một bộ đếm tăng lên khi gặp 1 và đặt lại về 0 khi gặp 0 sẽ tìm được dãy dài nhất chỉ trong một lượt duyệt.
Đếm tiến từ mọi chỉ số
Đúng, nhưng không chạy xong với các test lớn nhất
Ý tưởng
Thử từng chỉ số làm điểm bắt đầu và đi tiếp khi bạn còn thấy số 1; số bước đi được là độ dài của đoạn bắt đầu tại đó. Đoạn dài nhất bắt đầu tại một trong các chỉ số này, vì vậy số đếm lớn nhất chính là đáp án.
Các lượt đi bị chồng lấp. Với một mảng gồm n số 1, chúng cần khoảng n² / 2 bước, tức 2 × 10^8 bước khi n = 2 × 10^4.
Thuật toán
- Đặt
best = 0. - Với mỗi chỉ số
start, đặtlength = 0. - Khi
start + lengthvẫn nằm trong mảng vànums[start + length]là1, hãy tănglengththêm 1. - Giữ giá trị lớn hơn giữa
bestvàlength. - Trả về
best.
def findMaxConsecutiveOnes(nums):
n = len(nums)
best = 0
for start in range(n):
length = 0
while start + length < n and nums[start + length] == 1:
length += 1
best = max(best, length)
return bestMột lượt duyệt với bộ đếm đang chạy
Ý tưởng
Giữ current, độ dài của đoạn gồm các số 1 liên tiếp kết thúc tại chỉ số hiện tại. Số 1 kéo dài đoạn đó thêm một phần tử; số 0 kết thúc đoạn, vì vậy current giảm xuống 0. Mỗi đoạn được đo tại chỉ số cuối cùng, nơi current bằng độ dài đầy đủ của đoạn, nên giá trị lớn nhất mà current đạt được chính là đáp án.
Với [1, 1, 0, 1, 1, 1, 0, 1], current nhận các giá trị 1, 2, 0, 1, 2, 3, 0, 1, và giá trị lớn nhất là 3.
Thuật toán
- Đặt
best = 0vàcurrent = 0. - Với mỗi giá trị trong
nums: nếu giá trị đó là1, cộng 1 vàocurrentvà giữ giá trị lớn hơn giữabestvàcurrent. - Nếu giá trị đó là
0, đặtcurrent = 0. - Trả về
best.
def findMaxConsecutiveOnes(nums):
best = 0
current = 0
for x in nums:
if x == 1:
current += 1
best = max(best, current)
else:
# A 0 breaks the run.
current = 0
return best
Lỗi thường gặp và trường hợp biên
- Chỉ cập nhật
bestkhi gặp0. Một lượt chạy đến cuối, như[0, 1, 1], sẽ không bao giờ được ghi nhận. Hãy cập nhật sau mỗi số 1 hoặc so sánh thêm một lần sau vòng lặp. - Không đặt lại
currentkhi gặp0. Các lượt chạy riêng biệt sẽ cộng dồn, nên[1, 1, 0, 1, 1]trả về4. - Khởi tạo
bestbằng1hoặc bằngnums[0].[0, 0, 0]phải trả về0. - Trong Lua và R, nơi mảng bắt đầu từ 1, hãy giới hạn lượt duyệt tiến bằng
< nthay vì≤ n. Giá trị cuối cùng sẽ không bao giờ được đọc, nên[0, 1]trả về0.
Câu hỏi thường gặp3
Độ phức tạp thời gian của Max Consecutive Ones là bao nhiêu?
Lời giải duyệt một lượt chạy trong thời gian O(n) vì nó đọc mỗi giá trị một lần và dùng thêm O(1) dung lượng: một biến đếm cho chuỗi liên tiếp hiện tại và một biến cho chuỗi dài nhất. Đếm lại từ đầu tại mỗi chỉ số sẽ mất O(n²) với một mảng toàn số 1.
Tại sao bộ đếm trở về 0 thay vì 1?
Biến đếm lưu độ dài của chuỗi liên tiếp kết thúc tại chỉ số hiện tại. Khi giá trị tại đó là 0, không có chuỗi liên tiếp nào gồm các số 1 kết thúc tại đó, nên độ dài là 0. Số 1 tiếp theo làm tăng giá trị này lên 1, tức là độ dài của chuỗi liên tiếp mới.
Max Consecutive Ones có phải là bài toán cửa sổ trượt không?
Bạn có thể xem nó như một cửa sổ: cửa sổ chứa lần chạy hiện tại, cạnh phải dịch chuyển theo mỗi giá trị, còn 0 khiến cạnh trái vượt qua nó. Cửa sổ không thu hẹp từng bước, vì vậy một bộ đếm có thể thay thế hai cạnh.
Bài tập tương tự
Các bài tập dùng cùng ý tưởng. Giải hai hoặc ba bài là bạn sẽ nhớ được mẫu này.
def findMaxConsecutiveOnes(nums):
# Viết code ở đâyKiểm thử #1
Kiểm thử #2
Kiểm thử #3
Đối số
nums = [1, 1, 0, 1, 1, 1, 0, 1]
Đầu ra mong đợi
3