暴力求解系列之简单枚举

题目来自刘汝佳的《算法竞赛入门经典(第二版)》,下面实现代码均为Java

简单枚举

问题1:

  输入正整数 n n n, 按从小到大的顺序输出所有形如 a b c d e / f g h i j = n abcde/fghij = n abcde/fghij=n的表达式, 其中 a j a~ j aj恰好为数字 0 9 0~ 9 09的一个排列(可以有前导0),其中 2 n 79 2≤n≤79 2n79
解题思路:直接枚举所有 0 9 0~ 9 09的所有排列,枚举量为 10 ! = 3628800 10!=3628800 10!=3628800,可以只枚举 f g h i j fghij fghij,枚举量下降至不到10万
下面是枚举 f g h i j fghij fghij的两种解法:
解法1是直接枚举 1000 1000 1000 49999 49999 49999的所有数,枚举会有重复元素,枚举量为4万+;
解法2是递归枚举(解答树),没有枚举重复元素,枚举量为 10 9 8 7 6 = 30240 10*9*8*7*6=30240 109876=30240

public class Division {
    /**
     * 算法1实现
     * @param n 正整数
     * @return  所有满足abcde/fghij = n的abcdefghij列表
     */
    private List<String> solver1(int n){
        List<String> results = new ArrayList<>();
        for(Integer i = 1000;i<=49999;i++){
            String divisor  = new String(i.toString());
            if(divisor.length() < 5){
                divisor = "0" + divisor;
            }
            String dividend = new String(new Integer(i*n).toString());
            /* 如果位数共大于10 */
            if(dividend.length() + divisor.length() > 10){
                continue;
            }
            Set<Character> countSet = new HashSet<>();
            for(int j = 0;j<dividend.length();j++){
                countSet.add(dividend.charAt(j));
            }
            if(countSet.size() < 5){
                continue;
            }
            for(int j = 0;j<divisor.length();j++){
                countSet.add(divisor.charAt(j));
            }
            if(countSet.size() == 10){
                results.add(dividend + "/" + divisor + "=" + n);
            }
        }
        return results;
    }
    /**
     * 算法2实现:递归枚举
     * @param n 输入
     * @param results 保存所有结果
     * @param temp 辅助数组,记录当前已经用过的元素
     * @param cur 记录当前已经用过的元素个数
     */
    private void solver2(int n, List<String> results, Integer[] temp, int cur){
        if(cur == 5){
            String s = "";
            Set<Integer> countSet = new HashSet<>(Arrays.asList(temp));
            for(int i = 0;i<5;i++){
                s += temp[i];
            }
            String dividend = new Integer(Integer.parseInt(s) * n).toString();
            if(dividend.length() == 5){
                for(int j = 0;j<dividend.length();j++){
                    countSet.add(Integer.parseInt(dividend.substring(j,j+1)));
                }
                if(countSet.size() == 10){
                    results.add(dividend + "/" + s + "=" + n);
                }
            }
        }else{
            for(int i = 0;i<=9;i++){
                boolean flag = true;
                for(int j = 0;j<cur;j++){
                    if(temp[j] == i){
                        flag = false;
                        break;
                    }
                }
                if(flag){
                    temp[cur] = i;
                    solver2(n, results, temp, cur+1);
                }
            }
        }
    }
   /**
     * 输出结果
     */
    public void solution(){
        int n = 3;
        /* 解法1 */
        for(String s:solver1(n)){
            System.out.println(s);
        }
        System.out.println();
        /* 解法2 */
        List<String> results = new ArrayList<>();
        Integer[] temp = new Integer[5];
        Arrays.fill(temp, -1);
        solver2(n, results, temp, 0);
        for(String s:results){
            System.out.println(s);
        }

    }
    public static void main(String[] args){
        Division division = new Division();
        division.solution();
    }
}

问题2:

  输入正整数 k k k, 找到所有的正整数 x y x \geq y xy,使得 1 k = 1 x + 1 y \frac{1}{k} = \frac{1}{x}+\frac{1}{y} k1=x1+y1
解题思路:首先发现 x = y = 2 k x=y=2k x=y=2k时等式成立,因此只要枚举 k &lt; y 2 k k&lt; y\leq2k k<y2k即可,根据 k k k y y y判断求出的 x = k y y k x=\frac{k*y}{y-k} x=ykky是否为整数

/**
     * 算法实现
     * @param k 正整数k
     * @return 所有满足1/k = 1/x + 1/y的x和y的列表
     */
    private List<int[]> solver1(int k){
        List<int[]> results = new ArrayList<>();
        /* 枚举y */
        for(int y = k+1;y<=2*k;y++){
            double temp = (double) k*y/(y-k);
            if(temp == (int) temp){
                results.add(new int[]{(int) temp, y});
            }
        }
        return results;
    }
    /**
     * 输出结果
     */
    public void solution(){
    	/* 输入 */
        int k = 12;
        for(int[] result:solver1(k)){
            System.out.println("1/" + result[0] + " + " + "1/" + result[1] + " = " + "1/" + k);
        }
    }
    public static void main(String[] args){
        Fractions fractions = new Fractions();
        fractions.solution();
    }

问题3:

  输入 n n n个元素组成的序列 S S S, 你需要找出一个乘积最大的连续子序列。 如果这个最大的乘积不是正数, 应输出 0 0 0。 其中 1 n 18 1≤n≤18 1n18 10 S i 10 -10≤S_i≤10 10Si10
解题思路:直接枚举起点 i i i到终点 j j j的乘积,找出最大值即可(虽然所有元素的绝对值都小于等于10,其最大乘积可能会溢出,这里我没管了= =)

public class MaxmiumProduct {
    /**
     * 算法实现
     * @param a 包含所有元素
     * @return  连续子序列最大乘积
     */
    private long solver1(int[] a){
        int n = a.length;
        long[][] product = new long[n][n];
        long maxProduct = 0;
        for(int i = 0;i<n;i++){
            long tempProduct = 1L;
            for(int j = i;j<n;j++){
                product[i][j] = tempProduct *= a[j];
                if(maxProduct < product[i][j]){
                    maxProduct = product[i][j];
                }
            }
        }
        return maxProduct;
    }
    /**
     * 输出结果
     */
    public void solution(){
    	/* 输入 */
        int a[] = new int[]{2, 4, -3, 2, 0, -2, -4, -8, 0, 4, 9, -5, -10} ;
        System.out.println(solver1(a));
    }
    public static void main(String[] args){
        MaxmiumProduct maxmiumProduct = new MaxmiumProduct();
        maxmiumProduct.solution();
    }
}


有任何问题,欢迎指出 :)

全部评论

相关推荐

群星之怒:1.照片可以换更好一点的,可以适量P图,带一些发型,遮住额头,最好穿的正式一点,可以适当P图。2.内容太少。建议添加的:求职意向(随着投递岗位动态更改);项目经历(内容太少了建议添加一些说明,技术栈:用到了什么技术,还有你是怎么实现的,比如如何确保数据传输稳定的,角色注册用到了什么技术等等。)项目经历是大头,没有实习是硬伤,如果项目经理不突出的话基本很难过简历筛。3.有些内容不必要,比如自我评价,校内实践。如果实践和工作无关千万别写,不如多丰富丰富项目。4.排版建议:建议排版是先基础信息,然后教育背景(要突出和工作相关的课程),然后专业技能(一定要简短,不要长篇大论,写你会什么,会的程度就可以),然后是项目经历(一定要详细,占整个简历一定要超过一半,甚至超过百分之70都可以)。最后如果有一部分空白的话可以填补上校内获得的专业相关的奖项,没有就写点校园经历和自我评价。5.技术一定要够硬,禁得住拷打。还有作息尽量保证正常,不要太焦虑。我24双非本科还是非科班,秋招春招各找了一段实习结果都没有转正,当时都想噶了,最后6月份在校的尾巴也找到一份工作干到现在,找工作有时很看运气的不要急着自我否定。 加油
点赞 评论 收藏
分享
allin秋招的大菠萝很爱交友:后续,已拿offer ~查看图片
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务