牛客--distinct-subsequences、最长递增子序列、19年贝壳笔试题

最长递增子序列

题目:对于一个数字序列,请设计一个复杂度为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;
    }

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值