LIS - changicho/algorithm-training GitHub Wiki

LIS(Longest Increasing Subsequence)

๋ฐฑ์ค€.2568.์ „๊นƒ์ค„ - 2

์ตœ์žฅ ์ฆ๊ฐ€ ์ˆ˜์—ด

๋ณดํ†ต LIS๋ฅผ ๊ตฌํ•˜๋Š” ๋ฌธ์ œ์˜ ๋‹ต์€ ํ•œ ์ˆ˜์—ด์—์„œ ์ฃผ์–ด์ง€๋Š” LIS์˜ ๊ธธ์ด๊ฐ€ ๋‹ต์ด ๋œ๋‹ค.

O(N^2)

index๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ฆ๊ฐ€์‹œ์ผœ๊ฐ€๋ฉฐ, ์ด์ „์— ๋ฐฉ๋ฌธํ–ˆ๋˜ 0 ~ (index-1)๊นŒ์ง€์˜ ๊ฐ’์„ ๋‹ค์‹œ ์ˆœํšŒํ•˜๋ฉฐ ๊ณ„์‚ฐํ–ˆ๋˜ ๊ฐ’์„ ์ด์šฉํ•ด ํ˜„์žฌ index์˜ ๊ฐ’์„ ๊ฐฑ์‹ ํ•œ๋‹ค.

int lis(vector<int> array) {
  int size = array.size();
  // initialize
  vector<int> dp(size, 1);

  for (int target = 0; target < size; target++) {
    for (int before = 0; before < target; before++) {
      if (array[before] < array[target]) {
        dp[target] = max(dp[target], dp[before] + 1);
      }
    }
  }

  return dp.back();
}

O(N * log_2(N))

์‹œ๊ฐ„ ๋ณต์žก๋„ : O(N * log_2(N))

  • N : O(N)์œผ๋กœ ๋ฐฐ์—ด์„ ํƒ์ƒ‰ํ•จ
  • log_2(N) : lower_bound๋กœ ์ตœ์ ์˜ ์ž๋ฆฌ๋ฅผ ์ฐพ์Œ

๋ฐฐ์—ด์„ ์ˆœํšŒํ•˜๋ฉด์„œ ๋ฒกํ„ฐ์˜ ๋งจ ๋’ค ์›์†Œ์™€ ํ˜„์žฌ ๋ณด๊ณ ์žˆ๋Š” ์ˆ˜์—ด์˜ ์›์†Œ๋ฅผ ๋น„๊ตํ•œ๋‹ค.

์ˆ˜์—ด์˜ ์›์†Œ๊ฐ€ ๋” ํด ์‹œ ๋ฒกํ„ฐ์— push_backํ•ด์ค€ ๋’ค LIS์˜ ํฌ๊ธฐ(๋‹ต)์„ 1์ฆ๊ฐ€ ์‹œํ‚จ๋‹ค. ์ˆ˜์—ด์˜ ์›์†Œ๊ฐ€ ๋ฒกํ„ฐ์˜ ๋งจ ๋’ค ์›์†Œ๋ณด๋‹ค ์ž‘์„ ๊ฒฝ์šฐ lower_bound๋ฅผ ์ด์šฉํ•˜์—ฌ ์ตœ์ ์˜ ์ž๋ฆฌ๋ฅผ ์ฐพ์€ ๋’ค ๊ทธ ์ž๋ฆฌ์˜ ๊ฐ’์„ ํ•ด๋‹น ์ˆ˜์—ด์˜ ์›์†Œ๋กœ ๊ต์ฒดํ•œ๋‹ค.

LIS ๋ฐฐ์—ด์„ ๊ตฌํ•˜๊ธฐ ์œ„ํ•ด์„  ๊ฐ index๋ณ„๋กœ ์–ด๋–ค ๊ฐ’์ด ์žˆ๋Š”์ง€ ๊ฐ™์ด ์ €์žฅํ•ด์•ผํ•œ๋‹ค.

int lisLength(vector<int>& nums) {
  int size = nums.size();
  vector<int> lis;

  for (int i = 0; i < size; i++) {
    int target = lower_bound(lis.begin(), lis.end(), nums[i]) - lis.begin();

    if (target == lis.size()) {
      lis.push_back(nums[i]);
    } else {
      lis[target] = nums[i];
    }
  }

  // lis ๋ฐฐ์—ด์— LIS๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์ž„์‹œ๋กœ ์‚ฌ์šฉ๋œ ์ˆซ์ž๋“ค์ด ๋“ค์–ด์žˆ์Œ
  return lis.size();
}

Longest Non-decreasing Subsequence

LIS ์•Œ๊ณ ๋ฆฌ์ฆ˜์—์„œ lower_bound๋ฅผ ์ด์šฉํ•ด ์ด์ „์— ๋‚˜์˜จ ๊ฐ’์ค‘์—์„œ ํ˜„์žฌ๊ฐ’ ์ด์ƒ์ธ ๋ถ€๋ถ„์„ ๊ต์ฑ„ํ•œ๋‹ค.

์ด๋ฅผ upper_bound๋ฅผ ์ด์šฉํ•  ๊ฒฝ์šฐ ์ด์ „์— ๋‚˜์˜จ ๊ฐ’์ค‘ ํ˜„์žฌ๊ฐ’์„ ์ดˆ๊ณผํ•˜๋Š” ๋ถ€๋ถ„์„ ๊ต์ฑ„ํ•˜๋ฉฐ, ์ด ๊ณผ์ •์—์„œ ์ค‘๋ณตํ•ด์„œ ์›์†Œ๊ฐ€ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋‹ค.

int longestNonDecreasingSubsequence(vector<int> &nums){
  int size = nums.size();
  vector<int> lis;

  for (int i = 0; i < size; i++) {
    int target = upper_bound(lis.begin(), lis.end(), nums[i]) - lis.begin();

    if (target == lis.size()) {
      lis.push_back(nums[i]);
    } else {
      lis[target] = nums[i];
    }
  }

  // lis ๋ฐฐ์—ด์— LIS๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ์›์†Œ๊ฐ€ ๋“ค์–ด์žˆ์Œ
  return lis.size();
}

LIS๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ์›์†Œ ๊ตฌํ•˜๊ธฐ

struct LIS {
  int index, from;
};

vector<int> longestIncreasingSubsequence(int N, vector<int> array) {
  vector<LIS> lis;
  int lis_cache[MAX] = {
      0,
  };
  int index = 0;

  lis_cache[index] = array[0];
  lis.push_back({0, array[0]});
  for (int i = 1; i < N; i++) {
    if (lis_cache[index] < array[i]) {
      index++;
      lis_cache[index] = array[i];
      lis.push_back({index, array[i]});
    } else {
      int new_index = lower_bound(lis_cache, lis_cache + index, array[i]) - lis_cache;

      lis_cache[new_index] = array[i];
      lis.push_back({new_index, array[i]});
    }
  }

  // index + 1์€ LIS ๋ฐฐ์—ด์˜ ํฌ๊ธฐ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
  // ์—ญ์ˆœ์œผ๋กœ LIS ๋ฐฐ์—ด์„ ๊ตฌํ•œ๋‹ค. (index๋ฅผ ์ด์šฉํ•ด ์—ญ์ˆœ์œผ๋กœ ๊ตฌํ•จ)
  stack<int> s;
  for (int i = N - 1; i >= 0; i--) {
    if (lis[i].index == index) {
      s.push(lis[i].from);
      index--;
    }
  }

  // stack์— ์—ญ์ˆœ์œผ๋กœ ์ €์žฅ๋˜์–ด์žˆ์œผ๋ฏ€๋กœ ๋’ค์ง‘์–ด LIS ๋ฐฐ์—ด์„ ๊ตฌํ•จ
  vector<int> ret;
  while (!s.empty()) {
    ret.push_back(s.top());
    s.pop();
  }

  return ret;
}
โš ๏ธ **GitHub.com Fallback** โš ๏ธ