Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Python

Python - หา Good Indices ในอาร์เรย์

ได้อาร์เรย์ A ต้องการหา indices ทั้งหมดที่ถ้าลบ element ตัวนั้นออก อาร์เรย์ที่เหลือจะเป็น "Good Array" โดย Good Array = มี element หนึ่งตัวที่เท่ากับผลรวมของอีกทั้งหมด ใช้ 1-based indexing

ตัวอย่าง

Input: [10, 4, 6, 2]

Output: [1, 4]

อธิบาย:

  • ลบ A[1]=10 → [4, 6, 2] → 6 = 4+2 ✓
  • ลบ A[4]=2 → [10, 4, 6] → 10 = 4+6 ✓

อัลกอริธึม: Prefix Sum + Hash Map


from collections import defaultdict

def find_good_indices(A):
    n = len(A)
    total_sum = sum(A)
    freq = defaultdict(int)
    
    for x in A:
        freq[x] += 1
    
    good_indices = []
    
    for i in range(n):
        # ผลรวมหลังลบ A[i]
        remaining_sum = total_sum - A[i]
        
        # ต้องหาร 2 ลงตัว (เพราะ x = sum - x → 2x = sum)
        if remaining_sum % 2 == 0:
            target = remaining_sum // 2
            
            # ตรวจสอบว่า target มีในอาร์เรย์ที่เหลือ
            if target in freq:
                # ถ้า target == A[i] ต้องมีอย่างน้อย 2 ตัว
                # ถ้า target != A[i] ต้องมีอย่างน้อย 1 ตัว
                if (A[i] == target and freq[target] > 1) or (A[i] != target):
                    good_indices.append(i + 1)  # 1-based
    
    return good_indices

# ทดสอบ
A = [10, 4, 6, 2]
print(find_good_indices(A))  # [1, 4]

การทำงานแบบ Step-by-Step


A = [10, 4, 6, 2]
total_sum = 22
freq = {10:1, 4:1, 6:1, 2:1}

i=0, A[i]=10: remaining=12, target=6, freq[6]=1, 10!=6 → good (index 1)
i=1, A[i]=4:  remaining=18, target=9, freq[9]=0 → not good
i=2, A[i]=6:  remaining=16, target=8, freq[8]=0 → not good
i=3, A[i]=2:  remaining=20, target=10, freq[10]=1, 2!=10 → good (index 4)

Result: [1, 4]

Edge Cases


# ทดสอบ edge cases
test_cases = [
    [1, 1],           # [1, 2] - ลบตัวไหนก็ได้ เหลือ [1] → 1 = 0? ไม่ (empty sum=0)
    [2, 2, 2],        # [1, 2, 3] - ลบตัวไหน เหลือ [2,2] → 2 = 2 ✓
    [0, 0, 0],        # [1, 2, 3] - 0 = 0 ✓
    [1],              # [] - ไม่มี index ที่ valid (n<2)
    [5, 5, 10],       # [3] - ลบ 10 เหลือ [5,5] → 5=5 ✓
]

for arr in test_cases:
    print(f"{arr} -> {find_good_indices(arr)}")

ผลลัพธ์ Edge Cases


[1, 1] -> []           # remaining sum = 1, target = 0.5 (not int)
[2, 2, 2] -> [1, 2, 3] # remaining = 4, target = 2, freq[2]=3 > 1
[0, 0, 0] -> [1, 2, 3] # remaining = 0, target = 0, freq[0]=3 > 1
[1] -> []              # n < 2
[5, 5, 10] -> [3]      # remove 10 → [5,5] good

Complexity

  • Time: O(n) - single pass สำหรับ sum, freq, และ check
  • Space: O(n) - frequency map

Mathematical Insight

หลังลบ A[i] อาร์เรย์ที่เหลือมีผลรวม S' = S - A[i]

ต้องการให้มี x ในอาร์เรย์ที่เหลือ ทำให้ x = S' - x → 2x = S' → x = S'/2

ดังนั้น S' ต้องเป็นเลขคู่ และ S'/2 ต้องมีอยู่ในอาร์เรย์ที่เหลือ

สรุป

  • คำนวณ total_sum และ frequency map ครั้งเดียว
  • แต่ละ index: remaining_sum = total - A[i]
  • ถ้า remaining_sum even และ target = remaining_sum/2 อยู่ใน freq
  • ตรวจสอบ frequency condition (target == A[i] ต้องมี > 1)
  • Time O(n), Space O(n)