网易笔试数列还原--枚举+全排列

7 篇文章 0 订阅

数列还原

题目描述

牛牛的作业薄上有一个长度为 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

解题思路

首先我们要能够发现,对于一个数列A,在添加了一个数以后,数列的对数变为 原数列的对数cv + 新加入的一个数与原来的数组产生的新对数之和。

很容易产生我们的解题思路:

1、首先求解我们的A(除去0元素 )的对数的个数。

2、我们对所有为0的位置的数进行全排列。

3、我们遍历我们的全排列,计算对数的个数为 cv + 新加入的对数个数,最后判断val与k的值,相等则res++。得出结果

解题算法

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
 
import javax.naming.InitialContext;
 
public class Main {
    int n,k;
    boolean []flag;
    //缺少的数
    List<Integer> list;
    //排列数
    List<ArrayList<Integer>> paramList;
    //数字排列
    int []sortArray;
    public static void main(String []args) {
        Main main8 = new Main();
        main8.init();
    }
    public void init() {
        Scanner in = new Scanner(System.in);
        int res= 0;
        n= in.nextInt();
        k=in.nextInt();
        list = new ArrayList<>();
        paramList = new ArrayList<ArrayList<Integer>>();
        flag = new boolean[n+1];
        sortArray = new int[n+1];
        for(int i = 1 ;i<=n;i++) {
            int num;
            num = in.nextInt();
            sortArray[i] = num;
            flag[num] = true;
        }
        //获取排列数
        for(int i = 1;i<=n;i++) {
            if(!flag[i]) list.add(i);
        }
        int cv = 0;
        for(int i = 1;i<=n;i++) {
            if(sortArray[i]!=0) {
                for(int j = i+1;j<=n;j++) {
                    if(sortArray[i]<sortArray[j]) {
                        cv++;
                    }
                }
            }
        }
        getParam(0);
        for(ArrayList<Integer> param :paramList ) {
            //System.out.println(param.toString());
            if((cv+getDuiShu(param))==k) {
                res++;
            }
        }
        System.out.println(res);
        in.close();
    }
    //获取对数的个数
    private int getDuiShu(List list) {
        int res = 0;
        int []temps = Arrays.copyOf(sortArray,sortArray.length);
        int j = 0;
        for(int i = 1 ;i<=n;i++) {
            if(temps[i]==0) {
                temps[i] = (Integer)list.get(j++);
                for(int k=1;k<i;k++) {
                    if(temps[k]!=0&&temps[k]<temps[i]) {
                        res++;
                    }
                }
                for(int k=i+1;k<=n;k++) {
                    if(temps[k]!=0&&temps[k]>temps[i]) {
                        res++;
                    }
                }
            }
        }
        return res;
    }
    private void getParam(int start) {
        if(start == list.size()) {
            paramList.add(new ArrayList<Integer>(list));
        }else {
            for(int i = start ; i<list.size();i++) {
                Collections.swap(list, start,i);
                getParam(start+1);
                Collections.swap(list, i,start);
            }
        }
    }
}
添加笔记 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值