英雄会上的一些题

第五届在线编程大赛月赛指定题目:反向互补子串
返回首页

题目详情

这是个字符串问题。我们的字符串只包含大写字母。我们定义一个字母和它13位以后的字母互补。即A与N互补,B与O互补,C与P互补……,我们需要找一个字符串的两个不重叠的子串,其中一个和另外一个的翻转全互补。另外,因为我们的问题来自生物学,所以我们允许这两个字符串的一个可以删掉两个字符(注意:仅允许一个字符串删掉任意位置的两个字符,另外一个必须全部互补上)。我们的目的是求最长的反向互补子串的长度。

输入格式:

多组数据,每组数据一行,有一个字符串。每个字符串长度不超过2000,只有大写英文字母组成。

输出格式:

每组数据输出一行包含一个整数,表示最长的反向互补子串长度。

答题说明


输入样例

ABCD

ABCDQOPN

ABON

输出样例:

0

2

2

解释:

第一个样例,没有互补的子串。

第二个样例,AB和NO互补,所以反向互补子串的时候我们可以选择NPO,删掉一个P即可。

第三个样例,AB与ON反向互补。


//代码仅供参考,请勿抄袭,尊重原创作者AimAtFuture, 3Q
import java.util.*;

public class ReverseComplementarySubstring{
    public static void main(String[] args) throws Exception{
        Scanner inputer = new Scanner(System.in);     
        while(inputer.hasNext())
        {  
            String str = inputer.next();  
            System.out.println(maxLenOfReverseComplementarySubStr(str));
        }
        inputer.close();    
    }

    private static int maxLenOfReverseComplementarySubStr(String str){
        int max_len = 0;
        HashMap<Character, Vector<Integer>> englishAlphabetsHM = convertStr2HM(str);
        Object[] englishAlphabetss = englishAlphabetsHM.keySet().toArray();
        for (int i = 0; i < englishAlphabetss.length; i++){
            if ((Character)englishAlphabetss[i] >= 'N'){
                continue;
            }

            Vector<Integer> englishAlphabetsIndexes = englishAlphabetsHM.get(englishAlphabetss[i]);
            Character hbenglishAlphabets = complementaryEnglishAlphabetsMapFunc((Character)englishAlphabetss[i]);
            Vector<Integer> hbenglishAlphabetsIndexes = englishAlphabetsHM.get(hbenglishAlphabets);
            if (null == hbenglishAlphabetsIndexes){
                continue;
            }else if (max_len < 1){
                max_len = 1;
            }

            int englishAlphabetsIndexesLen = englishAlphabetsIndexes.size();
            int hbEnglishAlphabetsIndexesLen = hbenglishAlphabetsIndexes.size();
            for (int j = 0; j < englishAlphabetsIndexesLen; j++){
                int j_index = englishAlphabetsIndexes.get(j);
                for (int k = 0; k < hbEnglishAlphabetsIndexesLen; k++){
                    int k_index = hbenglishAlphabetsIndexes.get(k);
                    if (k_index-j_index+1>=2*(max_len+1) || j_index-k_index+1>=2*(max_len+1)){
                        if (k_index>j_index){
                            max_len = maxSupLenOfSubString(str, j_index, k_index, max_len);
                        }else{
                            max_len = maxSupLenOfSubString(str, k_index, j_index, max_len);
                        }    
                    }                    
                }
            }
        }
        return max_len;        
    }

    private static int maxSupLenOfSubString(String str, int start_pos, int end_pos, int max_len){
        int condition = (end_pos-start_pos+1)/2;
        while (condition > max_len){
            String strA1 = str.substring(start_pos, start_pos+condition);
            int tmp_index1 = end_pos+1-condition-2;
            if (start_pos+condition > tmp_index1){
                if (start_pos+condition < end_pos+1-condition-1){
                    tmp_index1 = end_pos+1-condition-1;
                }else{
                    tmp_index1 = start_pos+condition;
                }
            }
            String strB1 = str.substring(tmp_index1, end_pos+1);
            if (isComplementTwoString(strA1, strB1)){
                max_len = condition;
                break;
            }
            
            int tmp_index2 = start_pos+condition+2;
            if (end_pos+1-condition < tmp_index2){
                if (end_pos+1-condition > start_pos+condition+1){
                    tmp_index2 = end_pos+1-condition-1;
                }else{
                    tmp_index2 = end_pos+1-condition;
                }
            }
            String strA2 = str.substring(start_pos, tmp_index2);
            String strB2 = str.substring(end_pos+1-condition, end_pos+1);
            if (isComplementTwoString(strA2, strB2)){
                max_len = condition;
                break;
            }
            condition--;
        }
        
        return max_len;
    }
    
    private static HashMap<Character, Vector<Integer>> convertStr2HM(String str){
        HashMap<Character, Vector<Integer>> ans = new HashMap<Character, Vector<Integer>>();
        int len = str.length();
        for (int i = 0; i < len; i++){
            Vector<Integer> tmp = ans.get(str.charAt(i));
            if (null == tmp){
                tmp = new Vector<Integer>();
            }
            tmp.add(i);
            ans.put(str.charAt(i), tmp);            
        }
        return ans;
    }

    // the different value of the lengths of strA and strB can not more than 2
    private static boolean isComplementTwoString(String strA, String strB){
        boolean ans = true;

        if (strB.length() > strA.length()){
            String tmp = strA;
            strA = strB;
            strB = tmp;
        }

        int a_len = strA.length();
        int b_len = strB.length();

        int max_diff = a_len - b_len;
        int diff = 0;
        for (int i = 0; i < a_len; i++){
            if (b_len-1-i+diff >= 0){
                if (strA.charAt(i) != complementaryEnglishAlphabetsMapFunc(strB.charAt(b_len-1-i+diff))){
                    diff++;
                }
            }

            if (diff > max_diff){
                ans = false;
                break;
            }
        }

        return ans;
    }

    private static char complementaryEnglishAlphabetsMapFunc(char englishAlphabets){
        char ans = (char)(englishAlphabets + 13);
        if (englishAlphabets - 'A' >= 13){
            ans = (char)(englishAlphabets - 13);
        }

        return ans;
    }
}    


评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jun-H

你的鼓励是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值