2022-08-06:给定一个数组arr,长度为N,arr中所有的值都在1~K范围上,
你可以删除数字,目的是让arr的最长递增子序列长度小于K。
返回至少删除几个数字能达到目的。
N <= 10^4,K <= 10^2。
来自京东。4.2笔试。

答案2022-08-06:

动态规划。
时间复杂度:O(NK)。
额外空间复杂度:O(N
K)。
rust和typescript的代码都有。

代码用rust编写。代码如下:

use rand::Rng;
fn main() {
let nn: i32 = 15;
let kk: i32 = 6;
let test_time: i32 = 10000;
println!("测试开始");
for _ in 0..test_time {
let len = rand::thread_rng().gen_range(0, nn) + 1;
let k = rand::thread_rng().gen_range(0, kk) + 1;
let mut arr = random_array(len, k);
let ans1 = min_remove1(&mut arr, k);
let ans2 = min_remove2(&mut arr, k);
if ans1 != ans2 {
println!("ans1 = {:?}", ans1);
println!("ans2 = {:?}", ans2);
println!("出错了!");
break;
}
}
println!("测试结束");
} // 暴力方法
// 为了验证
fn min_remove1(arr: &mut Vec<i32>, k: i32) -> i32 {
let mut path0: Vec<i32> = vec![];
for _ in 0..arr.len() {
path0.push(0);
}
return process1(arr, 0, &mut path0, 0, k);
} const MAX_VALUE: i32 = 2 << 31 - 1; fn process1(arr: &mut Vec<i32>, index: i32, path0: &mut Vec<i32>, size: i32, k: i32) -> i32 {
if index == arr.len() as i32 {
return if length_of_lis(path0, size) < k {
arr.len() as i32 - size
} else {
MAX_VALUE
};
} else {
let p1 = process1(arr, index + 1, path0, size, k);
path0[size as usize] = arr[index as usize];
let p2 = process1(arr, index + 1, path0, size + 1, k);
return get_min(p1, p2);
}
} fn get_min<T: Clone + Copy + std::cmp::PartialOrd>(a: T, b: T) -> T {
if a < b {
a
} else {
b
}
} fn get_max<T: Clone + Copy + std::cmp::PartialOrd>(a: T, b: T) -> T {
if a > b {
a
} else {
b
}
} fn length_of_lis(arr: &mut Vec<i32>, size: i32) -> i32 {
if size == 0 {
return 0;
}
let mut ends: Vec<i32> = vec![];
for _ in 0..size {
ends.push(0);
}
ends[0] = arr[0];
let mut right: i32 = 0;
let mut l;
let mut r;
let mut m;
let mut max = 1;
for i in 1..size {
l = 0;
r = right;
while l <= r {
m = (l + r) / 2;
if arr[i as usize] > ends[m as usize] {
l = m + 1;
} else {
r = m - 1;
}
}
right = get_max(right, l);
ends[l as usize] = arr[i as usize];
max = get_max(max, l + 1);
}
return max;
} // arr[0...index-1]上,选择了一些数字,之前的决定!
// len长度了!len = 3 : 1 2 3
// arr[index....]是能够决定的,之前的,已经不能再决定了
// 返回:让最终保留的数字,凑不足k长度的情况下,至少要删几个!
fn zuo(arr: &mut Vec<i32>, index: i32, len: i32, k: i32) -> i32 {
if len == k {
return MAX_VALUE;
}
// 凑的(1...len)还不到(1...k)
if index == arr.len() as i32 {
return 0;
}
// 没凑到 < k, 有数字!
let cur = arr[index as usize];
// 可能性1:保留
// 可能性2:删除
// 1...3 3
if len >= cur || len + 1 < cur {
return zuo(arr, index + 1, len, k);
}
// 1..3 4
// len + 1 == cur
// 可能性1:保留
let p1 = zuo(arr, index + 1, len + 1, k);
// 可能性2:删除
let mut p2 = MAX_VALUE;
let next2 = zuo(arr, index + 1, len, k);
if next2 != MAX_VALUE {
p2 = 1 + next2;
}
return get_min(p1, p2);
} // 正式方法
// 时间复杂度O(N*K)
fn min_remove2(arr: &mut Vec<i32>, k: i32) -> i32 {
let n = arr.len() as i32;
let mut dp: Vec<Vec<i32>> = vec![];
for i in 0..n {
dp.push(vec![]);
for _ in 0..k {
dp[i as usize].push(0);
}
}
for i in 0..n {
for j in 0..k {
dp[i as usize][j as usize] = -1;
}
}
return process2(arr, k, 0, 0, &mut dp);
} fn process2(arr: &mut Vec<i32>, k: i32, index: i32, range: i32, dp: &mut Vec<Vec<i32>>) -> i32 {
if range == k {
return MAX_VALUE;
}
if index == arr.len() as i32 {
return 0;
}
if dp[index as usize][range as usize] != -1 {
return dp[index as usize][range as usize];
}
let mut ans: i32;
if arr[index as usize] == range + 1 {
let mut p1 = process2(arr, k, index + 1, range, dp);
p1 += if p1 != MAX_VALUE { 1 } else { 0 };
let p2 = process2(arr, k, index + 1, range + 1, dp);
ans = get_min(p1, p2);
} else {
ans = process2(arr, k, index + 1, range, dp);
}
dp[index as usize][range as usize] = ans;
return ans;
} // 为了测试
fn random_array(len: i32, k: i32) -> Vec<i32> {
let mut arr: Vec<i32> = vec![];
for _ in 0..len {
arr.push(rand::thread_rng().gen_range(0, k) + 1);
}
return arr;
}

执行结果如下:

代码用typescript编写。代码如下:

// 暴力方法
// 为了验证
function minRemove1(arr: number[], k: number): number {
return process1(arr, 0, new Array(arr.length), 0, k);
} var MAX_VALUE: number = 2147483647;
function process1(
arr: number[],
index: number,
path: number[],
size: number,
k: number
): number {
if (index == arr.length) {
return lengthOfLIS(path, size) < k ? arr.length - size : MAX_VALUE;
} else {
var p1: number = process1(arr, index + 1, path, size, k);
path[size] = arr[index];
var p2: number = process1(arr, index + 1, path, size + 1, k);
return Math.min(p1, p2);
}
} function lengthOfLIS(arr: number[], size: number): number {
if (size == 0) {
return 0;
}
var ends: number[] = new Array(size); ends[0] = arr[0];
var right: number = 0;
var l: number = 0;
var r: number = 0;
var m: number = 0;
var max: number = 1;
for (var i: number = 1; i < size; i++) {
l = 0;
r = right;
while (l <= r) {
m = Math.floor((l + r) / 2);
if (arr[i] > ends[m]) {
l = m + 1;
} else {
r = m - 1;
}
}
right = Math.max(right, l);
ends[l] = arr[i];
max = Math.max(max, l + 1);
}
return max;
} // arr[0...index-1]上,选择了一些数字,之前的决定!
// len长度了!len = 3 : 1 2 3
// arr[index....]是能够决定的,之前的,已经不能再决定了
// 返回:让最终保留的数字,凑不足k长度的情况下,至少要删几个!
function zuo(arr: number[], index: number, len: number, k: number): number {
if (len == k) {
return MAX_VALUE;
}
// 凑的(1...len)还不到(1...k)
if (index == arr.length) {
return 0;
}
// 没凑到 < k, 有数字!
var cur: number = arr[index];
// 可能性1:保留
// 可能性2:删除
// 1...3 3
if (len >= cur || len + 1 < cur) {
return zuo(arr, index + 1, len, k);
}
// 1..3 4
// len + 1 == cur
// 可能性1:保留
var p1: number = zuo(arr, index + 1, len + 1, k);
// 可能性2:删除
var p2: number = MAX_VALUE;
var next2: number = zuo(arr, index + 1, len, k);
if (next2 != MAX_VALUE) {
p2 = 1 + next2;
}
return Math.min(p1, p2);
} // 正式方法
// 时间复杂度O(N*K)
function minRemove2(arr: number[], k: number): number {
var n: number = arr.length;
var dp: number[][] = new Array(n);
for (var i: number = 0; i < n; i++) {
dp[i] = new Array(k);
}
for (var i: number = 0; i < n; i++) {
for (var j: number = 0; j < k; j++) {
dp[i][j] = -1;
}
}
return process2(arr, k, 0, 0, dp);
} function process2(
arr: number[],
k: number,
index: number,
range: number,
dp: number[][]
): number {
if (range == k) {
return MAX_VALUE;
}
if (index == arr.length) {
return 0;
}
if (dp[index][range] != -1) {
return dp[index][range];
}
var ans: number = 0;
if (arr[index] == range + 1) {
var p1: number = process2(arr, k, index + 1, range, dp);
p1 += p1 != MAX_VALUE ? 1 : 0;
var p2: number = process2(arr, k, index + 1, range + 1, dp);
ans = Math.min(p1, p2);
} else {
ans = process2(arr, k, index + 1, range, dp);
}
dp[index][range] = ans;
return ans;
} // 为了验证
function randomArray(len: number, k: number): number[] {
var arr: number[] = new Array(len);
for (var i: number = 0; i < len; i++) {
arr[i] = Math.floor(Math.random() * k) + 1;
}
return arr;
} // 为了验证
function main() {
var N: number = 15;
var K: number = 6;
var testTime: number = 10000;
console.log("测试开始");
for (var i: number = 0; i < testTime; i++) {
var len: number = Math.floor(Math.random() * N) + 1;
var k: number = Math.floor(Math.random() * K) + 1;
var arr: number[] = randomArray(len, k);
var ans1: number = minRemove1(arr, k);
var ans2: number = minRemove2(arr, k);
if (ans1 != ans2) {
console.log("出错了!");
arr.forEach(function (num) {
console.log(num + " ");
}); console.log();
console.log("k : " + k);
console.log("ans1 : " + ans1);
console.log("ans2 : " + ans2);
break;
}
}
console.log("测试结束");
} main();

执行结果如下:


左神java代码

2022-08-06:给定一个数组arr,长度为N,arr中所有的值都在1~K范围上, 你可以删除数字,目的是让arr的最长递增子序列长度小于K。 返回至少删除几个数字能达到目的。 N <= 10^4的更多相关文章

  1. POJ 2533 - Longest Ordered Subsequence - [最长递增子序列长度][LIS问题]

    题目链接:http://poj.org/problem?id=2533 Time Limit: 2000MS Memory Limit: 65536K Description A numeric se ...

  2. 编程之美 set 7 求数组中的最长递增子序列

    解法 1. 假设在目标数组 array[] 的前 i 个元素中, 最长递增子序列的长度为 LIS[i] 那么状态转移方程为 LIS[i] = max(1, LIS[k]+1) array[i+1] & ...

  3. 动态规划 - 最长递增子序列(LIS)

    最长递增子序列是动态规划中经典的问题,详细如下: 在一个已知的序列{a1,a2,...,an}中,取出若干数组组成新的序列{ai1,ai2,...,aim},其中下标i1,i2,...,im保持递增, ...

  4. 算法之动态规划(最长递增子序列——LIS)

    最长递增子序列是动态规划中最经典的问题之一,我们从讨论这个问题开始,循序渐进的了解动态规划的相关知识要点. 在一个已知的序列 {a1, a 2,...an}中,取出若干数组成新的序列{ai1, ai ...

  5. 最长递增子序列(LIS)

    最长递增子序列(Longest Increasing Subsequence) ,我们简记为 LIS. 题:求一个一维数组arr[i]中的最长递增子序列的长度,如在序列1,-1,2,-3,4,-5,6 ...

  6. 求解最长递增子序列(LIS) | 动态规划(DP)+ 二分法

    1.题目描述     给定数组arr,返回arr的最长递增子序列. 2.举例     arr={2,1,5,3,6,4,8,9,7},返回的最长递增子序列为{1,3,4,8,9}. 3.解答      ...

  7. 动态规划----最长递增子序列问题(LIS)

    题目: 输出最长递增子序列的长度,如输入 4 2 3 1 5 6,输出 4 (因为 2 3 5 6组成了最长递增子序列). 暴力破解法:这种方法很简单,两层for循环搞定,时间复杂度是O(N2). 动 ...

  8. 最长递增子序列(LIS)(转)

    最长递增子序列(LIS)   本博文转自作者:Yx.Ac   文章来源:勇幸|Thinking (http://www.ahathinking.com)   --- 最长递增子序列又叫做最长上升子序列 ...

  9. 最长递增子序列问题—LIS

    问题:给定一组数 a0,a0,....,an-1. 求该序列的最长递增(递减)序列的长度. 最长递增子序列长度的求法有O(n^2)和O(nlogn)两种算法. 1.复杂度为O(n^2)的算法. 设L[ ...

  10. leetcode最长递增子序列问题

    题目描写叙述: 给定一个数组,删除最少的元素,保证剩下的元素是递增有序的. 分析: 题目的意思是删除最少的元素.保证剩下的元素是递增有序的,事实上换一种方式想,就是寻找最长的递增有序序列.解法有非常多 ...

随机推荐

  1. java_day23~24

    Java基础 GUI编程 核心技术:Swing.AWT 现在GUI并不流行 因为其界面不美观.需要依赖jre环境 Swing public class Demo1 { //init();初始化 pub ...

  2. Visual Studio-截断类错误

    Visual Studio-截断类错误 传输数据的目标端,将提示的错误的表对应的截断字段的长度增大,重新创建表 并且,对于Visual 传输节点里面,双击红色报错的节点,然后对于数据源右键,接着选择& ...

  3. Keil Jlink没法找到STM32H750

    https://www.amobbs.com/thread-5713382-1-1.html MDK使用的是5.32,jlink使用的是9.2jlink驱动使用的是6.44b 删除工程下的JLinkS ...

  4. Linux 基础命令2

    一.输出重定向命令 : > />> 1.ls > 1.txt 把命令返回的结果输出到文件中,会覆盖之前的数据,默认情况命令返回的结果显示在屏幕中: 2.Ls >1.txt ...

  5. linux 查看进程的启动开始时间

    先使用命令查看需要查看的进程 ps -ef | grep java root 29861 13755 2 09:42 pts/0 00:10:48 java -jar XXXX.jar ps axo ...

  6. ElasticSearch 实现分词全文检索 - term、terms查询

    数据准备 ElasticSearch 实现分词全文检索 - 测试数据准备 ElasticSearch的各种查询 不会对查询关键字进行分词 term 查询 term的查询是代表完全匹配,搜索之前不会对你 ...

  7. 【桥接设计模式详解】Java/JS/Go/Python/TS不同语言实现

    [桥接设计模式详解]Java/JS/Go/Python/TS不同语言实现 简介 桥接模式(Bridge Pattern)是一种结构型设计模式,它将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的 ...

  8. 如何规避MyBatis使用过程中带来的全表更新风险

    作者:京东零售 贾玉西 一.前言 程序员A: MyBatis用过吧? 程序员B: 用过 程序员A: 好巧,我也用过,那你遇到过什么风险没?比如全表数据被更新或者删除了. 程序员B: 咔,还没遇到过,这 ...

  9. mybatis-plus #和$的使用场景

    #防止sql注入,但是会把里面的内容默认为是字符串 $使用场景:如果条件查询要加入数据权限判断,那么久需要使用$符号而不是#符号

  10. progress监视linux命令进程

    progress监视linux命令进程 可以查看哪些命令进程 cp mv tar dd gzip cat grep 如何在ubuntu安装 sudo apt install progress 使用方法 ...