平安科技2020校招技术岗部分编程题

题目源自:平安科技2020校招技术岗部分编程题汇总

1. 字符串异构同质判定

请编码实现一个命令行工具,判定两个指定的字符串是否异构同质;异构同质的定义为:一个字符串的字符重新排列后,能变成另一个字符串。

输入描述:

以空格字符分隔的两个字符串;输入字符串的合法字符集为[a-zA-Z0-9 ],大小写敏感,无需考虑异常输入场景。

输出描述:

如果判定两个字符串异构同质,则输出true,否则输出false。

示例:

输入:abc cba
输出:true

思路:

  • 输入示例两个字符串以空格分隔,故字符串输入在使用next()方法,空格符视为分隔符;
  • 输入两个字符串转换成字符数组,并分别使用Arrays类的排序方法,此时若两数组相等则符合异构同质;
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        boolean flag = true; 	//标志是否符合异构同质
        while(scan.hasNext()){
            char []c1 = scan.next().toCharArray();
            char []c2 = scan.next().toCharArray();
            Arrays.sort(c1);
            Arrays.sort(c2);
            for(int i = 0;i < c1.length;i++){
                if(c1[i]!=c2[i]){	//两个排序后的字符数组的元素依次比较
                    flag = false;	
                    System.out.println("false");	
                    break;	//不符合异构同质退出循环
                }
            }
        }
        if(flag){	//如果循环体是从break退出,那么flag已经被置false
            System.out.println("true");
        }
    }
}

2. 查找字符串最长公共子串

请编码实现一个命令行工具,找出指定的2个字符串的最长公共子串。

输入描述:

命令行工具接收两个字符串参数。输入字符串的合法字符集为[a-zA-Z0-9],大小写敏感,无需考虑异常输入场景。

输出描述:

所找到的公共子串;如果存在多个等长的公共子串,则请按字母序排序,依次打印出所有公共子串,每行一个。

示例:

输入:
1234567 12893457
输出:
345

输入:
12a34 34b12
输出:
12
34


思路:动态规划

  • 依次取得字符串s1和字符串s2的字符,若某两个字符相等,则说明此字符可能作为公共子串的最末一个字符,此时公共子串的长度为s1和s2从此字符往前比较保持相等的个数。利用二维数组dp记录以同时s1的第i个字符和s2的第j个字符作为子串最末字符的长度。显然当两字符不等时长度为0;而相等时长度为s1和s2从此字符往前一个位置字符的长度加1。

  • 例如s1=“12a34”,s2=“34b12”,s1在取到’2’时,s2取非’2’的字符都不构成公共子串;当s也取得’2’时,再从此往前比较s1和s2都取到相等的’1’,而dp记录了以’1’为公共子串的最末字符的长度是1,故dp在字符’2’需记为2,即以’2’为公共子串最末字符的长度是1+1=2。

  • 找到所有的可能构成的公共子串中长度最大的,记长度为max,公共子串最末字符在s1中的下标为end,由于可能多个公共子串都是最大长度,故end可能是多个。故用key-value的形式来保存max并动态更新下标end的列表。


 //对于s1=“12a34”,s2=“34b12”中,构造dp数组:s1字符作为行,s2字符作为列;
 //dp[i][j]存放同时以s1中第i个字符和s2中第j个字符
    作为公共子串最末一个字符的子串长度
 //初始化行或列为0时dp[i][j]=0,即将dp索引i、j对应到s1和s2的第i和第j个位置
col=034b12
row=0000000
10
20
a0
30
40
 //当s1的第i个字符和s2的第j个字符相等时,dp[i][j]=dp[i-1][j-1]+1
col=034b12
row=0000000
1000010
2000002
a000000
3010000
4002000
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        String s1 = scan.next();
        String s2 = scan.next();
        List<String> res = getRes(s1,s2);
        for(String str:res){
            System.out.println(str);
        }
    }
    public static List<String> getRes(String s1,String s2){
        List<String> res = new ArrayList<>();
        int[][] dp = new int [s1.length()+1][s2.length()+1];
        int max = 0;		//存放最长公共子串长度
        Map<Integer,List<Integer>> map = new HashMap<>();	//key存放max,value存放长度为max的公共子串末位字符在s1中的下标end
        
        for(int i=1;i<=s1.length();i++){
            for(int j=1;j<=s2.length();j++){
                if(s1.charAt(i-1)==s2.charAt(j-1)){
                    dp[i][j] = dp[i-1][j-1]+1;
                    if(dp[i][j]>=max){	//当取到的字符对应的新的长度大于或等于临时的max
                        max = dp[i][j];
                        if(!map.containsKey(max)){        
                            map.put(max,new ArrayList<>());
                        }
                        map.get(max).add(i-1);	//动态更新公共子串长度为max的末位字符在s1中的下标end
                    }
                }
            }
        }
        List<Integer> end = map.get(max);	//最终max是最长公共子串长度,下标end可能有多个
        for(int i:end){
            res.add(s1.substring(i-(max-1),i+1));	//从end下标处往前减长度(max-1)即为公共子串首字符
        }
        Collections.sort(res);
        return res;
    }
}

关于String 类中substring()方法的使用


3. 分糖果

n 个小朋友坐在一排,每个小朋友拥有 ai 个糖果,现在你要在他们之间转移糖果,使得最后所有小朋友拥有的糖果数都相同,每一次,你只能从一个小朋友身上拿走恰好两个糖果到另一个小朋友上,问最少需要移动多少次可以平分糖果,如果方案不存在输出 -1。

输入描述:

每个输入包含一个测试用例。每个测试用例的第一行包含一个整数n(1 <= n <= 100),接下来的一行包含n个整数ai(1 <= ai <= 100)。

输出描述:

输出一行表示最少需要移动多少次可以平分苹果,如果方案不存在则输出-1。

示例:

输入:
4
7 15 9 5
输出:
3

思路:

  • n个小朋友加一起的糖果总数为sum=a1+a2+…+an个,目标是转移后每个小朋友都有avg=(sum/n)个。假设存在可行的转移糖果的方案,其中m个小朋友初始糖果数ai比avg多,另外n-m个小朋友的ai比avg少,那么需要满足:avg是整数;m个小朋友每个人的(ai-avg)恰好是2的倍数,那么另外n-m个小朋友的每个人的(ai-avg)也会是二的倍数。

  • 例如:三个小朋友,初始各有4,6,8个糖果,sum=4+6+8=18,avg=18/3=6,要平分只需从第三个小朋友转移一次(每次拿两颗)到第一个小朋友,显然转移方案存在;而当三个小朋友初始各有6,7,8个糖果,由于每次转移拿两颗,拿一次后糖果数变成8,7,6实际上还是初始情况,故此情况平分方案不存在。

  • 计算转移次数:如果方案存在,考虑有m个初始ai多于avg的小朋友,count为这m个(ai-avg)的总和,即要转移给其他n-m个小朋友的总糖果个数,那么转移次数times=count/2。

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int[] a = new int[n];
        int sum = 0,avg = 0;	
        int count = 0,times = 0;	
        for(int i = 0;i < n;i++){
            a[i] = scan.nextInt();
            sum+=a[i];
        }
        if(sum%n==0){	//糖果总数需要是n个小朋友的倍数(avg是整数)
            avg = sum/n;
            for(int i = 0;i < n;i++){
            if(a[i]>avg){		//初始糖果数大于avg的小朋友(假设m个)
                count += a[i]-avg;	//count = m个大于avg的个数总和
                }
            }
            if(count%2==0){		//count需要是2的倍数(每次转移2个)
                times = count/2;	//次数=count/2
                System.out.println(times);
            }else{	//count不是2的倍数,不存在转移方案
                System.out.println(-1);		
            }
        }else{	//sum不是n的倍数,不存在转移方案
            System.out.println(-1);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值