2018校招真题【牛客网】练习(七)

1、最后一位

题目描述
牛牛选择了一个正整数X,然后把它写在黑板上。然后每一天他会擦掉当前数字的最后一位,直到他擦掉所有数位。 在整个过程中,牛牛会把所有在黑板上出现过的数字记录下来,然后求出他们的总和sum.
例如X = 509, 在黑板上出现过的数字依次是509, 50, 5, 他们的和就是564.
牛牛现在给出一个sum,牛牛想让你求出一个正整数X经过上述过程的结果是sum.

思路:
abc+ab+a=x即111a+11b+1c=x,所以a=x/111,b=(x-a*111)/11,……以此类推。

代码:

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        long input = scanner.nextLong();
        scanner.close();
        long cp = input;
        long count = 1;//记录位数
        while(cp>=10){
            count++;
            cp/=10;
        }
        long result = 0;
        for(long i=count;i>=1;i--){
            long divisor = 0;
            for(long j=i;j>=1;j--){
                divisor = divisor*10+1;
            }
            long quotient = input/divisor;
            if(quotient>=10){
                System.out.println(-1);
                return;
            }
            result = result*10 + quotient;
            input -= (quotient*divisor);
        }
        System.out.println(result);
    }
    
}
2、冒泡排序

题目描述:
牛牛学习了冒泡排序,并写下以下冒泡排序的伪代码,注意牛牛排序的数组a是从下标0开始的。
BubbleSort(a):
Repeat length(a)-1 times:
For every i from 0 to length(a) - 2:
If a[i] > a[i+1] then:
Swap a[i] and a[i+1]
牛牛现在要使用上述算法对一个数组A排序。
在排序前牛牛允许执行最多k次特定操作(可以不使用完),每次特定操作选择一个连续子数组,然后对其进行翻转,并且k次特定操作选择的子数组不相交。
例如A = {1, 2, 3, 4, 5, 6, 7}, k = 1,如果牛牛选择的子数组是2,4,那么翻转之后的数组变为A = {1, 2, 5, 4, 3, 6, 7}。
牛牛知道冒泡排序的效率一定程度上取决于Swap操作次数,牛牛想知道对于一个数组A在进行k次特定操作之后,再进行上述冒泡排序最少的Swap操作次数是多少?

思路:
参考讨论区 https://www.nowcoder.com/questionTerminal/6a33f0ce1e1649069f222e69e1d3d05f
动态规划
dp[i][j]//下标0到n-1,可以换j次,最多可以消除多少逆序数
ni[i][j]//下标i到j逆序数
shun[i][j]//下标i到j顺序数(相等数字不计)
dp[i][j]=max{dp[i+1][j],{ni[i][t]-shun[i][t]+dp[t+1][j-1] | i<t<n}}
答案为总逆序数减最多消去的逆序数

代码:

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int k = scanner.nextInt();
        int[] nums = new int[n];
        for(int i=0;i<n;i++){
            nums[i] = scanner.nextInt();
        }
        scanner.close();
        // dp[i][j]表示经过不超过j次的交换后,a[i]...a[n-1]最小的逆序和。
        int[][] dp = new int[n+1][k+1];
        for(int i=n-1;i>=0;i--){
            for(int j=0;j<=k;j++){
                dp[i][j] = countReverseOrder(nums,i,i)+dp[i+1][k];
                if(j>0){
                    for(int p=i+1;p<n;p++){
                        int[] temp = new int[p+1];
                        System.arraycopy(nums,0,temp,0,p+1);
                        reverse(temp,i,p);
                        dp[i][j] = Math.min(dp[i][j],
                        countReverseOrder(temp,i,p)+dp[p+1][j-1]);
                    }
                }
            }
        }
        System.out.println(dp[0][k]);
    }
    public static int countReverseOrder(int arr[], int start, int end){
        int count = 0;
        for(int i=start;i<=end;i++){
            for(int j=0;j<i;j++){
                if(arr[j]>arr[i]){
                    count++;
                }
            }
        }
        return count;
    }
    public static void reverse(int arr[],int start,int end){
        while(start<end){
            int temp = arr[start];
            arr[start] = arr[end];
            arr[end] = temp;
            start++;
            end--;
        }
    }
}
3、

题目描述:
一个合法的括号匹配序列有以下定义:
1、空串"“是一个合法的括号匹配序列
2、如果"X"和"Y"都是合法的括号匹配序列,“XY"也是一个合法的括号匹配序列
3、如果"X"是一个合法的括号匹配序列,那么”(X)“也是一个合法的括号匹配序列
4、每个合法的括号序列都可以由以上规则生成。
例如: “”,”()”,"()()","((()))“都是合法的括号序列
对于一个合法的括号序列我们又有以下定义它的深度:
1、空串”“的深度是0
2、如果字符串"X"的深度是x,字符串"Y"的深度是y,那么字符串"XY"的深度为max(x,y) 3、如果"X"的深度是x,那么字符串”(X)"的深度是x+1
例如: "()()()“的深度是1,”((()))"的深度是3。牛牛现在给你一个合法的括号序列,需要你计算出其深度。

思路:
利用stack匹配()。

代码:

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        char[] str = scanner.nextLine().toCharArray();
        scanner.close();
        Stack<Character> stack = new Stack<>();
        int depth = 0;
        for(int i=0; i<str.length; i++){
            if(str[i]=='('){
                stack.push('(');
            }else{
                depth = Math.max(depth,stack.size());
                stack.pop();
            }
        }
        System.out.println(depth);
    }
}
4、奶牛编号

题目描述:
牛牛养了n只奶牛,牛牛想给每只奶牛编号,这样就可以轻而易举地分辨它们了。 每个奶牛对于数字都有自己的喜好,第i只奶牛想要一个1和x[i]之间的整数(其中包含1和x[i])。
牛牛需要满足所有奶牛的喜好,请帮助牛牛计算牛牛有多少种给奶牛编号的方法,输出符合要求的编号方法总数。

思路:
给输入从小到大排序,后面的总比前一个少一种选择,或者说是比第1个少i种选择。

代码:

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        ArrayList<Long> x = new ArrayList<>();
        for(int i=0;i<n;i++){
            x.add(scanner.nextLong());
        }
        scanner.close();
        Collections.sort(x);
        long result = 1;
        for(int i=0;i<n;i++){
            long choice = x.get(i)-i;
            result *= choice;
            result = result % 1000000007;
        }
        System.out.println(result);
    }
}
5、平方串

题目描述:
如果一个字符串S是由两个字符串T连接而成,即S = T + T, 我们就称S叫做平方串,例如"",“aabaab”,"xxxx"都是平方串.
牛牛现在有一个字符串s,请你帮助牛牛从s中移除尽量少的字符,让剩下的字符串是一个平方串。换句话说,就是找出s的最长子序列并且这个子序列构成一个平方串。

思路:
将字符串分成两块,寻找最大重复子串。
使用动态规划找到两个字符串里的最大自串。dp[i][j]表示子串0-(-1)和0-(j-1)中重复的字符个数。
dp[i][j] = str1.charAt(i)==str2.charAt(j)? dp[i-1][j-1]+1 : Math.max(dp[i][j-1],dp[i-1][j])

代码:

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        String str = scanner.nextLine();
        int maxLen = 0;
        for(int i=1;i<str.length();i++){
            String str1 = str.substring(0,i);
            String str2 = str.substring(i);
            maxLen = Math.max(maxLen,maxSameLength(str1,str2));
        }
        System.out.println(maxLen);
    }
    public static int maxSameLength(String str1,String str2){
        int len1 = str1.length(),len2 = str2.length();
        int[][] dp = new int[len1+1][len2+1];
        for(int i=1;i<len1+1;i++){
            for(int j=1;j<len2+1;j++){
                dp[i][j] = (str1.charAt(i-1)==str2.charAt(j-1))? dp[i-1][j-1]+1:Math.max(dp[i-1][j],dp[i][j-1]);
            }
        }
        return dp[len1][len2]*2;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值