字典排序问题加强版(java)

本文介绍了一种解决牛客网排列恢复问题的算法。该问题要求根据已知的顺序对数量,恢复一个部分缺失的排列。算法通过字典排序未出现的元素,并将其插入到缺失位置来寻找所有可能的解决方案。

1、牛客网原题:

题目描述

牛牛的作业薄上有一个长度为 n 的排列 A,这个排列包含了从1到n的n个数,但是因为一些原因,其中有一些位置(不超过 10 个)看不清了,但是牛牛记得这个数列顺序对的数量是 k,顺序对是指满足 i < j 且 A[i] < A[j] 的对数,请帮助牛牛计算出,符合这个要求的合法排列的数目。

输入描述:

每个输入包含一个测试用例。每个测试用例的第一行包含两个整数 n 和 k(1 <= n <= 100, 0 <= k <= 1000000000),接下来的 1 行,包含 n 个数字表示排列 A,其中等于0的项表示看不清的位置(不超过 10 个)。

输出描述:

输出一行表示合法的排列数目。
示例1

输入

5 5
4 0 0 2 0

输出

2


2、思路:

(1)记录排列中没有的元素(X1,X2,X3...),并升序排序(记录字典排序需要用到的所有值)。

(2)将(X1,X2,X3...)序列,进行一次字典排序,然后按顺序插入到原序列A中为0的位置处。

(3)对插入(X1,X2,X3...)序列后的序列A,检验其顺序对个数是否等于k。

(4)对每一次的字典排序,重复执行(2)(3),即找出所有符合要求的合法排列。



3、code:已a

package schooloffer17;

import java.util.*;

/**
 * Created by caoxiaohong on 17/11/1 16:55.
 * 字典排序加强版
 */
public class DataRecovery {
    public static void main(String[] args) {
        int n,k;
        Scanner scanner=new Scanner(System.in);
        ArrayList<Integer> list=new ArrayList<Integer>();
        ArrayList<Integer> notHas=new ArrayList<Integer>();


        while (scanner.hasNextInt()){
            n=scanner.nextInt();
            k=scanner.nextInt();

            for(int i=0;i<n;i++) {
                list.add(scanner.nextInt());
            }

            //查找没有的元素
            for(int i=1;i<=n;i++){
                if(!list.contains(i))
                    notHas.add(i);
            }
            Collections.sort(notHas);//升序

            int size=notHas.size();
            int solutions=0;
            //notHas当前状态是否符合 有k个顺序对
            solutions+=getSolution(list,notHas,k);

            while(true){
                boolean isFind=false;
                for(int i=size-2;i>=0;i--){
                    if(notHas.get(i)<notHas.get(i+1)){
                        isFind=true;
                        for(int j=size-1;j>i;j--){
                            if(notHas.get(j)>notHas.get(i)){
                                int tmp1=notHas.get(j);
                                notHas.set(j,notHas.get(i));
                                notHas.set(i,tmp1);
                                //从i+1~(size-1)进行升序排序
                                int low=i+1,high=size-1;
                                while (low<high){
                                    int tmp2=notHas.get(low);
                                    notHas.set(low,notHas.get(high));
                                    notHas.set(high,tmp2);
                                    low++;
                                    high--;
                                }
                                solutions+=getSolution(list,notHas,k);
                            }
                        }
                    }else{
                        isFind=false;
                    }
                }
                if(!isFind)
                    break;
            }

            System.out.println(solutions);
            //清空输入列表
            list.clear();
            notHas.clear();
        }
    }

    /**对于ArrayList查找顺序对个数
     * 顺序对定义: i < j 且 A[i] < A[j]
     * @param list
     * @return
     */
    private static int getCount(ArrayList<Integer> list){
        int len=list.size();
        int res=0;
        for(int i=0;i<len;i++){
            for(int j=i+1;j<len;j++){
                if(list.get(j)>list.get(i))
                    res++;
            }
        }
        return res;
    }

    /**
     * 本次字典排序 是否符合顺序对为k个
     * @param list
     * @param notHas
     * @param k
     * @return
     */
    private static int getSolution(ArrayList<Integer> list,ArrayList<Integer> notHas,int k){
        int size=notHas.size();
        ArrayList<Integer> original=new ArrayList<Integer>();
        original.addAll(list);

        //将新生成的字典序数组插入list中元素为0的位置
        int from=0;
        for(int p=0;p<size;p++){
            for(int q=from;q<list.size();q++){
                if(list.get(q)==0){
                    list.set(q,notHas.get(p));
                    from=q+1;
                    break;
                }
            }
        }
        //查询顺序对个数
        int kk=getCount(list);
        //恢复list原值
        Collections.copy(list,original);
        if(kk==k)
            return 1;
        else
            return 0;
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值