[LeetCode]Longest Consecutive Sequence

Icarus<Wing>ยท2025๋…„ 4์›” 22์ผ
post-thumbnail

https://leetcode.com/problems/longest-consecutive-sequence/description/

๐Ÿ“œ๋ฌธ์ œ ํ•ด์„

intํ˜• nums ๋ฐฐ์—ด์ด ์ •๋ ฌ๋˜์ง€ ์•Š์€ ์ฑ„๋กœ ์ฃผ์–ด์กŒ์„ ๋•Œ, ์—ฐ์†์ ์ธ ์›์†Œ ์‹œํ€€์Šค์˜ ๊ธธ์ด๋ฅผ ๋ฆฌํ„ดํ•˜๋ผ.(๋‹จ, O(N) ๋‚ด์— ๋Ÿฐํƒ€์ž„์„ ๊ตฌ์„ฑํ•ด์•ผ ํ•œ๋‹ค. -> sort ์“ฐ์ง€ ๋ง๋ผ๋Š” ๋œป!)

๐Ÿšง์ œ์•ฝ ์กฐ๊ฑด
0 <= nums.length <= 10^5 => longest_length = 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•˜๋ผ๋Š” ๋œป
-10^9 <= nums[i] <= 10^9 => ์ตœ์†Ÿ๊ฐ’์„ ์ฐพ์œผ์‹œ์˜ค

โš™๏ธ์ฝ”๋“œ ์„ค๊ณ„

  1. ๋จผ์ € map์— <Integer, Boolean> ํ˜•ํƒœ๋กœ nums์— ์žˆ๋Š” ๋ชจ๋“  ์›์†Œ๋ฅผ ์ €์žฅํ•œ๋‹ค.
    ๐Ÿ‘‰๊ทธ๋ž˜์•ผ containsKey()๋กœ ๊ฒ€์‚ฌํ•ด์„œ ์‹œํ€€์Šค๋ฅผ ๋ฝ‘์•„๋‚ผ ์ˆ˜ ์žˆ์Œ
    1.1. ์ œ์•ฝ ์กฐ๊ฑด์— ์˜ํ•ด ์ตœ์†Ÿ๊ฐ’์„ ์„ธํŒ…ํ•ด์•ผ ๋˜๋Š”๋ฐ, ์ด๋ฅผ ์œ„ํ•ด min_val์„ Integer.MAX_VALUE๋กœ ์„ค์ •ํ•˜๊ณ  Math.min() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ตœ์†Ÿ๊ฐ’์„ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.
  2. map.containsKey(min_val)์ด ์ฐธ์ด๋ฉด map์— ์žˆ๋Š” ๊ธฐ์กด์˜ min_val์„ ์ œ๊ฑฐํ•˜๊ณ  min_val์„ 1์”ฉ ์ฆ๊ฐ€์‹œ์ผœ์„œ key chaining์„ ์‚ฌ์šฉํ•ด์„œ sequence๋ฅผ ๋ฝ‘์•„๋‚ธ๋‹ค.
  3. ์ตœ์ข…์ ์œผ๋กœ longest_length๋ฅผ ๋ฆฌํ„ด

๐Ÿ’ป์ฝ”๋“œ ๊ตฌํ˜„

public class LcsSolution {
    public int longestConsecutive(int[] nums) {
        HashMap<Integer, Boolean> map = new HashMap<>();
        List<Integer> keyStack = new ArrayList<>();
        int longest_length = 0; // due to zero of nums.length
        int min_val = Integer.MAX_VALUE;

        // nums์˜ ๊ธธ์ด๊ฐ€ 0์ด๋ฉด ๊ทธ๋Œ€๋กœ ๋ฆฌํ„ด
        if (nums.length == 0) {
            return longest_length;
        }
        // ๋ฐฐ์—ด -> Set(์ค‘๋ณต๋˜๋Š” ์š”์†Œ ์ œ๊ฑฐํ•˜๊ธฐ ์œ„ํ•จ)
        Set<Integer> numSet = Arrays.stream(nums)
                .boxed() // int -> Integer
                .collect(Collectors.toSet());

        // ๋จผ์ € nums[i]๋ฅผ ๋ชจ๋‘ ์ €์žฅ && ์ตœ์†Ÿ๊ฐ’ ์„ค์ •
        for (int i : numSet) {
            map.put(i, true);
            min_val = Math.min(i, min_val);
        }

        for (int i = 0; i < map.size(); i++) {
            if (map.isEmpty()) {
                break;
            }
            while (map.containsKey(min_val)) {
                map.remove(min_val); // for key chaining
                min_val += 1;
                longest_length += 1; // for return consecutive length
            }
            keyStack.add(longest_length);
            longest_length = 0; // ๋‹ค์‹œ 0์œผ๋กœ ์ดˆ๊ธฐํ™”

            //! ๋˜‘๊ฐ™์ด ์™ธ๋ถ€ ๋ฃจํ”„ ๋‚ด์—์„œ ๋ฐ˜๋ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ตœ์ข…์ ์œผ๋กœ O(N^2)์ด ๊ฑธ๋ฆผ
            min_val = Integer.MAX_VALUE;
            for (Integer key : map.keySet()) {
                if (key < min_val) {
                    min_val = key;
                }
            }
        }

        // longest_length ์ตœ๋Œ“๊ฐ’์„ ๋ฆฌํ„ด
        int max_val = Integer.MIN_VALUE;
        for (int num : keyStack) {
            max_val = Math.max(num, max_val);
        }
        
        return max_val;
    }
}

๐Ÿšฉ์ด ์ฝ”๋“œ์˜ ๋ฌธ์ œ์ ์€ ์™ธ๋ถ€ ๋ฃจํ”„ ๋‚ด์—์„œ ์ตœ์†Œ๊ฐ’์„ ์ฐพ๊ธฐ ์œ„ํ•ด map.keySet()์„ ์ˆœํšŒํ•˜๋Š” ๋ถ€๋ถ„์ธ๋ฐ, ์ด ์ž‘์—…์ด ์™ธ๋ถ€ ๋ฃจํ”„๊ฐ€ ๋ฐ˜๋ณต๋  ๋•Œ๋งˆ๋‹ค ์ˆ˜ํ–‰๋˜์–ด O(nยฒ) ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
๐Ÿ’กwhile (map.containsKey(min_val))์€ key๋ฅผ ํƒ์ƒ‰ํ•˜๋Š”๋ฐ O(1)๋งŒ ๊ฑธ๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค.


๐Ÿ˜ต2์‹œ๊ฐ„ ์ด์ƒ ๊ณ ๋ฏผํ•ด๋„ ๋‹ต์„ ๋ชป์ฐพ์•„์„œ AI์˜ ๋„์›€์„ ๋ฐ›์•˜๋‹ค.
๐Ÿ‘‰nums์—์„œ ์‹œํ€€์Šค๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•œ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์ด ํ•„์š”

๐Ÿค–์ฝ”๋“œ ์„ค๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
1. ์‹œํ€€์Šค์˜ ์‹œ์ž‘์ ๋งŒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค(num-1์ด ์—†๋Š” ์ˆซ์ž).
2. ์‹œ์ž‘์ ์„ ์ฐพ์œผ๋ฉด, ํ•ด๋‹น ์ง€์ ๋ถ€ํ„ฐ ์—ฐ์†๋œ ์ˆซ์ž๋ฅผ ์ฐพ์•„ ์‹œํ€€์Šค ๊ธธ์ด๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ’ป์ˆ˜์ •๋œ ์ฝ”๋“œ ๊ตฌํ˜„

public class LcsSolution {
    public int longestConsecutive(int[] nums) {
        HashSet<Integer> set = new HashSet<>();
        int streak = 1; // longest_streak์„ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์œ„ํ•ด ์ „์—ญ๋ณ€์ˆ˜ ์„ค์ •

        if (nums.length == 0) {
            return 0;
        }

        for (int i : nums) {
            set.add(i);
        }

        for (Integer num : set) {
            if (!set.contains(num - 1)) {
                int curNum = num; // ์‹œํ€€์Šค ์‹œ์ž‘์ ์œผ๋กœ ์„ค์ •
                int curStreak = 1; // ๋‹ค๋ฅธ ์‹œํ€€์Šค ๊ฒ€์‚ฌ ์œ„ํ•ด ๋‹ค์‹œ 1๋กœ ์„ค์ •

                while (set.contains(curNum + 1)) {
                    curStreak += 1;
                    curNum += 1;
                }
                streak = Math.max(curStreak, streak); // ์‹œํ€€์Šค ์—…๋ฐ์ดํŠธ
            }
        }
        return streak;
    }
}
  1. ์‹œํ€€์Šค์˜ ์‹œ์ž‘์ ์€ if (!set.contains(num - 1)) int curNum = num๋กœ ์ฒ˜๋ฆฌํ•˜์˜€๋‹ค.
    1.1. ๋‹ค๋ฅธ ์‹œํ€€์Šค๋„ ์žˆ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜์˜ while๋ฌธ์„ ๋น ์ ธ๋‚˜๊ฐ€๋ฉด ๋‹ค์‹œ curStreak๋ฅผ 1๋กœ ์„ค์ •ํ•˜์˜€๋‹ค.
  2. ์‹œ์ž‘์ ์„ ์ฐพ์œผ๋ฉด, ํ•ด๋‹น ์ง€์ ๋ถ€ํ„ฐ ์—ฐ์†๋œ ์ˆซ์ž๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด if๋ฌธ ๋‚ด์—์„œ while (set.contains(curNum + 1)) curNum += 1๋กœ ์ฒ˜์Œ์— ์ฝ”๋“œ ๊ตฌํ˜„ํ–ˆ๋˜ key chaining๊ณผ ๋น„์Šทํ•˜๊ฒŒ ๊ตฌํ˜„ํ–ˆ๊ณ , ์—ฐ์†๋œ ์ˆซ์ž๋ฅผ ์ฐพ์„ ๋•Œ๋งˆ๋‹ค curStreak += 1์„ ํ•˜์˜€๋‹ค.
  3. ๋งˆ์ง€๋ง‰์œผ๋กœ ๊ฐ€์žฅ ์ตœ๋Œ“๊ฐ’์ธ streak๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.

๐Ÿ’ก์ž๋ฐ”์—์„œ๋Š” for๋ฌธ, if๋ฌธ ๋‚ด์˜ ๋ธ”๋ก์œผ๋กœ ๋ณ€์ˆ˜ ์Šค์ฝ”ํ”„๋ฅผ ์ •์˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— streak๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜๊ธฐ ์œ„ํ•ด ๋ฉ”์†Œ๋“œ ๋ ˆ๋ฒจ์—์„œ streak๋ฅผ 1๋กœ ์ดˆ๊ธฐํ™”ํ•˜์˜€๋‹ค.

๐Ÿค”for๋ฌธ ๋‚ด๋ถ€์˜ while๋ฌธ๋„ N๋ฒˆ ๋ฐ˜๋ณตํ•˜๋‹ˆ๊นŒ ์ตœ์ข…์ ์œผ๋กœ O(N^2)์ด ๊ฑธ๋ฆฌ์ง€ ์•Š๋‚˜์š”?
๐Ÿ‘‰์—ฐ์†๋œ ์ˆซ์ž๋ฅผ ๋”ฐ๋ผ๊ฐ€๋ฉฐ ๊ฐ ์ˆซ์ž๋ฅผ ๋”ฑ ํ•œ ๋ฒˆ์”ฉ๋งŒ ๋ฐฉ๋ฌธํ•˜๊ณ , ๋งŒ์•ฝ ๋ฐฉ๋ฌธ์„ ํ–ˆ๋‹ค๋ฉด if๋ฌธ์—์„œ ๊ฑธ๋Ÿฌ์ง€๊ธฐ ๋•Œ๋ฌธ์— ์ตœ์ข…์ ์œผ๋กœ for๋ฌธ์˜ ์›์†Œ๋งŒํผ๋งŒ ์ˆœํšŒํ•ด์„œ O(N)๋งŒ ๊ฑธ๋ฆฐ๋‹ค.

  • ์ถ”๊ฐ€๋กœ, set.contains()ํ•จ์ˆ˜๋Š” O(1)๋งŒ ๊ฑธ๋ฆผ
profile
๋ชจ๋“  ์ฝ”๋“œ์—๋Š” ์ด์œ ๊ฐ€ ์žˆ๊ธฐ์— ์›์ธ์„ ํŒŒ์•…ํ•  ๋•Œ๊นŒ์ง€ ์ง‘์š”ํ•˜๊ฒŒ ํƒ๊ตฌํ•˜๋Š” ๊ฒƒ์„ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€