(Leetcode) [Dynamic programming] Longest increasing subsequence

Topic: Dynamic programming
Difficulty: Medium

Question

Given an integer array nums, return the length of the longest strictly increasing subsequence.


My first solution

int lengthOfLIS(vector<int>& nums) {
    int len = nums.size();
    int arr[len];
    for (int i=0; i<len; i++) {
        arr[i]=0;
    }

    for (int i=0; i<len; i++) {
        if (arr[i] == 0) { arr[i]=1; }
        else { continue; }

        vector<int>::iterator p = nums.begin()+i+1;
        int p_arr = i+1;
        vector<int>::iterator mark=p-1;
        int mark_arr = p_arr-1;

        for (p; p!=nums.end(); p++) {
            if (*p > *mark) {
                if (arr[p_arr] < arr[mark_arr]+1) {
                    arr[p_arr] = arr[mark_arr]+1;
                    mark_arr = p_arr;
                    mark = p;
                }
            }
            p_arr++;
        }
    }

    return *max_element(arr, arr+len);
}

์™„๋ฒฝํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ฐœ๊ฒฌํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์ง€๋งŒ, ์ด๊ฑด ํฐ ์˜ค์‚ฐ์ด์˜€๋‹ค.

์ผ๋‹จ longest subsequence array์˜ ์š”์†Œ ๊ฐฏ์ˆ˜๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ array๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด์ค€๋‹ค (arr[]).

์ฒซ๋ฒˆ์งธ for loop์€ sequential array์˜ ์‹œ์ž‘์ ์„ ์žก๊ธฐ ์œ„ํ•จ์ด๊ณ , ๋‘๋ฒˆ์งธ loop์—์„  iterator๊ฐ€ ๋‘ ๊ฐœ ์“ฐ์ธ๋‹ค.
sequential array๋ฅผ ์ด์–ด๋‚˜๊ฐ€๊ธฐ ์œ„ํ•ด์„  ๋ฐ”๋กœ ์ „์˜ element์™€ ํฌ๊ธฐ ๋น„๊ต๋ฅผ ํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋น„๊ตํ•˜๋Š” ๊ณผ์ •์—์„œ ์ œ์•ฝ์ ์ด ํ•˜๋‚˜ ๋ฐœ์ƒํ•œ๋‹ค.

nums = [0 1 0 3 2 3]

arr =  [1 2 1 3 2 3] -> my algorithm (wrong)
arr =  [1 2 1 1 3 4] -> correct algorithm

nums์—์„œ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๊ฐ€์žฅ ๊ธด subarray๊ฐ€ [0 1 2 3]์ด๋‹ค.
ํ•˜์ง€๋งŒ ๋‚ด ์ฝ”๋“œ์—์„œ p iterator๊ฐ€ ์ˆœ์„œ๋Œ€๋กœ ์›€์ง์ด๊ธฐ ๋•Œ๋ฌธ์—, ๋’ค์— ๋” ์ž‘์€ ์ˆซ์ž๊ฐ€ ์žˆ์„์ˆ˜๋„ ์žˆ๋Š”๋ฐ ๋น„๊ต๋ฅผ ํ•˜์ง€ ์•Š์•„์„œ 1 ๋‹ค์Œ์— 2๊ฐ€ ์žˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  2๋ณด๋‹ค ์•ž์— ์žˆ๋Š” 3์„ ์ฑ„ํƒํ•ด๋ฒ„๋ฆฐ๋‹ค.
๊ทธ๋Ÿฌ๋ฏ€๋กœ 2๋Š” ๋ฌด์‹œ๊ฐ€ ๋˜์–ด๋ฒ„๋ฆฐ๋‹ค.
๊ทธ๋ ‡๋‹ค๋ฉด ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์ด ๋ฌด์—‡์ด ์žˆ์„๊นŒ??

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ๋ชป ์ฐพ์•„์„œ ๊ฒฐ๊ตญ์—” geeksforgeeks,,


My second solution: Dynamic programming

์ผ๋‹จ ์ฝ”๋“œ๋Š” ๋ณด์ง€ ์•Š๊ณ  ์„ค๋ช… (illustration)๋งŒ ์ฝ์–ด๋ดค๋‹ค.

nums[] = {3, 10, 2, 11}
arr[] = {1, 1, 1, 1} (initialization)

1. arr[2] > arr[1] -> arr[2] = max(arr[2], arr[1]+1) = 2
2. arr[3] < arr[1] -> no change
3. arr[3] < arr[2] -> no change
4. arr[4] > arr[1] -> arr[4] = max(arr[4], arr[1]+1) = 2
5. arr[4] > arr[2] -> arr[4] = max(arr[4], arr[2]+1) = 3
6. arr[4] > arr[3] -> arr[4] = max(arr[4], arr[3]+1) = 3

p๋ผ๋Š” iterator๋ฅผ ๋‘๊ณ , ์ด์ค‘ ๋ฃจํ”„๋ฅผ ์ด์šฉํ•ด์„œ p ์ด์ „์— ์žˆ๋Š” ๋ชจ๋“  element๋“ค๊ณผ ๋น„๊ต๋ฅผ ํ•˜๊ฒŒ ํ•˜๋ฉด ๋‚˜์˜ ์ฒซ๋ฒˆ์งธ solution์˜ ๋ฌธ์ œ์ ์ด ํ•ด๊ฒฐ์ด ๋œ๋‹ค.

int lengthOfLIS(vector<int>& nums) {
    int len = nums.size();
    int arr[len];
    for (int i=0; i<len; i++) {
        arr[i]=1;
    }
    if (len==1) { return 1; }

    vector<int>::iterator p;
    int p_arr = 1;
    for (p=nums.begin()+1; p != nums.end(); p++) {
        vector<int>::iterator mark;
        int mark_arr = 0;
        for (mark=nums.begin(); mark != p; mark++) {
            if (*p > *mark) {
                if (arr[p_arr] < arr[mark_arr]+1) {
                    arr[p_arr] = arr[mark_arr]+1;
                }
            }
            mark_arr++;
        }
        p_arr++;
    }

    return *max_element(arr, arr+len);
}

runtime: 163 ms (์ƒ์œ„ 30%)
memory usage: 10.4 MB (์ƒ์œ„ 30%)
time complexity: O(n^2)

๋ฌธ์ œ follow up์—์„œ time complexity๊ฐ€ O(nlog n)์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ฐพ์•„๋ณด๋ผ๊ณ  ํ–ˆ๋‹ค. ๋‚œ ๋ชป ์ฐพ์•„.


Third solution: Lower bound based approach (time complexity of O(nlog n))

int lengthOfLIS(vector<int>& nums) {
    vector<int> arr;
    int len = nums.size();
    for (int i=0; i<len; i++) {
        // lower_bound searches for nums[i] by binary search.
        // if nums[i] doesn't exist in arr, p์˜ ์œ„์น˜๋Š” nums[i]๋ณด๋‹ค ํฐ ๊ฐ’ ์ค‘์— ๊ฐ€์žฅ ์ž‘์€ ๊ฐ’์„ ๊ฐ€๋ฅดํ‚ด.
        vector<int>::iterator p = lower_bound(arr.begin(), arr.end(), nums[i]);

        // p==nums.end() if all values of arr < nums[i]
        if (p==nums.end()) { arr.push_back(nums[i]); }
        // replace *p with ์ž์‹ ๋ณด๋‹ค ํฐ ๊ฐ’ ์ค‘ ๊ฐ€์žฅ ์ž‘์€ ๊ฐ’.
        // ๋”ฐ๋ผ์„œ arr์˜ ๊ธธ์ด์—๋Š” ๋ณ€ํ™”๊ฐ€ ์—†์ง€๋งŒ, ์›์†Œ๊ฐ€ ๋” ์ž‘์€ ๊ฐ’์œผ๋กœ ๋Œ€์ฒด๋˜์—ˆ์œผ๋ฏ€๋กœ ๋” ํฐ ๊ฐ’์„ ์›์†Œ๋กœ ๊ฐ€์ฆˆ๋Š” ๋ถ€๋ถ„ ๋ฐฐ์—ด๋ณด๋‹ค๋Š” ํ•ญ์ƒ ์ด๋“์ด๋‹ค.
        else { *p = nums[i]; }

        return arr.size();
    }
}

Reference

https://www.geeksforgeeks.org/longest-increasing-subsequence-dp-3/ https://www.geeksforgeeks.org/c-program-for-longest-increasing-subsequence/

Categories:

Updated:

Leave a comment