Cần giúp đỡ tối ưu bài toán đếm số bao đũa cần có khi nhận được 1 bó đũa

Anh mình bữa nay cho mình có cái bài này:
Thịnh là 1 nhân viên nhà hàng. Hằng ngày, Thịnh phải xếp đũa vào các giấy bọc đũa. Hãy giúp Thịnh đếm số bao cần có khi nhận được 1 bó đũa. Biết các có tồn tại các loại đũa khác nhau.
Đánh số cho các loại đũa, ta có cái mảng ar này, giờ phải code hàm countWrappers(ar) trả về số giấy bọc đũa cần phải dùng.

ar = [1, 22, 2, 1, 4, 3, 1, 5, 1, 2, 2, 4]
print(countWrappers(ar))
#4

Code của mình

import time
import random
# Mình random ra 1 mảng lớn lớn 1 tý để xem performance
ar =  []
for i in range(9999):
  ar.append(random.randint(1, 100))

for i in range(5):

  # Method 1
  start = time.time()
  mapper = {}
  for num in ar:
    if num not in mapper: 
      mapper[num] = ar.count(num)

  arr = [mapper[x]//2 for x in mapper if mapper[x]>1]
  print(sum(arr))
  end = time.time()
  print("Time 1: ", end-start)


  # Method 2
  start = time.time()
  mapper = {i:ar.count(i) for i in ar}
  arr = [mapper[x]//2 for x in mapper if mapper[x]>1]
  print(sum(arr))
  end = time.time()
  print("Time 2: ", end-start)

  # Method 3
  start = time.time()
  ar1 = sum(list({x: divmod(ar.count(x), 2)[0] for x in ar}.values()))
  print(ar1)
  end = time.time()
  print("Time 3:",end-start)

Mình chỉ nghĩ ra được ngần đó cách, nhưng vẫn chậm sấp mặt, nhà mình có ý gì hay gợi ý cho mình với ạ.
Mình xin chân thành cảm ơn.

nếu mình hiểu đúng đề thì 1 cặp (1, 1) tính là 1 đôi/1 bao à ?

4 Likes

Đúng rồi bạn, vậy là 1 cặp vì nó cùng loại mà.

1 Like

Code của bạn sai nhất ở chỗ này. Bạn có biết ar.count(num) có độ phức tạp là bao nhiêu không?
Thay vào đó, bạn có thể dùng mapper = collections.Counter(ar)

7 Likes

bài này hashmap chắc ổn áp nhỉ :thinking: ?

3 Likes

bạn thử code đi xem thế nào, cùng học với mình.

Mình đã nghịch rồi, vẫn không nhanh bằng anh mình, bạn thử code xem sao. Mình muốn học hỏi thêm.
Với cả độ phức tạp mình có thể xem ở đâu nhỉ, trong doc của python mình thấy không đề cập tới vấn đề này.

Mình có link này:

https://www.ics.uci.edu/~pattis/ICS-33/lectures/complexitypython.txt

Cách của mình:

  • Dài:
def countWrappers(a):
	d = {}
	for u in a:
		if u in d:
			d[u] += 1
		else:
			d[u] = 1

	return sum(v // 2 for v in d.values())
  • Ngắn (và không nhanh lắm):
countWrappers = lambda a: sum(a.count(u) // 2 for u in set(a))
8 Likes

Theo mình test thì dùng Counter đang là nhanh nhất trong các cách đang có.
Giờ bạn đề cập tới 1 cách siêu nhanh nhưng lại không chia sẻ cách đó để mọi người so sánh thì có vẻ không hợp lý lắm nhỉ?

7 Likes

Chưa, mình chưa có giải pháp. Anh mình đang cho mình 1 ngày để tự mò, có gì mai mình gửi kết quả lên mọi người cùng tham khảo. Với cả bạn thử code đi, xem chênh lệch như thế nào. Cũng là một lần học mà :hugs:

from collections import Counter

def ...(a):
    return sum(v//2 for k,v in dict(Counter(a)).items())

:V :V

10 Likes

Thứ nhất, mình đang chưa muốn học python.
Thứ hai, cho dù muốn học thì cũng chưa chắc cách như thế này là tốt.
Thứ ba, quan trọng nhất, mình đang cảm nhận đây không phải là “Cần giúp đỡ” như tiêu đề bạn đặt ra, mà giống như là “một lời thách đố” thì đúng hơn.

7 Likes

chỗ này, sửa thành:

  for num in ar:
    mapper[num] = mapper.get(num,0) + 1

Sẽ nhanh hơn nhiều đấy.

Edit: Test sơ sơ thấy nhanh gấp 10 lần =)) https://repl.it/repls/PoisedEagerLoops

8 Likes
def bait(a):
    # nếu bạn tỉnh táo :))))
    m = [0] * (max(a) + 1)
    for v in a: m[v] += 1
    return sum([x//2 for x in list(set(m)) if x > 0])

print(countWrapper([1, 22, 2, 1, 4, 3, 1, 5, 1, 2, 2, 4]))

1 cái approach cực kì tốn space và time :penguin:

5 Likes

Ầy, đúng là thách thức. Bài tập là thách thức rồi. Mình mong muốn nhiều người tham gia, mình được học tập mà có mất gì đâu bạn.

Mình cần giúp đỡ vì như bạn thấy đấy, chưa đầy 1s bạn đã chỉ cho mình thấy nhược điểm của mình và cho mình solution rồi, vẫn hoan nghênh bạn tham gia cho vui

Mảng này vẫn nhỏ, test data structure phải ít nhất 1 triệu phần tử.

5 Likes

Ù, mình xin ghi nhận, nhưng mới đó thôi là đã thấy mình chậm cỡ nào rùi. Cảm ơn bạn.

No, I’m not randomly saying this for fun. Data structures and algorithms are created to solve the cases of asymptotically large input. If it’s only a difference between a few hundred mili-seconds then nobody would care. The only right way to evaluate an algorithm is to do with a fairly large input.

3 Likes

Cách 1: mỗi giá trị phải lục tung cái mảng 1 lần (ouch)
Cách 2: đọc tới đâu đếm tới đó :slight_smile: win chặt rồi.

Khi nghiên cứu người ta vẫn xét tất cả các độ dài input nhé :smiley:

5 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?