给你一个整数数组 nums 和一个正整数 k ,返回长度为 k 且最具 竞争力 的 nums 子序列。
数组的子序列是从数组中删除一些元素(可能不删除元素)得到的序列。
在子序列 a 和子序列 b 第一个不相同的位置上,如果 a 中的数字小于 b 中对应的数字,那么我们称子序列 a 比子序列 b(相同长度下)更具 竞争力 。 例如,[1,3,4] 比 [1,3,5] 更具竞争力,在第一个不相同的位置,也就是最后一个位置上, 4 小于 5 。
1 <= nums.length <= 10^5
0 <= nums[i] <= 10^9
1 <= k <= nums.length
func mostCompetitive(nums []int, k int) []int {
}
本题是一个构造题,这种一般需要发现一些规则。
主要有2种解法,一种是通过模拟构造,需要用到区间查询的数据结构。
另一种是利用最小栈去构造。
func mostCompetitive(nums []int, k int) []int {
res := []int{}
for l:=-1;k>0;k-- {
ind := getMin(nums, l+1, l-(k-1)) // 遍历法求最小值
l=ind
res = append(res, nums[ind])
}
return res
}
/*
区间最值问题,指的是查询数组某一段中数字最大或最小值,
时间复杂度: 初始化 nlog(n), 查询O(1)
空间复杂度:nlog(n)
*/
func MinFunc(a, b int) int {
if a == b {
return 0
}
if a < b {
return -1
}
return 1
}
func MaxFunc(a, b int) int {
return MinFunc(b, a)
}
type RangeM struct {
array []int // 存储原始数据
store [][]int // 存储计算最值结果, store [i][j] 存储的是起点为j长度为2^i 的区间 [j, j+2^i)的最值(下标)。
compareFunc func(a, b int) int // 自定义比较函数
}
func (r *RangeM) Init(arr []int, comFunc func(a, b int) int) error {
if comFunc == nil {
return errors.New("comFunc is empty")
}
r.compareFunc = comFunc
r.array = arr
if err := r.assignStore(); nil != err {
return err
}
if err := r.calStore(); nil != err {
return err
}
return nil
}
// 预先分配内在
func (r *RangeM) assignStore() error {
l := len(r.array)
if l <= 0 {
return nil
}
r.store = make([][]int, int(math.Log2(float64(l)))+2) // 需要 log(l) 行,保险起见,+2
for i, _ := range r.store {
r.store[i] = make([]int, l)
}
return nil
}
func (r *RangeM) calStore() error {
l := len(r.array)
// 第一行长度为1,赋值为自身
for i := 0; i < l; i++ {
r.store[0][i] = i
}
// store[i][j] = max | min (store[i-1][j], store[i-1][j+1<<(i-1)])
for i := uint(1); 1<<i <= l; i++ {
for j := 0; j < l; j++ {
r.store[i][j] = r.store[i-1][j] // 默认赋值左半边最值
right := j + int(1<<(i-1))
// 如果有右半边,且值比左半边更优,则取右半边值
if right < l && r.compareFunc(r.array[r.store[i-1][j]], r.array[r.store[i-1][right]]) > 0 {
r.store[i][j] = r.store[i-1][right]
}
}
}
return nil
}
func (r *RangeM) GetValue(start, end int) (value int, index int, err error) {
if r.store == nil {
return 0, -1, errors.New("not init yet")
}
bit := uint(math.Log2(float64(end - start))) // 找到一个长度,使得从前后2边伸展,并最终可以交叉
// 比较前后2边最值,取最优解。
index = r.store[bit][start]
right := end - (1 << bit)
if r.compareFunc(r.array[index], r.array[r.store[bit][right]]) > 0 {
index = r.store[bit][right]
}
return r.array[index], index, nil
}
func getRangeMin(nums []int, start, end int) (num, ind int) {
num, ind = nums[start], start
for ; start < end; start++ {
if nums[start] < num {
num, ind = nums[start], start
}
}
return
}
func mostCompetitive(nums []int, k int) []int {
res := []int{}
l := len(nums)
rm := &RangeM{}
rm.Init(nums, MinFunc)
for ind := -1; k > 0; k-- {
var minNum int
minNum, ind, _ = rm.GetValue(ind+1, l-(k-1))
res = append(res, minNum)
}
return res
}
/*
[0]
1
*/
func mostCompetitive(nums []int, k int) []int {
st
for n in nums {
while len(st)>0 && st.top>n && len(st) + nums剩余个数 >k {
st.pop
}
st.push(n)
}
return st的前k个元素
}
func mostCompetitive(nums []int, k int) []int {
lastIndex :=-1
l := len(nums)
for ind := 0; ind<l; ind++ {
for lastIndex>=0 && nums[ind]<nums[lastIndex] && lastIndex +1 + l-ind >k {
lastIndex--
}
lastIndex++
nums[lastIndex] = nums[ind]
}
return nums[:k]
}
/*
[0]
1
*/
本人公众号:彬彬魔坊