最长递增子序列
题目:对于一个数字序列,请设计一个复杂度为O(nlogn)的算法,返回该序列的最长上升子序列的长度,这里的子序列定义为这样一个序列U1,U2…,其中Ui < Ui+1,且A[Ui] < A[Ui+1]。
给定一个数字序列A及序列的长度n,请返回最长上升子序列的长度。牛客链接
代码:
public class 最长递增子序列长度 {
public int findLongest(int[] A, int n) {
int[] dp=new int[n];
int result=0;
for(int i=0;i<n;i++){
dp[i]=1;
for(int j=0;j<i;j++){
if(A[j]<A[i]){
if(dp[j]+1>dp[i]){
dp[i]=dp[j]+1;
}
}
}
if(dp[i]>result){
result=dp[i];
}
}
return result;
}
}
牛客–distinct-subsequences
题目;给定两个字符串S和T,返回S子序列等于T的不同子序列个数有多少个?
字符串的子序列是由原来的字符串删除一些字符(也可以不删除)在不改变相对位置的情况下的剩余字符(例如,"ACE"is a subsequence of"ABCDE"但是"AEC"不是)
例如:
S =“rabbbit”, T =“rabbit”
返回3
题目描述:
给定两个字符串S和T,求S有多少个不同的子串与T相同。
S的子串定义为在S中任意去掉0个或者多个字符形成的串。
子串可以不连续,但是相对位置不能变。
比如“ACE”是“ABCDE”的子串,但是“AEC”不是。
问题翻译:S有多少个不同的子串与T相同
S[1:m]中的子串与T[1:n]相同的个数
由S的前m个字符组成的子串与T的前n个字符相同的个数
状态:
子状态:由S的前1,2,…,m个字符组成的子串与T的前1,2,…,n个字符相同的个数
F(i,j): S[1:i]中的子串与T[1:j]相同的个数
状态递推:
在F(i,j)处需要考虑S[i] = T[j] 和 S[i] != T[j]两种情况
当S[i] = T[j]:
1>: 让S[i]匹配T[j],则
F(i,j) = F(i-1,j-1)
2>: 让S[i]不匹配T[j],则问题就变为S[1:i-1]中的子串与T[1:j]相同的个数,则
F(i,j) = F(i-1,j)
故,S[i] = T[j]时,F(i,j) = F(i-1,j-1) + F(i-1,j)
当S[i] != T[j]:
问题退化为S[1:i-1]中的子串与T[1:j]相同的个数
故,S[i] != T[j]时,F(i,j) = F(i-1,j)
初始化:引入空串进行初始化
F(i,0) = 1 —> S的子串与空串相同的个数,只有空串与空串相同
返回结果:
F(m,n)
代码:
public class Solution {
public int numDistinct(String S, String T) {
int sLen = S.length();
int tLen = T.length();
int[][] numDis = new int[sLen + 1][tLen + 1];
numDis[0][0] = 1;
// F(i,j),初始化第一行剩余列的所有值为0
for(int i = 1; i <= tLen; ++i){
numDis[0][i] = 0;
}
//F(i, 0) = 1
for(int i = 1; i <= sLen; ++i){
numDis[i][0] = 1;
}
for(int i = 1; i <= sLen; ++i){
for(int j = 1; j <= tLen; ++j){
// S的第i个字符与T的第j个字符相同
if(S.charAt(i - 1) == T.charAt(j - 1)){
numDis[i][j] = numDis[i - 1][j] + numDis[i - 1][j - 1];
}
else{
// S的第i个字符与T的第j个字符不相同
// 从S的前i-1个字符中找子串,使子串与T的前j个字符相同
numDis[i][j] = numDis[i - 1][j];
}
}
}
return numDis[sLen][tLen];
}
}
19年贝壳笔试题
题目:小C在做一种特殊的服务器负载测试,对于一个请求队列中的请求,每一个请求都有一个负荷值,为了保证服务器稳定,请求队列中的请求负荷必须按照先递增后递减的规律(仅递增,仅递减也可以),比如[ 1,2,8,4,3 ],[ 1,3,5 ]和[ 10 ]这些是满足规律的,还有一些不满足的,比如[ 1,2,2,1 ],[ 2,1,2 ]和[ 10,10 ]。 现在给你一个请求队列,你可以对请求的负荷值进行增加,要求你调整队列中请求的负荷值,使数组满足条件。最后输出使队列满足条件最小的增加总和。
代码:
package com.lx.eurekaclient.action;
import java.util.Scanner;
public class Main444 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n;
int[] m;
while (scanner.hasNextInt()) {
n = scanner.nextInt();
m = new int[n];
for (int i = 0; i < n; i++) {
m[i] = scanner.nextInt();
}
System.out.println(minIncre(n, m));
}
}
private static int minIncre(int n, int[] mm) {
int[] m = new int[n];
int res = Integer.MAX_VALUE, i = 0;
for (int j = 0; j < n; j++) {//假设j为队列的最大值的下标
int thre = j, min = 0;//thre为顶峰节点的下标,min表示每次循环的最小值
for (int p = 0; p < n; p++) {
m[p] = mm[p];
}
for (int k = 1; k <= thre; k++) {//最大值左边必须递增
int temp = m[k - 1];
if(m[k] <= temp){
min += temp - m[k] + 1;
m[k] = temp + 1;
}
}
for (int k = n - 1; k > thre; k--) {//最大值右边必须递减
int temp = m[k - 1];
if(m[k] >= temp){
min += m[k] - temp + 1;
m[k - 1] = m[k] + 1;
}
}
if(min < res)
res = min;
}
return res;
}
}