Golang每日一练(leetDay0101) 最长递增子序列I\II\个数

简介: Golang每日一练(leetDay0101) 最长递增子序列I\II\个数

300. 最长递增子序列 Longest Increasing Subsequence

给你一个整数数组 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
  • -10^4 <= nums[i] <= 10^4

进阶:

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

代码1:二分查找,时间复杂度 O(n log n)

package main
import "fmt"
func lengthOfLIS(nums []int) int {
  n := len(nums)
  if n == 0 {
    return 0
  }
  d := make([]int, n+1)
  d[1] = nums[0]
  len := 1
  for i := 1; i < n; i++ {
    if nums[i] > d[len] {
      len++
      d[len] = nums[i]
    } else {
      l, r := 1, len
      pos := 0
      for l <= r {
        mid := l + (r-l)/2
        if d[mid] < nums[i] {
          pos = mid
          l = mid + 1
        } else {
          r = mid - 1
        }
      }
      d[pos+1] = nums[i]
    }
  }
  return len
}
func main() {
  nums := []int{10, 9, 2, 5, 3, 7, 101, 18}
  fmt.Println(lengthOfLIS(nums))
  nums = []int{0, 1, 0, 3, 2, 3}
  fmt.Println(lengthOfLIS(nums))
  nums = []int{7, 7, 7, 7, 7, 7, 7}
  fmt.Println(lengthOfLIS(nums))
}

输出:

4

4

1

代码2:动态规划,时间复杂度:O(n^2)

package main
import "fmt"
func lengthOfLIS(nums []int) int {
    n := len(nums)
    dp := make([]int, n)
    // 初始化 dp 数组
    for i := 0; i < n; i++ {
        dp[i] = 1
    }
    ans := 1
    // 开始 dp
    for i := 1; i < n; i++ {
        for j := 0; j < i; j++ {
            if nums[j] < nums[i] {
                dp[i] = max(dp[i], dp[j]+1)
            }
        }
        ans = max(ans, dp[i])
    }
    return ans
}
func max(x, y int) int {
    if x > y {
        return x
    }
    return y
}
func main() {
  nums := []int{10, 9, 2, 5, 3, 7, 101, 18}
  fmt.Println(lengthOfLIS(nums))
  nums = []int{0, 1, 0, 3, 2, 3}
  fmt.Println(lengthOfLIS(nums))
  nums = []int{7, 7, 7, 7, 7, 7, 7}
  fmt.Println(lengthOfLIS(nums))
}

2407. 最长递增子序列 II Longest Increasing Subsequence ii

给你一个整数数组 nums 和一个整数 k

找到 nums 中满足以下要求的最长子序列:

  • 子序列 严格递增
  • 子序列中相邻元素的差值 不超过k

请你返回满足上述要求的 最长子序列 的长度。

子序列 是从一个数组中删除部分元素后,剩余元素不改变顺序得到的数组。

示例 1:

输入:nums = [4,2,1,4,3,4,5,8,15], k = 3

输出:5

解释:

满足要求的最长子序列是 [1,3,4,5,8] 。

子序列长度为 5 ,所以我们返回 5 。

注意子序列 [1,3,4,5,8,15] 不满足要求,因为 15 - 8 = 7 大于 3 。


示例 2:

输入:nums = [7,4,5,1,8,12,4,7], k = 5

输出:4

解释:

满足要求的最长子序列是 [4,5,8,12] 。

子序列长度为 4 ,所以我们返回 4 。


示例 3:

输入:nums = [1,5], k = 1

输出:1

解释:

满足要求的最长子序列是 [1] 。

子序列长度为 1 ,所以我们返回 1 。


提示:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i], k <= 10^5

代码:二分查找

package main
import "fmt"
var mx []int // 全局变量
func updateTree(root, l, r, i, val int) {
  if l == r {
    mx[root] = val
    return
  }
  mid := (l + r) / 2
  if i <= mid {
    updateTree(root*2, l, mid, i, val)
  } else {
    updateTree(root*2+1, mid+1, r, i, val)
  }
  mx[root] = max(mx[root*2], mx[root*2+1])
}
func query(root, l, r, L, R int) int {
  if L <= l && r <= R {
    return mx[root]
  }
  ret := 0
  mid := (l + r) / 2
  if L <= mid {
    ret = query(root*2, l, mid, L, R)
  }
  if R > mid {
    ret = max(query(root*2+1, mid+1, r, L, R), ret)
  }
  return ret
}
func lengthOfLIS(nums []int, k int) int {
  up := 0
  for _, x := range nums {
    if x > up {
      up = x
    }
  }
  mx = make([]int, 4*up)
  for _, x := range nums {
    if x == 1 {
      updateTree(1, 1, up, 1, 1)
    } else {
      L := x - k
      if L < 1 {
        L = 1
      }
      ret := 1 + query(1, 1, up, L, x-1)
      updateTree(1, 1, up, x, ret)
    }
  }
  return mx[1]
}
func max(a, b int) int {
  if a > b {
    return a
  }
  return b
}
func main() {
  nums1 := []int{4, 2, 1, 4, 3, 4, 5, 8, 15}
  k1 := 3
  fmt.Println(lengthOfLIS(nums1, k1))
  nums2 := []int{7, 4, 5, 1, 8, 12, 4, 7}
  k2 := 5
  fmt.Println(lengthOfLIS(nums2, k2))
  nums3 := []int{1, 5}
  k3 := 1
  fmt.Println(lengthOfLIS(nums3, k3))
}

输出:

5

4

1


673. 最长递增子序列的个数 Number of Longest Increasing Subsequence

给定一个未排序的整数数组 nums返回最长递增子序列的个数

注意 这个数列必须是 严格 递增的。

示例 1:

输入: [1,3,5,4,7]

输出: 2

解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, 3, 5, 7]。


示例 2:

输入: [2,2,2,2,2]

输出: 5

解释: 最长递增子序列的长度是1,并且存在5个子序列的长度为1,因此输出5。


提示:

  • 1 <= nums.length <= 2000
  • -10^6 <= nums[i] <= 10^6

代码:

package main
import "fmt"
func findNumberOfLIS(nums []int) int {
  n := len(nums)
  if n <= 1 {
    return n
  }
  dp := make([]int, n)
  cnt := make([]int, n)
  for i := range dp {
    dp[i], cnt[i] = 1, 1
  }
  maxLen, ans := 1, 0
  for i := 1; i < n; i++ {
    for j := 0; j < i; j++ {
      if nums[j] < nums[i] {
        if dp[j]+1 > dp[i] {
          dp[i], cnt[i] = dp[j]+1, cnt[j]
        } else if dp[j]+1 == dp[i] {
          cnt[i] += cnt[j]
        }
      }
    }
    maxLen = max(maxLen, dp[i])
  }
  for i := range cnt {
    if dp[i] == maxLen {
      ans += cnt[i]
    }
  }
  return ans
}
func max(x, y int) int {
  if x > y {
    return x
  }
  return y
}
func main() {
  fmt.Println(findNumberOfLIS([]int{1, 3, 5, 4, 7}))
  fmt.Println(findNumberOfLIS([]int{2, 2, 2, 2, 2}))
}

输出:

2

5


🌟 每日一练刷题专栏 🌟

持续,努力奋斗做强刷题搬运工!

👍 点赞,你的认可是我坚持的动力!

🌟 收藏,你的青睐是我努力的方向!

评论,你的意见是我进步的财富!  

主页:https://hannyang.blog.csdn.net/

Rust每日一练 专栏

(2023.5.16~)更新中...

Golang每日一练 专栏

(2023.3.11~)更新中...

Python每日一练 专栏

(2023.2.18~2023.5.18)暂停更

C/C++每日一练 专栏

(2023.2.18~2023.5.18)暂停更

Java每日一练 专栏

(2023.3.11~2023.5.18)暂停更


目录
相关文章
|
3月前
|
Kubernetes Cloud Native Java
云原生之旅:从容器到微服务的演进之路Java 内存管理:垃圾收集器与性能调优
【8月更文挑战第30天】在数字化时代的浪潮中,企业如何乘风破浪?云原生技术提供了一个强有力的桨。本文将带你从容器技术的基石出发,探索微服务架构的奥秘,最终实现在云端自由翱翔的梦想。我们将一起见证代码如何转化为业务的翅膀,让你的应用在云海中高飞。
|
3月前
|
Java Linux Maven
java依赖冲突解决问题之容器加载依赖jar包如何解决
java依赖冲突解决问题之容器加载依赖jar包如何解决
|
1月前
|
消息中间件 NoSQL Kafka
Flink-10 Flink Java 3分钟上手 Docker容器化部署 JobManager TaskManager Kafka Redis Dockerfile docker-compose
Flink-10 Flink Java 3分钟上手 Docker容器化部署 JobManager TaskManager Kafka Redis Dockerfile docker-compose
33 4
|
1月前
|
Kubernetes Cloud Native 流计算
Flink-12 Flink Java 3分钟上手 Kubernetes云原生下的Flink集群 Rancher Stateful Set yaml详细 扩容缩容部署 Docker容器编排
Flink-12 Flink Java 3分钟上手 Kubernetes云原生下的Flink集群 Rancher Stateful Set yaml详细 扩容缩容部署 Docker容器编排
69 0
|
3月前
|
安全 算法 Java
【Java集合类面试二】、 Java中的容器,线程安全和线程不安全的分别有哪些?
这篇文章讨论了Java集合类的线程安全性,列举了线程不安全的集合类(如HashSet、ArrayList、HashMap)和线程安全的集合类(如Vector、Hashtable),同时介绍了Java 5之后提供的java.util.concurrent包中的高效并发集合类,如ConcurrentHashMap和CopyOnWriteArrayList。
【Java集合类面试二】、 Java中的容器,线程安全和线程不安全的分别有哪些?
|
3月前
|
Java 容器
【Java集合类面试一】、 Java中有哪些容器(集合类)?
这篇文章列出了Java中的四大类集合接口:Set、List、Queue和Map,以及它们的常用实现类,如HashSet、TreeSet、ArrayList、LinkedList、ArrayDeque、HashMap和TreeMap。
【Java集合类面试一】、 Java中有哪些容器(集合类)?
|
3月前
|
Java 测试技术 数据库
容器镜像解析问题之解析 Java 应用依赖时识别 jar 包如何解决
容器镜像解析问题之解析 Java 应用依赖时识别 jar 包如何解决
25 0
|
3月前
|
存储 安全 Java
【Java 第四篇章】流程控制、容器
本文档详细介绍了Java中的流程控制、集合类型、数组声明及容器的声明与遍历等内容。在流程控制部分,包括了if、if...else、if...else if...else、switch等语句的使用方法,并提供了具体示例。接着,文档对比分析了Java中单列集合(如HashSet、LinkedHashSet、TreeSet等)与双列集合(如HashMap、LinkedHashMap、Hashtable等)的特点及底层实现原理。此外,还介绍了如何声明与初始化数组,并提供了多种循环结构的使用示例。最后,通过具体的代码示例展示了不同集合类型的声明、基本操作(如添加、删除、更新、查找)以及遍历方法。
18 0
|
4月前
|
Java Scala 流计算
实时计算 Flink版产品使用问题之Docker镜像中的Java路径和容器内的Java路径不一致,是什么导致的
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
4月前
|
缓存 安全 Java
Java中的并发容器:ConcurrentHashMap详解
Java中的并发容器:ConcurrentHashMap详解
下一篇
无影云桌面