满足特定顺序的字典序列中最小子序列

题目:

输入12345,找出全部的字典序排序(12345,12354,12435,12453···,21345···,31245···,41235···,51234···54321)。并且在所有字典序中,找出,满足序列2 1 5排序的最小的子序列

举例:12345不满足2 1 5
3 2 4 1 5满足,2 1 3 4 5也满足,相比较21345为满足要求的最小的子序列
思路:1.求出所有字典序排序(见博客Main38,输入abc,输出abc,acb,bac,bca,cab,cba);
2.过滤满足满足条件的子序列(见博客Main20,判断一个字符串是否为数值)
class WangYiYouDao {
	//根据输入,通过字典序排序,获取所有输出
    private static ArrayList<String> permutation(String str) {
        ArrayList<String> list = new ArrayList<>();
        if (str == null || str.length() == 0) {
            return list;
        }
        char[] chars = str.toCharArray();
        Arrays.sort(chars);//将字符数组按升序排列
        list.add(String.valueOf(chars));//0.先将按升序排列后的字符串存入list中
        while (true) {
            int i = chars.length - 1;
            int j = chars.length - 1;
            //1.从字符数组最后一个字符开始往前遍历,寻找第一次chars[i-1]<chars[i]的位置
            while (i >= 1 && chars[i - 1] >= chars[i]) {//i=2
                i--;
            }
            if (i == 0) {//此时的数组已经是降序排列了(从右往左都是增的),表明全排列完成,cba这种
                break;
            }
            //2.j从从最后一个位置开始,往前遍历,遇到大于chars[i-1]的值时停下
            // 注意在遇到等于chars[i-1]的值的时候一定不要停下,不然会造成死循环(因为此时交换的是值相同的两个数)
            while (j >= 0 && chars[j] <= chars[i - 1]) {
                j--;
            }
            //3.
            swap(chars, i - 1, j);//交换chars[i-1]和chars[j]的值
            reverse(chars, i);//反转包括chars[i]元素在内到数组结尾的所有元素
            list.add(String.valueOf(chars));
        }
        return list;
    }

    private static void reverse(char[] ch, int i) {
        int left = i;
        int right = ch.length - 1;
        while (left <= right) {
            char temp = ch[left];
            ch[left] = ch[right];
            ch[right] = temp;
            left++;
            right--;
        }
    }

    private static void swap(char[] chars, int i, int j) {
        char tmp = chars[i];
        chars[i] = chars[j];
        chars[j] = tmp;
    }

    public static void main(String[] args) {
        List<String> list = new Main_38().permutation("12345");//得到所有字典序
        String str = "2 1 5";
        permit(list,str);
    }

    /**
     * 过滤所有字典序,要求满足2 1 5这种顺序的,找出最小的满足条件的字典序
     * 比如: 12345(不满足 2 1 5),比如 32415(满足 2 1 5)顺序,而且21345(也满足2 1 5)且21345是满足中的排在最前的
     * @param list
     * @param str
     */
    private static void permit(List<String> list,String standard) {
        if (list == null || list.size() == 0 || standard == null)return;
        List<String> res = new ArrayList<>();//存所有满足2 1 5的字典序
        for (String s : list) {
            boolean exist2 = false;//表示2 已经出现过了,比如2(此时2出现了) 5(此时,exist2为true) 1 4 3
            boolean exist1 = false;
            boolean exist5 = false;
            int j = 0;
            for (j = 0; j < s.length(); j++) {
                if (s.charAt(j) == standard.charAt(0)) {
                    exist2 = true;
                } else if (s.charAt(j) == standard.charAt(2)) {
                    exist1 = true;
                } else if (s.charAt(j) == standard.charAt(4)) {
                    exist5 = true;
                }
                if (exist1 && !exist2) {//1出现了,2还未出现,不满足 2 1 5这个条件
                    break;
                }
                if (exist5 && (!exist2 || !exist1)) {//5出现了,而2,1还没出现,不允许
                    break;
                }
            }
            if (j == 5)//(j<4执行后j=5<5不满足)此时s合格,满足 2 1 5,比如 2 1 3 4 5(1出现之前,2出现了)(5出现之前2,1都出现了)
                res.add(s);
        }
        Collections.sort(res);
        System.out.println(res.get(0));
    }
}

猜你喜欢

转载自blog.csdn.net/tmax52HZ/article/details/108123151