返回介绍

solution / 0300-0399 / 0300.Longest Increasing Subsequence / README

发布于 2024-06-17 01:04:02 字数 8715 浏览 0 评论 0 收藏 0

300. 最长递增子序列

English Version

题目描述

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7]子序列

 

示例 1:

输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。

示例 2:

输入:nums = [0,1,0,3,2,3]
输出:4

示例 3:

输入:nums = [7,7,7,7,7,7,7]
输出:1

 

提示:

  • 1 <= nums.length <= 2500
  • -104 <= nums[i] <= 104

 

进阶:

  • 你能将算法的时间复杂度降低到 O(n log(n)) 吗?

解法

方法一:动态规划

我们定义 $f[i]$ 表示以 $nums[i]$ 结尾的最长递增子序列的长度,初始时 $f[i] = 1$,答案为 $f[i]$ 的最大值。

对于 $f[i]$,我们需要枚举 $0 \le j \lt i$,如果 $nums[j] \lt nums[i]$,则 $f[i] = \max(f[i], f[j] + 1)$。

最后的答案即为 $f[i]$ 的最大值。

时间复杂度 $O(n^2)$,空间复杂度 $O(n)$。其中 $n$ 为数组长度。

class Solution:
  def lengthOfLIS(self, nums: List[int]) -> int:
    n = len(nums)
    f = [1] * n
    for i in range(1, n):
      for j in range(i):
        if nums[j] < nums[i]:
          f[i] = max(f[i], f[j] + 1)
    return max(f)
class Solution {
  public int lengthOfLIS(int[] nums) {
    int n = nums.length;
    int[] f = new int[n];
    Arrays.fill(f, 1);
    int ans = 1;
    for (int i = 1; i < n; ++i) {
      for (int j = 0; j < i; ++j) {
        if (nums[j] < nums[i]) {
          f[i] = Math.max(f[i], f[j] + 1);
        }
      }
      ans = Math.max(ans, f[i]);
    }
    return ans;
  }
}
class Solution {
public:
  int lengthOfLIS(vector<int>& nums) {
    int n = nums.size();
    vector<int> f(n, 1);
    for (int i = 1; i < n; ++i) {
      for (int j = 0; j < i; ++j) {
        if (nums[j] < nums[i]) {
          f[i] = max(f[i], f[j] + 1);
        }
      }
    }
    return *max_element(f.begin(), f.end());
  }
};
func lengthOfLIS(nums []int) int {
  n := len(nums)
  f := make([]int, n)
  for i := range f {
    f[i] = 1
  }
  ans := 1
  for i := 1; i < n; i++ {
    for j := 0; j < i; j++ {
      if nums[j] < nums[i] {
        f[i] = max(f[i], f[j]+1)
        ans = max(ans, f[i])
      }
    }
  }
  return ans
}
function lengthOfLIS(nums: number[]): number {
  const n = nums.length;
  const f: number[] = new Array(n).fill(1);
  for (let i = 1; i < n; ++i) {
    for (let j = 0; j < i; ++j) {
      if (nums[j] < nums[i]) {
        f[i] = Math.max(f[i], f[j] + 1);
      }
    }
  }
  return Math.max(...f);
}
impl Solution {
  pub fn length_of_lis(nums: Vec<i32>) -> i32 {
    let n = nums.len();
    let mut f = vec![1; n];
    for i in 1..n {
      for j in 0..i {
        if nums[j] < nums[i] {
          f[i] = f[i].max(f[j] + 1);
        }
      }
    }
    *f.iter().max().unwrap()
  }
}

方法二:离散化 + 树状数组

我们将数组中的元素离散化,然后使用树状数组维护不大于某个元素的最长递增子序列的长度。

遍历数组中的每个元素 $x$,将其离散化,然后在树状数组中查找不大于 $x-1$ 的最长递增子序列的长度 $t$,则 $x$ 的最长递增子序列的长度为 $t+1$,更新答案,并且更新树状数组中 $x$ 的最长递增子序列的长度。

遍历完数组中的所有元素,即可得到答案。

时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 为数组长度。

class BinaryIndexedTree:
  def __init__(self, n: int):
    self.n = n
    self.c = [0] * (n + 1)

  def update(self, x: int, v: int):
    while x <= self.n:
      self.c[x] = max(self.c[x], v)
      x += x & -x

  def query(self, x: int) -> int:
    mx = 0
    while x:
      mx = max(mx, self.c[x])
      x -= x & -x
    return mx


class Solution:
  def lengthOfLIS(self, nums: List[int]) -> int:
    s = sorted(set(nums))
    m = len(s)
    tree = BinaryIndexedTree(m)
    for x in nums:
      x = bisect_left(s, x) + 1
      t = tree.query(x - 1) + 1
      tree.update(x, t)
    return tree.query(m)
class Solution {
  public int lengthOfLIS(int[] nums) {
    int[] s = nums.clone();
    Arrays.sort(s);
    int m = 0;
    int n = s.length;
    for (int i = 0; i < n; ++i) {
      if (i == 0 || s[i] != s[i - 1]) {
        s[m++] = s[i];
      }
    }
    BinaryIndexedTree tree = new BinaryIndexedTree(m);
    for (int x : nums) {
      x = search(s, x, m);
      int t = tree.query(x - 1) + 1;
      tree.update(x, t);
    }
    return tree.query(m);
  }

  private int search(int[] nums, int x, int r) {
    int l = 0;
    while (l < r) {
      int mid = (l + r) >> 1;
      if (nums[mid] >= x) {
        r = mid;
      } else {
        l = mid + 1;
      }
    }
    return l + 1;
  }
}

class BinaryIndexedTree {
  private int n;
  private int[] c;

  public BinaryIndexedTree(int n) {
    this.n = n;
    c = new int[n + 1];
  }

  public void update(int x, int v) {
    while (x <= n) {
      c[x] = Math.max(c[x], v);
      x += x & -x;
    }
  }

  public int query(int x) {
    int mx = 0;
    while (x > 0) {
      mx = Math.max(mx, c[x]);
      x -= x & -x;
    }
    return mx;
  }
}
class BinaryIndexedTree {
public:
  BinaryIndexedTree(int _n)
    : n(_n)
    , c(_n + 1) {}

  void update(int x, int v) {
    while (x <= n) {
      c[x] = max(c[x], v);
      x += x & -x;
    }
  }

  int query(int x) {
    int mx = 0;
    while (x) {
      mx = max(mx, c[x]);
      x -= x & -x;
    }
    return mx;
  }

private:
  int n;
  vector<int> c;
};

class Solution {
public:
  int lengthOfLIS(vector<int>& nums) {
    vector<int> s = nums;
    sort(s.begin(), s.end());
    s.erase(unique(s.begin(), s.end()), s.end());
    BinaryIndexedTree tree(s.size());
    for (int x : nums) {
      x = lower_bound(s.begin(), s.end(), x) - s.begin() + 1;
      int t = tree.query(x - 1) + 1;
      tree.update(x, t);
    }
    return tree.query(s.size());
  }
};
type BinaryIndexedTree struct {
  n int
  c []int
}

func newBinaryIndexedTree(n int) *BinaryIndexedTree {
  return &BinaryIndexedTree{n, make([]int, n+1)}
}

func (bit *BinaryIndexedTree) update(x, v int) {
  for x <= bit.n {
    bit.c[x] = max(bit.c[x], v)
    x += x & -x
  }
}

func (bit *BinaryIndexedTree) query(x int) int {
  mx := 0
  for x > 0 {
    mx = max(mx, bit.c[x])
    x -= x & -x
  }
  return mx
}

func lengthOfLIS(nums []int) int {
  n := len(nums)
  s := make([]int, n)
  copy(s, nums)
  sort.Ints(s)
  m := 0
  for i, x := range s {
    if i == 0 || x != s[i-1] {
      s[m] = x
      m++
    }
  }
  tree := newBinaryIndexedTree(m)
  for _, x := range nums {
    x = sort.SearchInts(s[:m], x) + 1
    t := tree.query(x-1) + 1
    tree.update(x, t)
  }
  return tree.query(m)
}
class BinaryIndexedTree {
  private n: number;
  private c: number[];

  constructor(n: number) {
    this.n = n;
    this.c = new Array(n + 1).fill(0);
  }

  update(x: number, v: number) {
    while (x <= this.n) {
      this.c[x] = Math.max(this.c[x], v);
      x += x & -x;
    }
  }

  query(x: number): number {
    let mx = 0;
    while (x) {
      mx = Math.max(mx, this.c[x]);
      x -= x & -x;
    }
    return mx;
  }
}

function lengthOfLIS(nums: number[]): number {
  const s = [...new Set(nums)].sort((a, b) => a - b);
  const m = s.length;
  const tree = new BinaryIndexedTree(m);
  for (let x of nums) {
    x = search(s, x);
    const t = tree.query(x - 1) + 1;
    tree.update(x, t);
  }
  return tree.query(m);
}

function search(nums: number[], x: number): number {
  let l = 0,
    r = nums.length - 1;
  while (l < r) {
    const mid = (l + r) >> 1;
    if (nums[mid] >= x) {
      r = mid;
    } else {
      l = mid + 1;
    }
  }
  return l + 1;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文