ν™ˆ [DSA] μΉ΄μš΄νŒ…
포슀트
μ·¨μ†Œ

[DSA] μΉ΄μš΄νŒ…


Title


κ°œμš”

ν•΄μ‹œ 맡을 ν™œμš©ν•œ μΉ΄μš΄νŒ…μ€ 일반적인 νŒ¨ν„΄ 쀑 ν•˜λ‚˜μ΄λ‹€. μ—¬κΈ°μ„œ β€œμΉ΄μš΄νŒ…β€μ΄λž€ λ‹€μ–‘ν•œ ν•­λͺ©λ“€μ˜ λ°œμƒ λΉˆλ„λ₯Ό μΆ”μ ν•˜λŠ” 것을 λ§ν•œλ‹€. μ΄λŠ” 우리의 ν•΄μ‹œ 맡이 ν‚€λ₯Ό μ •μˆ˜ 값에 λŒ€μ‘μ‹œν‚€κ²Œ 됨을 μ˜λ―Έν•œλ‹€. μ–΄λ–€ 것을 μ„Έμ–΄μ•Ό ν•  ν•„μš”κ°€ μžˆμ„ λ•Œ, κ·Έ μž‘μ—…μ„ μœ„ν•΄ ν•΄μ‹œ 맡을 μ‚¬μš©ν•˜λŠ” 것을 κ³ λ €ν•΄ λ³Ό 수 μžˆλ‹€.

μŠ¬λΌμ΄λ”© μœˆλ„μš°λ₯Ό μ‚΄νŽ΄λ³΄λ©΄, 일뢀 λ¬Έμ œλ“€μ΄ μœˆλ„μš° λ‚΄ νŠΉμ • μš”μ†Œμ˜ 수λ₯Ό μ œν•œν•˜λŠ” 것을 μ œμ•½ 쑰건으둜 μ‚ΌλŠ” 것을 μ•Œ 수 μžˆλ‹€. 예λ₯Ό λ“€μ–΄, μ΅œλŒ€ k개의 0을 ν¬ν•¨ν•˜λŠ” κ°€μž₯ κΈ΄ λΆ€λΆ„ λ¬Έμžμ—΄ λ¬Έμ œκ°€ μžˆλ‹€. μ΄λŸ¬ν•œ λ¬Έμ œμ—μ„œλŠ” 였직 ν•˜λ‚˜μ˜ μš”μ†Œ(0)μ—λ§Œ μ§‘μ€‘ν•˜κ³  있기 λ•Œλ¬Έμ— κ°„λ‹¨νžˆ μ •μˆ˜ λ³€μˆ˜ curr을 μ‚¬μš©ν•  수 μžˆμ—ˆλ‹€. 반면, ν•΄μ‹œ 맡은 μ—¬λŸ¬ μš”μ†Œλ₯Ό ν¬ν•¨ν•˜λŠ” μ œμ•½ 쑰건이 μžˆλŠ” λ¬Έμ œλ“€μ„ ν•΄κ²°ν•  수 μžˆλŠ” μƒˆλ‘œμš΄ 방법을 μ œκ³΅ν•œλ‹€. 이제 ν•΄μ‹œ 맡을 ν™œμš©ν•˜λŠ” μŠ¬λΌμ΄λ”© μœˆλ„μš° μ˜ˆμ‹œλ₯Ό μ‚΄νŽ΄λ³΄λ©° μ‹œμž‘ν•΄λ³΄μž.


예제 1: μ΅œλŒ€ k개의 μ„œλ‘œ λ‹€λ₯Έ 문자λ₯Ό ν¬ν•¨ν•˜λŠ” κ°€μž₯ κΈ΄ λΆ€λΆ„ λ¬Έμžμ—΄μ˜ 길이

λ¬Έμžμ—΄ s와 μ •μˆ˜ kκ°€ μ£Όμ–΄μ‘Œμ„ λ•Œ, μ΅œλŒ€ k개의 μ„œλ‘œ λ‹€λ₯Έ 문자λ₯Ό ν¬ν•¨ν•˜λŠ” κ°€μž₯ κΈ΄ λΆ€λΆ„ λ¬Έμžμ—΄μ˜ 길이λ₯Ό μ°Ύμ•„λ³΄μž.

예λ₯Ό λ“€μ–΄, s = "eceba"와 k = 2κ°€ 주어지면, 3μ΄λΌλŠ” κ²°κ³Όλ₯Ό λ°˜ν™˜ν•œλ‹€. μ—¬κΈ°μ„œ μ΅œλŒ€ 2개의 μ„œλ‘œ λ‹€λ₯Έ 문자λ₯Ό 가진 κ°€μž₯ κΈ΄ λΆ€λΆ„ λ¬Έμžμ—΄μ€ "ece"이닀.

이 λ¬Έμ œλŠ” λΆ€λΆ„ λ¬Έμžμ—΄μ„ 닀루고, λΆ€λΆ„ λ¬Έμžμ—΄μ— μ΅œλŒ€ k개의 μ„œλ‘œ λ‹€λ₯Έ λ¬ΈμžλΌλŠ” μ œμ•½ 쑰건이 μžˆλ‹€. μ΄λŸ¬ν•œ νŠΉμ„±μœΌλ‘œ 인해, μŠ¬λΌμ΄λ”© μœˆλ„μš° 기법을 κ³ λ €ν•΄ λ³Ό ν•„μš”κ°€ μžˆλ‹€. μŠ¬λΌμ΄λ”© μœˆλ„μš°λŠ” μ œμ•½ 쑰건을 μœ„λ°˜ν•  λ•ŒκΉŒμ§€ μœˆλ„μš°λ₯Ό 였λ₯Έμͺ½μœΌλ‘œ ν™•μž₯ν•˜κ³ , μœ„λ°˜ν•˜λ©΄ μœˆλ„μš°λ₯Ό μ™Όμͺ½μœΌλ‘œ μ€„μ—¬λ‚˜κ°€λŠ” λ°©μ‹μœΌλ‘œ μž‘λ™ν•œλ‹€. 이 λ¬Έμ œμ—μ„œλŠ” μœˆλ„μš° λ‚΄μ˜ μ„œλ‘œ λ‹€λ₯Έ 문자 μˆ˜μ— μ§‘μ€‘ν•œλ‹€. 이 μ œμ•½ 쑰건을 ν™•μΈν•˜λŠ” 전톡적인 방법은 맀번 전체 μœˆλ„μš°λ₯Ό κ²€μ‚¬ν•˜λŠ” 것인데, μ΄λŠ” $O(n)$의 μ‹œκ°„μ΄ μ†Œμš”λ  수 μžˆλ‹€. ν•΄μ‹œ 맡을 μ‚¬μš©ν•˜λ©΄, 이 μž‘μ—…μ„ $O(1)$의 μ‹œκ°„μ— μˆ˜ν–‰ν•  수 μžˆλ‹€.

μœˆλ„μš° λ‚΄ 문자의 λΉˆλ„μˆ˜λ₯Ό μΆ”μ ν•˜κΈ° μœ„ν•΄ ν•΄μ‹œ 맡 countsλ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€. μ΄λŠ” 문자λ₯Ό λΉˆλ„μˆ˜μ— λ§€ν•‘ν•˜λŠ” 것을 μ˜λ―Έν•œλ‹€. μ–΄λŠ μ‹œμ μ—μ„œλ“  counts의 길이(즉, ν‚€μ˜ 수)λŠ” μ„œλ‘œ λ‹€λ₯Έ 문자의 수λ₯Ό λ‚˜νƒ€λ‚Έλ‹€. μ™Όμͺ½μ—μ„œ μš”μ†Œλ₯Ό μ œκ±°ν•  λ•Œ, ν•΄λ‹Ή μš”μ†Œμ˜ λΉˆλ„μˆ˜λ₯Ό κ°μ†Œμ‹œν‚¬ 수 μžˆλ‹€. λΉˆλ„μˆ˜κ°€ 0이 되면, ν•΄λ‹Ή λ¬ΈμžλŠ” 더 이상 μœˆλ„μš°μ˜ 일뢀가 μ•„λ‹ˆλ―€λ‘œ, ν•΄λ‹Ή ν‚€λ₯Ό μ‚­μ œν•  수 μžˆλ‹€.

예제 1 상세 μ„€λͺ…

μŠ¬λΌμ΄λ”© μœˆλ„μš° μ•Œκ³ λ¦¬μ¦˜μ— λŒ€ν•΄ μžŠμ—ˆλ‹€λ©΄, κ΄€λ ¨ λ¬Έμ„œλ₯Ό λ‹€μ‹œ ν™•μΈν•˜κΈ° λ°”λž€λ‹€.

이 λ¬Έμ œμ—μ„œ μ œμ•½ 쑰건은 β€œμœˆλ„μš° 내에 μžˆλŠ” κ³ μœ ν•œ 문자의 μˆ˜β€μ΄λ‹€. 수치적 μ œν•œμ€ k μ΄ν•˜μ΄λ‹€. μœˆλ„μš° λ‚΄ 각 문자의 λΉˆλ„λ₯Ό μΆ”μ ν•˜λŠ” ν•΄μ‹œ 맡 countsλ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€. counts의 κΈΈμ΄λŠ” ν‚€μ˜ 수이며, μ΄λŠ” μ œμ•½ 쑰건을 λ‚˜νƒ€λ‚Έλ‹€. λ”°λΌμ„œ counts의 길이가 k보닀 클 λ•Œ, μœˆλ„μš°λŠ” μœ νš¨ν•˜μ§€ μ•Šμ€ μƒνƒœκ°€ λœλ‹€.

문자 s[right]λ₯Ό μΆ”κ°€ν•  λ•Œ, counts λ‚΄μ—μ„œ ν•΄λ‹Ή 문자의 λΉˆλ„λ₯Ό ν•˜λ‚˜ μ¦κ°€μ‹œν‚¨λ‹€. λ§Œμ•½ counts 내에 ν•΄λ‹Ή λ¬Έμžκ°€ μ—†λ‹€λ©΄, μƒˆλ‘œμš΄ ν‚€-κ°’ 쌍인 s[right]: 1을 μ‚½μž…ν•œλ‹€.

문자 s[left]λ₯Ό μ œκ±°ν•  λ•Œ, counts λ‚΄μ—μ„œ ν•΄λ‹Ή 문자의 λΉˆλ„λ₯Ό ν•˜λ‚˜ κ°μ†Œμ‹œν‚¨λ‹€. λΉˆλ„κ°€ 0이 되면, ν•΄λ‹Ή λ¬ΈμžλŠ” 더 이상 μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” κ²ƒμ΄λ―€λ‘œ, ν•΄μ‹œ λ§΅μ—μ„œ ν•΄λ‹Ή ν‚€λ₯Ό μ‚­μ œν•˜κ³  counts의 길이λ₯Ό 쀄인닀.

μœˆλ„μš°μ˜ κΈΈμ΄λŠ” right - left + 1둜 κ³„μ‚°λœλ‹€λŠ” 점을 κΈ°μ–΅ν•˜μž.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int findLongestSubstring(string s, int k) {
    unordered_map<char, int> counts;
    int left = 0, ans = 0;
    
    for (int right = 0; right < s.size(); right++) {
        counts[s[right]]++;
        while (counts.size() > k) {
            counts[s[left]]--;
            if (counts[s[left]] == 0) {
                counts.erase(s[left]);
            }
            left++;
        }
        
        ans = max(ans, right - left + 1);
    }
    
    return ans;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
fn find_longest_substring(s: &str, k: usize) -> usize {
    let mut counts: HashMap<char, i32> = HashMap::new();
    let (mut left, mut ans) = (0, 0);

    for (right, c) in s.chars().enumerate() {
        *counts.entry(c).or_insert(0) += 1;

        while counts.len() > k {
            let left_char = s.chars().nth(left).unwrap();
            *counts.get_mut(&left_char).unwrap() -= 1;

            if counts[&left_char] == 0 {
                counts.remove(&left_char);
            }

            left += 1;
        }

        ans = ans.max(right - left + 1);
    }

    ans
}

이 μ½”λ“œμ—μ„œ λ³Ό 수 μžˆλ“―μ΄, ν•΄μ‹œ 맡을 ν™œμš©ν•˜μ—¬ μ›ν•˜λŠ” ν‚€μ˜ λΉˆλ„λ₯Ό μ €μž₯ν•¨μœΌλ‘œμ¨, μ—¬λŸ¬ μš”μ†Œμ— λŒ€ν•œ μ œμ•½μ„ ν¬ν•¨ν•˜λŠ” μŠ¬λΌμ΄λ”© μœˆλ„μš° 문제λ₯Ό ν•΄κ²°ν•  수 μžˆλ‹€. 이전에 μ‚΄νŽ΄λ³Έ 바와 같이, 각 for λ¬Έ λ°˜λ³΅λ§ˆλ‹€ μˆ˜ν–‰λ˜λŠ” μž‘μ—…μ΄ μΌμ •ν•œ μ‹œκ°„ 내에 처리되면, μŠ¬λΌμ΄λ”© μœˆλ„μš° 문제의 μ‹œκ°„ λ³΅μž‘λ„λŠ” $O(n)$이 λœλ‹€. 이 경우 ν•΄μ‹œ 맡이 $O(1)$의 μ—°μ‚° μ‹œκ°„μ„ 가지고 있기 λ•Œλ¬Έμ— ν•΄λ‹Ή 쑰건을 λ§Œμ‘±ν•œλ‹€. ν•΄μ‹œ 맡은 $O(k)$의 곡간을 μ°¨μ§€ν•˜λ©°, $k$λ₯Ό μ΄ˆκ³Όν•˜λŠ” 경우 μ•Œκ³ λ¦¬μ¦˜μ€ ν•΄μ‹œ λ§΅μ—μ„œ ν•΄λ‹Ή μš”μ†Œλ₯Ό μ œκ±°ν•œλ‹€.


예제 2: μ—¬λŸ¬ λ°°μ—΄μ˜ ꡐ집합

문제 링크

μ„œλ‘œ λ‹€λ₯Έ μ •μˆ˜λ“€λ‘œ 이루어진 n개의 배열을 ν¬ν•¨ν•œ 2차원 λ°°μ—΄ numsκ°€ μ£Όμ–΄μ§ˆ λ•Œ, λͺ¨λ“  배열에 κ³΅ν†΅μœΌλ‘œ λ‚˜νƒ€λ‚˜λŠ” μˆ«μžλ“€μ„ ν¬ν•¨ν•œ μ •λ ¬λœ n개의 배열을 λ°˜ν™˜ν•΄λ³΄μž.

예λ₯Ό λ“€μ–΄, nums = [[3,1,2,4,5],[1,2,3,4],[3,4,5,6]]이 주어진닀면, [3, 4]λ₯Ό λ°˜ν™˜ν•œλ‹€. 3κ³Ό 4λŠ” λͺ¨λ“  배열에 κ³΅ν†΅μœΌλ‘œ λ‚˜νƒ€λ‚˜λŠ” μœ μΌν•œ μˆ«μžλ“€μ΄λ‹€.

이 λ¬Έμ œμ—μ„œ 각 배열은 μ„œλ‘œ λ‹€λ₯Έ μ •μˆ˜λ“€μ„ ν¬ν•¨ν•œλ‹€κ³  ν•œλ‹€. μ΄λŠ” νŠΉμ • μˆ«μžκ°€ n번 λ‚˜νƒ€λ‚œλ‹€λ©΄ κ·Έ μˆ«μžκ°€ λͺ¨λ“  배열에 λ‚˜νƒ€λ‚˜κ³  μžˆμŒμ„ μ˜λ―Έν•œλ‹€.

ν•΄μ‹œ 맡 countsλ₯Ό ν™œμš©ν•˜μ—¬ μš”μ†Œλ“€μ˜ λΉˆλ„λ₯Ό μ„Έμ–΄λ³΄μž. 각 λ‚΄λΆ€ 배열을 μˆœνšŒν•˜λ©° countsλ₯Ό 각 μš”μ†Œλ‘œ μ—…λ°μ΄νŠΈν•œλ‹€. λͺ¨λ“  배열을 μˆœνšŒν•œ ν›„, ν•΄μ‹œ 맡을 톡해 n번 λ‚˜νƒ€λ‚˜λŠ” μˆ«μžλ“€μ„ μ°Ύμ•„λ‚Ό 수 μžˆλ‹€.

예제 2 상세 λ‚΄μš©

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
vector<int> intersection(vector<vector<int>>& nums) {
    unordered_map<int, int> counts;
    for (vector<int>& arr: nums) {
        for (int x: arr) {
            counts[x]++;
        }
    }
    
    int n = int(nums.size());
    vector<int> ans;
    for (auto [key, val]: counts) {
        if (val == n) {
            ans.push_back(key);
        }
    }
    
    sort(ans.begin(), ans.end());
    return ans;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fn intersection(nums: Vec<Vec<i32>>) -> Vec<i32> {
    let mut counts = HashMap::new();

    for arr in nums.iter() {
        for &x in arr {
            *counts.entry(x).or_insert(0) += 1;
        }
    }

    let n = nums.len() as i32;
    let mut ans: Vec<i32> = counts.into_iter()
        .filter(|&(_key, val)| val == n)
        .map(|(key, _val)| key)
        .collect();

    ans.sort_unstable();
    ans
}

ν•΄μ‹œ 맡을 μ‚¬μš©ν•˜λŠ” 것이 νŽΈλ¦¬ν•œ μ΄μœ κ°€ 이 λ¬Έμ œμ—μ„œ 잘 λ“œλŸ¬λ‚œλ‹€. ν‚€κ°€ μ •μˆ˜μΈλ° μ™œ λ°°μ—΄ λŒ€μ‹  ν•΄μ‹œ 맡을 μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”μ§€ μ˜λ¬Έμ„ κ°€μ§ˆ 수 μžˆλ‹€. 배열을 μ‚¬μš©ν•  μˆ˜λ„ μžˆμ§€λ§Œ, 배열은 μ΅œλŒ€ μš”μ†Œ 크기만큼 컀야 ν•œλ‹€. 예λ₯Ό λ“€μ–΄, [1, 2, 3, 1000] 같은 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€κ°€ μžˆλ‹€λ©΄, 1000 크기의 배열을 μ΄ˆκΈ°ν™”ν•΄μ•Ό ν•˜λ©°, μ‹€μ œ μ‚¬μš©λ˜λŠ” μΈλ±μŠ€λŠ” μ†Œμˆ˜μ— λΆˆκ³Όν•˜λ‹€. λ”°λΌμ„œ 배열을 μ‚¬μš©ν•˜λ©΄ 곡간이 크게 낭비될 수 μžˆλ‹€. ν•΄μ‹œ 맡은 λ•Œλ•Œλ‘œ μ˜€λ²„ν—€λ“œκ°€ μžˆμ„ 수 μžˆμ§€λ§Œ, μ „λ°˜μ μœΌλ‘œ 더 μ•ˆμ „ν•˜λ‹€. μž…λ ₯에 99999999999 같은 큰 μˆ«μžκ°€ μžˆμ–΄λ„ ν•΄μ‹œ 맡은 λ‹€λ₯Έ μš”μ†Œμ²˜λŸΌ 적절히 μ²˜λ¦¬ν•œλ‹€.

$n$개의 λ¦¬μŠ€νŠΈκ°€ 있고 각 λ¦¬μŠ€νŠΈμ— ν‰κ· μ μœΌλ‘œ $m$개의 μš”μ†Œκ°€ μžˆλ‹€κ³  κ°€μ •ν•˜μž. ν•΄μ‹œ 맡을 μ±„μš°λŠ” λ°λŠ” λͺ¨λ“  μš”μ†Œλ₯Ό μˆœνšŒν•˜λŠ” 데 $O(n \cdot m)$의 μ‹œκ°„μ΄ μ†Œμš”λœλ‹€. ans에 μ΅œλŒ€ $m$개의 μš”μ†Œκ°€ λ“€μ–΄κ°ˆ 수 μžˆμœΌλ―€λ‘œ, μ΅œμ•…μ˜ 경우 μ •λ ¬ν•˜λŠ” λ°λŠ” $O(m \cdot \log m)$의 μ‹œκ°„μ΄ λ“ λ‹€. λ”°λΌμ„œ μ‹œκ°„ λ³΅μž‘λ„λŠ” $O(n \cdot m + m \cdot \log m) = O(m \cdot (n + \log m))$이닀. μž…λ ₯의 λͺ¨λ“  μš”μ†Œκ°€ κ³ μœ ν•˜λ‹€λ©΄, ν•΄μ‹œ 맡은 $n \cdot m$ 크기둜 μ¦κ°€ν•˜λ―€λ‘œ, μ•Œκ³ λ¦¬μ¦˜μ˜ 곡간 λ³΅μž‘λ„λŠ” $O(n \cdot m)$이닀.


예제 3: λͺ¨λ“  λ¬Έμžκ°€ λ™μΌν•œ 횟수둜 λ°œμƒν•˜λŠ”μ§€ ν™•μΈν•˜κΈ°

문제 링크

λ¬Έμžμ—΄ sκ°€ μ£Όμ–΄μ‘Œμ„ λ•Œ, λͺ¨λ“  λ¬Έμžκ°€ λ™μΌν•œ λΉˆλ„λ‘œ λ‚˜νƒ€λ‚˜λŠ”μ§€ ν™•μΈν•΄λ³΄μž.

예λ₯Ό λ“€μ–΄, s = "abacbc"κ°€ 주어지면 λͺ¨λ“  λ¬Έμžκ°€ 두 번 λ‚˜νƒ€λ―€λ‘œ trueλ₯Ό λ°˜ν™˜ν•œλ‹€. 반면, s = "aaabb"κ°€ 주어지면 "a"λŠ” 3번, "b"λŠ” 2번 λ‚˜νƒ€λ‚˜κΈ° λ•Œλ¬Έμ— falseλ₯Ό λ°˜ν™˜ν•œλ‹€(3 != 2).

ν•΄μ‹œ 맡과 μ„ΈνŠΈμ˜ 지식을 ν™œμš©ν•˜λ©΄, 이 λ¬Έμ œλŠ” κ°„λ‹¨ν•˜κ²Œ ν•΄κ²°ν•  수 μžˆλ‹€. ν•΄μ‹œ 맡 countsλ₯Ό μ‚¬μš©ν•˜μ—¬ λͺ¨λ“  문자의 λΉˆλ„λ₯Ό μ„Έμ–΄λ³Έλ‹€. sλ₯Ό μˆœνšŒν•˜λ©° λͺ¨λ“  문자의 λΉˆλ„λ₯Ό μ–»λŠ”λ‹€. 그런 λ‹€μŒ λͺ¨λ“  λΉˆλ„κ°€ λ™μΌν•œμ§€ ν™•μΈν•œλ‹€.

μ„ΈνŠΈλŠ” 쀑볡을 λ¬΄μ‹œν•˜κΈ° λ•Œλ¬Έμ—, λͺ¨λ“  λΉˆλ„λ₯Ό μ„ΈνŠΈμ— λ„£κ³  길이가 1인지 ν™•μΈν•˜λ©΄ λͺ¨λ“  λΉˆλ„κ°€ 같은지 검증할 수 μžˆλ‹€.

예제 3 상세 μ„€λͺ…

μ„ΈνŠΈλŠ” λΉˆλ„λ₯Ό λ¬΄μ‹œν•œλ‹€λŠ” 사싀을 κΈ°μ–΅ν•˜μž. 같은 μš”μ†Œλ₯Ό μ„ΈνŠΈμ— 100번 좔가해도 첫 번째 μž‘μ—…λ§Œ μš”μ†Œλ₯Ό μΆ”κ°€ν•˜κ³  λ‚˜λ¨Έμ§€λŠ” 아무 영ν–₯을 λ―ΈμΉ˜μ§€ μ•ŠλŠ”λ‹€.

이 λ¬Έμ œμ—μ„œλŠ” ν•˜λ‚˜μ˜ 고유 λΉˆλ„λ§Œ μ‘΄μž¬ν•˜λŠ”μ§€ νŒλ‹¨ν•˜λ €κ³  ν•œλ‹€. λ¨Όμ € ν•΄μ‹œ 맡을 μ‚¬μš©ν•˜μ—¬ 각 문자의 λΉˆλ„λ₯Ό μ„Έμ–΄λ³Έλ‹€. μ„ΈλŠ” μž‘μ—…μ΄ λλ‚œ ν›„, ν•΄μ‹œ 맡의 값듀은 μš°λ¦¬κ°€ μ°ΎλŠ” λΉˆλ„κ°€ λœλ‹€.

λ§Œμ•½ ν•˜λ‚˜μ˜ 고유 λΉˆλ„λ§Œ μžˆλ‹€λ©΄, λͺ¨λ“  값을 μ„ΈνŠΈμ— μΆ”κ°€ν•œ ν›„ μ„ΈνŠΈμ˜ κΈΈμ΄λŠ” 1이 될 것이닀. λ‹€λ₯Έ λΉˆλ„λ₯Ό 가진 λ¬Έμžκ°€ μžˆλ‹€λ©΄ μ„ΈνŠΈμ˜ κΈΈμ΄λŠ” 1보닀 컀질 것이닀. μ΄λŠ” μ„ΈνŠΈκ°€ λͺ¨λ“  고유 λΉˆλ„λ₯Ό ν¬ν•¨ν•˜κ²Œ 되기 λ•Œλ¬Έμ΄λ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
bool areOccurrencesEqual(string s) {
    unordered_map<char, int> counts;
    for (char c: s) {
        counts[c]++;
    }
    
    unordered_set<int> frequencies;
    for (auto [key, val]: counts) {
        frequencies.insert(val);
    }
    
    return frequencies.size() == 1;
}
1
2
3
4
5
6
7
8
9
10
11
fn are_occurrences_equal(s: &str) -> bool {
    let mut counts: HashMap<char, i32> = HashMap::new();

    for c in s.chars() {
        *counts.entry(c).or_insert(0) += 1;
    }

    let frequencies: HashSet<&i32> = counts.values().collect();

    frequencies.len() == 1
}

s의 길이λ₯Ό $n$이라고 ν•  λ•Œ, ν•΄μ‹œ 맡을 μ±„μš°λŠ” 데 $O(n)$의 λΉ„μš©μ΄ λ“ λ‹€. κ·Έ λ‹€μŒ, ν•΄μ‹œ 맡의 값듀을 μ„ΈνŠΈλ‘œ λ³€ν™˜ν•˜λŠ” 데 $O(n)$이 μ†Œμš”λœλ‹€. λ”°λΌμ„œ μ‹œκ°„ λ³΅μž‘λ„λŠ” $O(n)$이닀. ν•΄μ‹œ 맡과 μ„ΈνŠΈκ°€ μ°¨μ§€ν•˜λŠ” 곡간은 고유 문자의 μˆ˜μ— ν•΄λ‹Ήν•œλ‹€. 이전에 λ…Όμ˜λœ 바와 같이, 일뢀 μ‚¬λžŒλ“€μ€ μ˜μ–΄ μ•ŒνŒŒλ²³μ—μ„œ μœ λž˜ν•œ λ¬Έμžλ“€μ΄κΈ° λ•Œλ¬Έμ— 이λ₯Ό $O(1)$이라고 μ£Όμž₯ν•œλ‹€. 보닀 일반적인 λŒ€λ‹΅μ€ 곡간 λ³΅μž‘λ„κ°€ $O(k)$라고 λ§ν•˜λŠ” 것이닀. μ—¬κΈ°μ„œ $k$λŠ” μž…λ ₯에 포함될 수 μžˆλŠ” 문자의 수둜, 이 λ¬Έμ œμ—μ„œλŠ” 26이닀.


β€œμ •ν™•ν•œβ€ μ œμ•½ 쑰건을 가진 λΆ€λΆ„ λ°°μ—΄μ˜ 수 κ³„μ‚°ν•˜κΈ°

μš°λ¦¬λŠ” 이전 μŠ¬λΌμ΄λ”© μœˆλ„μš° κ΄€λ ¨ κΈ€μ—μ„œ, β€œμ œμ•½ 쑰건에 λ§žλŠ” λΆ€λΆ„ λ°°μ—΄/λΆ€λΆ„ λ¬Έμžμ—΄μ˜ 수λ₯Ό μ°ΎλŠ” νŒ¨ν„΄β€μ— λŒ€ν•΄ λ…Όμ˜ν–ˆλ‹€. 이런 μœ ν˜•μ˜ λ¬Έμ œμ—μ„œλŠ” left와 right μ‚¬μ΄μ˜ μœˆλ„μš°κ°€ μ œμ•½ 쑰건을 λ§Œμ‘±ν•œλ‹€λ©΄, left < x <= right λ²”μœ„ λ‚΄μ˜ λͺ¨λ“  xμ—μ„œ rightκΉŒμ§€μ˜ μœˆλ„μš°λ„ 같은 μ œμ•½ 쑰건을 λ§Œμ‘±ν•œλ‹€.

μ΄λ²ˆμ—λŠ” 더 μ—„κ²©ν•œ μ œμ•½ 쑰건을 가진 λ¬Έμ œλ“€μ„ μ‚΄νŽ΄λ³Ό 것이닀. 이전에 μ–ΈκΈ‰λœ 속성이 λ°˜λ“œμ‹œ 참일 ν•„μš”λŠ” μ—†λ‹€.

예λ₯Ό λ“€μ–΄, β€œμ–‘μˆ˜λ§Œ μžˆλŠ” μž…λ ₯에 λŒ€ν•΄ k보닀 μž‘μ€ 합을 가진 λΆ€λΆ„ λ°°μ—΄μ˜ 수λ₯Ό μ°ΎλŠ”β€ λ¬Έμ œλŠ” μŠ¬λΌμ΄λ”© μœˆλ„μš°λ‘œ ν•΄κ²°ν•  수 μžˆλ‹€. 이 μ„Ήμ…˜μ—μ„œλŠ” β€œμ •ν™•νžˆ k와 같은 합을 가진 λΆ€λΆ„ λ°°μ—΄μ˜ 수λ₯Ό μ°ΎλŠ”β€ 같은 μ§ˆλ¬Έμ„ λ‹€λ£° 것이닀.

μ²˜μŒμ— 이 λ¬Έμ œλ“€μ€ 맀우 μ–΄λ €μ›Œ 보일 수 μžˆλ‹€. ν•˜μ§€λ§Œ 이 νŒ¨ν„΄μ„ 배우고 λ‚˜λ©΄ 맀우 간단해지며, 이 νŒ¨ν„΄μ— μ†ν•˜λŠ” 각 문제의 μ½”λ“œκ°€ μ–Όλ§ˆλ‚˜ μœ μ‚¬ν•œμ§€ μ•Œ 수 μžˆλ‹€. μ•Œκ³ λ¦¬μ¦˜μ„ μ΄ν•΄ν•˜κΈ° μœ„ν•΄μ„œλŠ” ꡬ간 ν•©μ˜ κ°œλ…μ„ λ‹€μ‹œ 생각해볼 ν•„μš”κ°€ μžˆλ‹€.

ꡬ간 합을 μ‚¬μš©ν•˜λ©΄, 두 ꡬ간 ν•©μ˜ 차이둜 λΆ€λΆ„ λ°°μ—΄μ˜ 합을 찾을 수 μžˆλ‹€. k와 μ •ν™•νžˆ 같은 합을 가진 λΆ€λΆ„ 배열을 찾고자 ν•œλ‹€κ³  κ°€μ •ν•΄λ³΄μž. λ˜ν•œ μž…λ ₯의 ꡬ간 합을 가지고 μžˆλ‹€κ³  ν•˜μž. ꡬ간 ν•©μ—μ„œ k와 같은 차이가 λ‚˜νƒ€λ‚˜λŠ” λͺ¨λ“  κ²½μš°κ°€ k와 같은 합을 가진 λΆ€λΆ„ 배열을 λ‚˜νƒ€λ‚Έλ‹€. κ·Έλ ‡λ‹€λ©΄ μ΄λŸ¬ν•œ 차이듀을 μ–΄λ–»κ²Œ μ°Ύμ„κΉŒ?

λ¨Όμ € ꡬ간 합이 μ–Όλ§ˆλ‚˜ 자주 λ°œμƒν•˜λŠ”μ§€ λ§€ν•‘ν•˜λŠ” ν•΄μ‹œ 맡 countsλ₯Ό μ„ μ–Έν•œλ‹€. 이 ν•΄μ‹œ 맡은 ꡬ간 합을 μ–Όλ§ˆλ‚˜ 자주 λ°œμƒν•˜λŠ”μ§€ κΈ°λ‘ν•œλ‹€(μž…λ ₯에 μŒμˆ˜κ°€ μžˆλŠ” 경우, μˆ«μžκ°€ ꡬ간 ν•©μ—μ„œ μ—¬λŸ¬ 번 λ‚˜νƒ€λ‚  수 μžˆλ‹€). counts[0] = 1둜 μ΄ˆκΈ°ν™”ν•΄μ•Ό ν•œλ‹€. μ΄λŠ” 빈 ꡬ간 []의 합이 0이기 λ•Œλ¬Έμ΄λ‹€.

λ‹€μŒμœΌλ‘œ, 닡을 μ €μž₯ν•  λ³€μˆ˜μ™€ currλ₯Ό μ„ μ–Έν•œλ‹€. μž…λ ₯을 μˆœνšŒν•˜λ©΄μ„œ, currλŠ” μ§€κΈˆκΉŒμ§€ μˆœνšŒν•œ λͺ¨λ“  μš”μ†Œλ“€μ˜ 합을 λ‚˜νƒ€λ‚Ό 것이닀.

μž…λ ₯을 μˆœνšŒν•˜λŠ” λ™μ•ˆ, 각 μš”μ†Œμ—μ„œ currλ₯Ό μ—…λ°μ΄νŠΈν•˜κ³  counts도 ν•¨κ»˜ μ—…λ°μ΄νŠΈν•œλ‹€. countsλ₯Ό μ—…λ°μ΄νŠΈν•˜κΈ° 전에 λ¨Όμ € 닡을 μ—…λ°μ΄νŠΈν•΄μ•Ό ν•œλ‹€.

닡을 μ–΄λ–»κ²Œ μ—…λ°μ΄νŠΈν• κΉŒ? μŠ¬λΌμ΄λ”© μœˆλ„μš° κ΄€λ ¨ κΈ€μ—μ„œ β€œλΆ€λΆ„ λ°°μ—΄μ˜ μˆ˜β€λ₯Ό 찾을 λ•Œ, 각 μΈλ±μŠ€μ— μ§‘μ€‘ν•˜κ³  ν˜„μž¬ μΈλ±μŠ€μ—μ„œ λλ‚˜λŠ” μœ νš¨ν•œ λΆ€λΆ„ 배열이 μ–Όλ§ˆλ‚˜ μžˆλŠ”μ§€ νŒŒμ•…ν–ˆλ‹€. μ—¬κΈ°μ„œλ„ 같은 방식을 μ‚¬μš©ν•œλ‹€. 인덱슀 i에 λ„λ‹¬ν–ˆλ‹€κ³  κ°€μ •ν•˜μž. 이 μ‹œμ κΉŒμ§€ currλŠ” iκΉŒμ§€μ˜ λͺ¨λ“  μš”μ†Œλ“€μ˜ ꡬ간 합을 μ €μž₯ν•˜κ³  μžˆλ‹€. λ˜ν•œ i μ΄μ „μ˜ λͺ¨λ“  λ‹€λ₯Έ ꡬ간 합듀을 counts에 μ €μž₯ν–ˆλ‹€. λ”°λΌμ„œ iμ—μ„œ λλ‚˜λŠ” k와 같은 합을 가진 λΆ€λΆ„ 배열이 μžˆλ‹€λ©΄, curr - kλŠ” 이전에 이미 λ‚˜νƒ€λ‚¬μ–΄μ•Ό ν•œλ‹€.

ꡬ간 ν•©μ˜ 차이둜 λΆ€λΆ„ λ°°μ—΄μ˜ 합을 μ°ΎλŠ”λ‹€λŠ” 것을 κΈ°μ–΅ν•˜μž. λ§Œμ•½ curr - kκ°€ 이 μ‹œμ  이전에 ꡬ간 ν•©μœΌλ‘œ μ‘΄μž¬ν–ˆλ‹€λ©΄, ν˜„μž¬ ꡬ간 합이 curr일 λ•Œ, 이 두 ꡬ간 ν•©μ˜ μ°¨μ΄λŠ” curr - (curr - k) = k둜, μš°λ¦¬κ°€ 찾고자 ν•˜λŠ” μ •ν™•ν•œ 값이 λœλ‹€.

λ”°λΌμ„œ 닡은 counts[curr - k]둜 μ¦κ°€ν•œλ‹€. λ§Œμ•½ curr - k ꡬ간이 이전에 μ—¬λŸ¬ 번 λ‚˜νƒ€λ‚¬λ‹€λ©΄, 각각의 ꡬ간을 μ‹œμž‘μ μœΌλ‘œ μ‚¬μš©ν•˜μ—¬ ν˜„μž¬ μΈλ±μŠ€μ—μ„œ λλ‚˜λŠ” k 합을 가진 λΆ€λΆ„ 배열을 ν˜•μ„±ν•  수 μžˆλ‹€. κ·Έλ ‡κΈ° λ•Œλ¬Έμ— λΉˆλ„λ₯Ό μΆ”μ ν•˜λŠ” 것이 μ€‘μš”ν•˜λ‹€.


예제 4: 합이 K인 λΆ€λΆ„ λ°°μ—΄μ˜ 수 κ³„μ‚°ν•˜κΈ°

문제 링크

μ •μˆ˜ λ°°μ—΄ nums와 μ •μˆ˜ kκ°€ μ£Όμ–΄μ‘Œμ„ λ•Œ, 합이 k인 λΆ€λΆ„ λ°°μ—΄μ˜ 수λ₯Ό κ³„μ‚°ν•΄λ³΄μž.

이 문제λ₯Ό μ΄ν•΄ν•˜κΈ° μœ„ν•΄ μ˜ˆμ‹œλ₯Ό 톡해 μ•Œκ³ λ¦¬μ¦˜μ„ μ‚΄νŽ΄λ³΄μž. 예λ₯Ό λ“€μ–΄, nums = [1, 2, 1, 2, 1], k = 3인 경우λ₯Ό μƒκ°ν•΄λ³΄μž. 합이 3인 λΆ€λΆ„ 배열은 총 λ„€ κ°œκ°€ μžˆλ‹€ - [1, 2]κ°€ 두 번, [2, 1]이 두 λ²ˆμ΄λ‹€.

이 μž…λ ₯에 λŒ€ν•œ ꡬ간 합은 μˆœνšŒν•˜λŠ” λ™μ•ˆ currκ°€ λ‚˜νƒ€λ‚΄λŠ” κ²ƒμœΌλ‘œ, [1, 3, 4, 6, 7]이닀. 이 λ°°μ—΄μ—μ„œ 3μ΄λΌλŠ” μ°¨μ΄λŠ” μ„Έ 번 λ‚˜νƒ€λ‚œλ‹€: (4 - 1), (6 - 3), (7 - 4).

ν•˜μ§€λ§Œ μœ νš¨ν•œ λΆ€λΆ„ 배열이 λ„€ 개라고 ν–ˆλŠ”λ° μ–΄λ–»κ²Œ 이해할 수 μžˆμ„κΉŒ? ν•΄μ‹œ 맡을 0: 1둜 μ΄ˆκΈ°ν™”ν•΄μ•Ό ν•œλ‹€λŠ” 것을 κΈ°μ–΅ν•΄μ•Ό ν•œλ‹€. μ΄λŠ” k와 같은 합을 가진 ꡬ간이 μžˆλ‹€λ©΄, 0: 1을 μ΄ˆκΈ°ν™”ν•˜μ§€ μ•ŠμœΌλ©΄ curr - k = 0이 ν•΄μ‹œ 맡에 λ‚˜νƒ€λ‚˜μ§€ μ•Šμ•„ μœ νš¨ν•œ λΆ€λΆ„ 배열을 놓칠 수 있기 λ•Œλ¬Έμ΄λ‹€.

λ”°λΌμ„œ 인덱슀 1, 2, 3, 4μ—μ„œ curr - kκ°€ 이전에 λ‚˜νƒ€λ‚¬μŒμ„ μ•Œ 수 μžˆλ‹€. λͺ¨λ“  μš”μ†Œκ°€ μ–‘μˆ˜μ΄λ―€λ‘œ curr - k 값은 각각 ν•œ λ²ˆμ”©λ§Œ λ‚˜νƒ€λ‚œλ‹€. κ·ΈλŸ¬λ―€λ‘œ 닡은 4κ°€ λœλ‹€.

예제 4 상세 μ„€λͺ…

1
2
3
4
5
6
7
8
9
10
11
12
13
int subarraySum(vector<int>& nums, int k) {
    unordered_map<int, int> counts;
    counts[0] = 1;
    int ans = 0, curr = 0;
    
    for (int num: nums) {
        curr += num;
        ans += counts[curr - k];
        counts[curr]++;
    }
    
    return ans;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
fn subarray_sum(nums: &[i32], k: i32) -> i32 {
    let mut counts = HashMap::new();

    counts.insert(0, 1);
    let (mut ans, mut curr) = (0, 0);

    for &num in nums {
        curr += num;
        ans += counts.get(&(curr - k)).unwrap_or(&0);
        *counts.entry(curr).or_insert(0) += 1;
    }

    ans
}

currκ°€ 계속 μ¦κ°€ν•œλ‹€λ©΄ ν•΄μ‹œ 맡의 값은 1을 λ„˜μ§€ μ•ŠμœΌλ―€λ‘œ μ„ΈνŠΈλ§Œ μ‚¬μš©ν•˜λ©΄ λ˜μ§€ μ•Šμ„κΉŒ 생각할 수 μžˆλ‹€. ν•˜μ§€λ§Œ μ œμ•½ 쑰건은 -1000 <= nums[i] <= 1000이닀. 예λ₯Ό λ“€μ–΄, nums = [1, -1, 1, -1], k = 0인 경우λ₯Ό μ‚΄νŽ΄λ³΄μž. λ„€ 개의 μœ νš¨ν•œ λΆ€λΆ„ 배열이 μžˆλ‹€: [1, -1] 두 번, [-1, 1] ν•œ 번, 전체 λ°°μ—΄ [1, -1, 1, -1].

ꡬ간 합은 [1, 0, 1, 0]이닀. λ§ˆμ§€λ§‰ μΈλ±μŠ€μ—μ„œ λλ‚˜λŠ” 두 개의 λΆ€λΆ„ 배열이 μžˆλ‹€ - [1, -1]κ³Ό 전체 λ°°μ—΄. counts[0] = 1둜 μ΄ˆκΈ°ν™”ν–ˆκΈ° λ•Œλ¬Έμ—, 두 번째 인덱슀 μ΄ν›„μ—λŠ” counts[0] = 2κ°€ λœλ‹€. λ”°λΌμ„œ λ§ˆμ§€λ§‰ μΈλ±μŠ€μ— λ„λ‹¬ν•˜κ³  ans += counts[curr - k] = ans += counts[0]λ₯Ό μˆ˜ν–‰ν•˜λ©΄, 두 λΆ€λΆ„ 배열을 닡에 μΆ”κ°€ν•œλ‹€. μž…λ ₯에 μŒμˆ˜κ°€ ν¬ν•¨λ˜μ–΄ μžˆμ„ λ•Œ, λ™μΌν•œ ꡬ간 합이 μ—¬λŸ¬ 번 λ‚˜νƒ€λ‚  수 있으며, λΉˆλ„λ₯Ό κ³„μ‚°ν•˜κΈ° μœ„ν•΄ ν•΄μ‹œ 맡이 ν•„μš”ν•˜λ‹€.

μš”μ•½ν•˜μžλ©΄:

  • currλ₯Ό μ‚¬μš©ν•˜μ—¬ ꡬ간 합을 μΆ”μ ν•œλ‹€.
  • μ–΄λ–€ 인덱슀 iμ—μ„œ, iκΉŒμ§€μ˜ 합은 curr이닀. λ§Œμ•½ 인덱슀 j의 ꡬ간 합이 curr - k라면, j + 1λΆ€ν„° iκΉŒμ§€μ˜ λΆ€λΆ„ λ°°μ—΄μ˜ 합은 curr - (curr - k) = kκ°€ λœλ‹€.
  • 배열에 μŒμˆ˜κ°€ μžˆμ„ 수 있기 λ•Œλ¬Έμ—, λ™μΌν•œ ꡬ간 합이 μ—¬λŸ¬ 번 λ‚˜νƒ€λ‚  수 μžˆλ‹€. ν•΄μ‹œ 맡 countsλ₯Ό μ‚¬μš©ν•˜μ—¬ ꡬ간 합이 λͺ‡ 번 λ‚˜νƒ€λ‚¬λŠ”μ§€ μΆ”μ ν•œλ‹€.
  • λͺ¨λ“  인덱슀 iμ—μ„œ, curr - k의 λΉˆλ„λŠ” k와 같은 합을 가진 λΆ€λΆ„ λ°°μ—΄μ˜ μˆ˜μ™€ κ°™μœΌλ©°, μ΄λŠ” iμ—μ„œ λλ‚œλ‹€. 이λ₯Ό 닡에 λ”ν•œλ‹€.

이 μ•Œκ³ λ¦¬μ¦˜μ˜ μ‹œκ°„ λ³΅μž‘λ„μ™€ 곡간 λ³΅μž‘λ„λŠ” λͺ¨λ‘ $O(n)$이닀. μ—¬κΈ°μ„œ $n$은 nums의 길이이닀. 각 for λ¬Έ λ°˜λ³΅μ€ μƒμˆ˜ μ‹œκ°„μ— μ‹€ν–‰λ˜λ©°, ν•΄μ‹œ 맡은 μ΅œλŒ€ $n$개의 μš”μ†Œλ‘œ μ„±μž₯ν•  수 μžˆλ‹€.


예제 5: 쒋은 λΆ€λΆ„ λ°°μ—΄μ˜ 수 μ„ΈκΈ°

문제 링크

μ–‘μ˜ μ •μˆ˜ λ°°μ—΄ nums와 μ •μˆ˜ kκ°€ μ£Όμ–΄μ‘Œμ„ λ•Œ, μ •ν™•νžˆ k개의 ν™€μˆ˜λ₯Ό ν¬ν•¨ν•˜λŠ” λΆ€λΆ„ λ°°μ—΄μ˜ 수λ₯Ό μ°Ύμ•„λ³΄μž.

예λ₯Ό λ“€μ–΄, nums = [1, 1, 2, 1, 1], k = 3인 경우, 닡은 2κ°œμ΄λ‹€. 3개의 ν™€μˆ˜λ₯Ό ν¬ν•¨ν•˜λŠ” λΆ€λΆ„ 배열은 [1, 1, 2, 1]κ³Ό [1, 2, 1, 1] 두 가지이기 λ•Œλ¬Έμ΄λ‹€.

이전 μ˜ˆμ œμ—μ„œ μ œμ•½ 쑰건은 ν•©μ΄μ—ˆκ³ , curr은 ꡬ간 합을 λ‚˜νƒ€λƒˆλ‹€. 이 λ¬Έμ œμ—μ„œλŠ” μ œμ•½ 쑰건이 ν™€μˆ˜μ˜ κ°œμˆ˜μ΄λ―€λ‘œ, curr은 ν™€μˆ˜μ˜ 수λ₯Ό μΆ”μ ν•œλ‹€. 각 μš”μ†Œμ—μ„œ curr - kλ₯Ό λ‹€μ‹œ μ‘°νšŒν•  수 μžˆλ‹€. 예제 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€μ—μ„œ, λ§ˆμ§€λ§‰ μΈλ±μŠ€μ—μ„œ curr = 4이닀. μ΄λŠ” 배열에 4개의 ν™€μˆ˜κ°€ μžˆμŒμ„ μ˜λ―Έν•œλ‹€. 첫 번째 μΈλ±μŠ€μ—μ„œ curr = 1이닀. 4 - 1 = 3이고, 인덱슀 1μ—μ„œ 4κΉŒμ§€μ˜ λΆ€λΆ„ 배열은 λ‹΅ 쀑 ν•˜λ‚˜μ΄λ‹€([1, 2, 1, 1]).

μˆ˜κ°€ ν™€μˆ˜μΈμ§€ ν™•μΈν•˜κΈ° μœ„ν•΄μ„œλŠ” ν•΄λ‹Ή 수λ₯Ό 2둜 λ‚˜λˆˆ λ‚˜λ¨Έμ§€λ₯Ό μ·¨ν•˜λ©΄ λœλ‹€. xκ°€ ν™€μˆ˜λΌλ©΄, x % 2 = 1이닀.

예제 5 상세 μ„€λͺ…

μŠ¬λΌμ΄λ”© μœˆλ„μš°λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šμ§€λ§Œ, β€œμœ νš¨ν•œβ€ λΆ€λΆ„ 배열을 μ°ΎλŠ” κ²ƒμ—λŠ” 같은 아이디어λ₯Ό μ μš©ν•  수 μžˆλ‹€.

이전 μ˜ˆμ œμ—μ„œ μ œμ•½ 쑰건은 β€œλΆ€λΆ„ λ°°μ—΄μ˜ ν•©β€μ΄μ—ˆκ³ , 수치적 μ œν•œμ€ k와 κ°™μ•„μ•Ό ν–ˆλ‹€.

이 λ¬Έμ œμ—μ„œλŠ” μ œμ•½ 쑰건이 β€œλΆ€λΆ„ λ°°μ—΄ λ‚΄ ν™€μˆ˜μ˜ κ°œμˆ˜β€μ΄λ©°, 수치적 μ œν•œλ„ k와 κ°™λ‹€.

μ—¬κΈ°μ„œ ꡬ간 합을 μ’€ 더 창의적으둜 ν™œμš©ν•΄μ•Ό ν•œλ‹€. curr을 ꡬ간 ν•©μœΌλ‘œ μ‚¬μš©ν•˜λŠ” λŒ€μ‹ , ν˜„μž¬ κ΅¬κ°„μ—μ„œ κ΄€μ°°λœ ν™€μˆ˜μ˜ 수λ₯Ό μΆ”μ ν•œλ‹€. 이λ₯Ό β€œκ΅¬κ°„ ν™€μˆ˜ κ°œμˆ˜β€λΌκ³  λΆ€λ₯Ό 수 μžˆλ‹€. λ§Œμ•½ curr - kκ°€ μ‘΄μž¬ν•œλ‹€λ©΄, 이전에 curr - k개의 ν™€μˆ˜λ₯Ό 가진 ꡬ간이 μžˆμ—ˆλ‹€λŠ” λœ»μ΄λ‹€. ν˜„μž¬ κ΅¬κ°„μ—λŠ” curr개의 ν™€μˆ˜κ°€ μžˆλ‹€. 이 두 ꡬ간 μ‚¬μ΄μ˜ μ°¨μ΄λŠ” ꡬ간 μ‚¬μ΄μ˜ ν™€μˆ˜ 개수λ₯Ό λ‚˜νƒ€λ‚΄λ©°, curr - (curr - k) = k개의 ν™€μˆ˜κ°€ λœλ‹€.

μˆ˜κ°€ ν™€μˆ˜μΈ 경우 2둜 λ‚˜λˆˆ λ‚˜λ¨Έμ§€κ°€ 1이 λœλ‹€. 그렇지 μ•ŠμœΌλ©΄ 0이 λœλ‹€. λ”°λΌμ„œ 각 μˆ˜μ— λŒ€ν•΄ curr += num % 2λ₯Ό μˆ˜ν–‰ν•  수 μžˆλ‹€.

μ—¬κΈ°μ„œλΆ€ν„° λͺ¨λ“  것이 μ™„μ „νžˆ λ™μΌν•˜κ²Œ μž‘λ™ν•œλ‹€. μ‹€μ œλ‘œ, 두 문제의 μ½”λ“œλ₯Ό 비ꡐ해보면 μ°¨μ΄λŠ” "% 2" 두 κΈ€μžλΏμ΄λ‹€. λ‹€μŒ λ³΄λ„ˆμŠ€ λ¬Έμ œλ“€μ„ 직접 풀어보며 이 κΈ€μ—μ„œ 배운 지식을 μ μš©ν•΄λ³΄μž.

1
2
3
4
5
6
7
8
9
10
11
12
13
int numberOfSubarrays(vector<int>& nums, int k) {
    unordered_map<int, int> counts;
    counts[0] = 1;
    int ans = 0, curr = 0;
    
    for (int num: nums) {
        curr += num % 2;
        ans += counts[curr - k];
        counts[curr] += 1;
    }
    
    return ans;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
fn number_of_subarrays(nums: &[i32], k: i32) -> i32 {
    let mut counts = HashMap::new();
    counts.insert(0, 1);
    let (mut ans, mut curr) = (0, 0);

    for &num in nums {
        curr += num % 2;
        ans += *counts.get(&(curr - k)).unwrap_or(&0);
        *counts.entry(curr).or_insert(0) += 1;
    }

    ans
}

β€œμ΄ νŒ¨ν„΄μ— μ†ν•˜λŠ” 각 문제의 μ½”λ“œκ°€ μ–Όλ§ˆλ‚˜ λΉ„μŠ·ν•œμ§€ μ•Œ 수 μžˆμ„ 것”이라고 λ§μ”€λ“œλ Έλ˜ 것을 κΈ°μ–΅ν•˜λŠ”κ°€? 두 가지 λ‹€λ₯Έ λ¬Έμ œμ™€ μ½”λ“œμ˜ μ°¨μ΄λŠ” 말 κ·ΈλŒ€λ‘œ β€œ% 2β€œλΌλŠ” 두 κΈ€μžλΏμ΄λ‹€. λ‹€μŒ λͺ‡ 가지 μ—°μŠ΅ 문제λ₯Ό 직접 ν’€μ–΄λ³΄λ©΄μ„œ 이 κΈ€μ—μ„œ 배운 지식을 μ μš©ν•΄ 보자.

이 μ•Œκ³ λ¦¬μ¦˜μ˜ μ‹œκ°„ λ³΅μž‘λ„μ™€ 곡간 λ³΅μž‘λ„λŠ” 이전 λ¬Έμ œμ™€ κ°™λ‹€($O(n)$). κ·Έ μ΄μœ λ„ λ™μΌν•˜λ‹€.


λ³΄λ„ˆμŠ€ 문제


좜처: Leetcode

이 ν¬μŠ€νŠΈλŠ” μ €μž‘κΆŒμžμ˜ CC BY-NC-ND 4.0 λΌμ΄μ„ΌμŠ€λ₯Ό λ”°λ¦…λ‹ˆλ‹€.
졜근 μ—…λ°μ΄νŠΈ
λ°”λ‘œκ°€κΈ°

[DSA] μš”μ†Œμ˜ 쑴재 μ—¬λΆ€ 확인

[DSA] ν•΄μ‹œ 맡을 ν™œμš©ν•œ μΆ”κ°€ 예제