JAVA基础(006_排列、组合)

原因:最近公司组织了一次算法考试,在规定的时间内(3个小时)没有完成考题,于是潜心研究一下。

题目:给定A、B两个二维数组(列数相等),数组中存放的是二进制数,数组的列代表属性。请找出最小的属性个数以区别A、B两个二维数组的行。(公司原题叙述要夸张很多,如同四六级的阅读理解。本人在此只叙述了题目的梗概。)

举例说明:

数组A
属性1属性2属性3属性4属性5
10110
10011
00111
00011


数组B
属性1属性2属性3属性4属性5
10010
01100
10001
11000



数组A、B分别是4行5列的二维数组,从示例数据可以得出,属性3、属性4、属性5即可区别数组A、B中的行(在属性3、4、5列,数组A的第2行数据与第4行数据重复,这个是允许的。在选定属性列的情况下,只要数组A、B中不存在重复数据即可):

数组A
属性1属性2属性3属性4属性5
10110
10011
00111
00011


数组B
属性1属性2属性3属性4属性5
10010
01100
10001
11000



数组A、B分别是4行5列的二维数组,从示例数据可以得出,属性1、属性2、属性3无法区别数组A、B中的行,不满足题目要求:

数组A
属性1属性2属性3属性4属性5
10110
10011
00111
00011


数组B
属性1属性2属性3属性4属性5
10010
01100
10001
11000



答案:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class MainClass {

    public static void main(String[] args) {

        int N = 4;
        int M = 5;

        int[][] Input1 = new int[][] { { 1, 0, 1, 1, 0 }, { 1, 0, 0, 1, 1 }, { 0, 0, 1, 1, 1 }, { 0, 0, 0, 1, 1 } };
        int[][] Input2 = new int[][] { { 1, 0, 0, 1, 0 }, { 0, 1, 1, 0, 0 }, { 1, 0, 0, 0, 1 }, { 1, 1, 0, 0, 0 } };

        List<String> list = new ArrayList<String>();
        List<String> temp = new ArrayList<String>();

        Map<String, String> map = new HashMap<String, String>();

        Map<String, String> map1 = new HashMap<String, String>();
        Map<String, String> map2 = new HashMap<String, String>();
        boolean bool = false;
        for (int k = 0; k < M; k++) {
            if (bool) {
                break;
            }
            if (k == 0) {
                for (int i = 0; i < M; i++) {
                    list.add(i + "");
                }
            } else {
                int size = list.size();
                temp.clear();
                for (int i = 0; i < size; i++) {
                    if (list.get(i).replace(",", "").length() == k) {
                        for (int j = 0; j < M; j++) {
                            if (!list.get(i).contains(j + "") && judge(list.get(i) + "," + j, temp)) {
                                temp.add(list.get(i) + "," + j);
                                // 核心代码
                                map1.clear();
                                map2.clear();
                                String[] arr = (list.get(i) + "," + j).split(",");
                                for (int y = 0; y < N; y++) {
                                    String key1 = "";
                                    for (int t = 0; t < arr.length; t++) {
                                        key1 = key1 + Input1[y][Integer.parseInt(arr[t])];
                                    }
                                    map1.put(key1, null);
                                }
                                for (int y = 0; y < N; y++) {
                                    String key2 = "";
                                    for (int t = 0; t < arr.length; t++) {
                                        key2 = key2 + Input2[y][Integer.parseInt(arr[t])];
                                    }
                                    map2.put(key2, null);
                                }
                                map.clear();
                                for (Entry<String, String> entry : map1.entrySet()) {
                                    map.put(entry.getKey(), null);
                                }
                                for (Entry<String, String> entry : map2.entrySet()) {
                                    map.put(entry.getKey(), null);
                                }
                                if (map.size() == map1.size() + map2.size()) {
                                    System.out.println("result:" + (k + 1));
                                    bool = true;
                                }
                                // 核心代码
                            }
                        }
                    }
                }
                size = temp.size();
                for (int i = 0; i < size; i++) {
                    list.add(temp.get(i));
                }
            }
        }
    }

    public static boolean judge(String str, List<String> temp) {
        Map<String, String> map = new HashMap<String, String>();
        int length = str.split(",").length;
        int size = temp.size();
        for (int i = 0; i < size; i++) {
            map.clear();
            for (int j = 0; j < length; j++) {
                map.put(str.split(",")[j], null);
            }
            for (int j = 0; j < temp.get(i).split(",").length; j++) {
                map.put(temp.get(i).split(",")[j], null);
            }
            if (map.size() == length) {
                return false;
            }
        }
        return true;
    }
}

解题思路:
1. 给定的两个二维数组,列数相等,行数可以不等。该题的考点就是对数组列的组合算法,即将数组的列进行组合,找出最小个数列使得两个数组在最小个数列中的数据不重复。
2. 在确定数组列的情况下比较两个数组对应列的行数据是否重复。

组合的定义:

从n个不同元素中,任取m(m≤n)个元素合并成一组,叫做从n个不同元素中取出m个元素的一个组合;从n个不同元素中取出m(m≤n)个元素的所有组合的个数,叫做从n个不同元素中取出m个元素的组合数。

组合的实现:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MainClass {
    public static void main(String[] args) {

        String[] arr = { "0", "1", "2", "3", "4" };
        int len = arr.length;

        // 组合的结果集
        List<String> list = new ArrayList<String>();

        // 組合:从5个数理选择1个数、2个数、3个数、4个数、5个数
        for (int k = 0; k < len; k++) { // k为选择数的个数(编码习惯,没有将k初值设置为1,即k=0表示选择1个数,以此类推)
            if (k == 0) { // 选择1个数进行组合的时候
                for (int i = 0; i < len; i++) {
                    list.add(arr[i]);
                }
                System.out.println(toString(list));
            } else { // 选择多个数进行组合的时候
                int size = list.size();
                for (int i = 0; i < size; i++) {
                    for (int j = 0; j < len; j++) {
                        if (list.get(i).replace(",", "").length() == k && !list.get(i).contains(arr[j])) {
                            if (judge((list.get(i) + "," + arr[j]).split(","), list, k)) {
                                continue;
                            }
                            list.add(list.get(i) + "," + arr[j]);
                        }
                    }
                }
                System.out.println(toString(list));
            }
        }
    }

    // 判断新增的组合在组合结果集中是否存在
    public static boolean judge(String[] arr, List<String> list, int k) {
        Arrays.sort(arr);
        int size = list.size();
        boolean bool = false;
        for (int l = 0; l < size; l++) {
            if (list.get(l).replace(",", "").length() == k + 1) {
                String[] tmp = list.get(l).split(",");
                Arrays.sort(tmp);
                if (Arrays.equals(arr, tmp)) {
                    return true;
                }
            }
        }
        return bool;
    }

    // 字符串格式化(对解题没有意义)
    public static String toString(List<String> list) {
        StringBuilder sb = new StringBuilder();
        int size = list.size();
        for (int l = 0; l < size; l++) {
            if (sb.length() == 0) {
                sb.append(list.get(l));
            } else {
                sb.append("&nbsp;&nbsp;&nbsp;" + list.get(l));
            }
        }
        return sb.toString();
    }
}

测试结果:

0   1   2   3   4
0   1   2   3   4   0,1   0,2   0,3   0,4   1,2   1,3   1,4   2,3   2,4   3,4
0   1   2   3   4   0,1   0,2   0,3   0,4   1,2   1,3   1,4   2,3   2,4   3,4   0,1,2   0,1,3   0,1,4   0,2,3   0,2,4   0,3,4   1,2,3   1,2,4   1,3,4   2,3,4
0   1   2   3   4   0,1   0,2   0,3   0,4   1,2   1,3   1,4   2,3   2,4   3,4   0,1,2   0,1,3   0,1,4   0,2,3   0,2,4   0,3,4   1,2,3   1,2,4   1,3,4   2,3,4   0,1,2,3   0,1,2,4   0,1,3,4   0,2,3,4   1,2,3,4
0   1   2   3   4   0,1   0,2   0,3   0,4   1,2   1,3   1,4   2,3   2,4   3,4   0,1,2   0,1,3   0,1,4   0,2,3   0,2,4   0,3,4   1,2,3   1,2,4   1,3,4   2,3,4   0,1,2,3   0,1,2,4   0,1,3,4   0,2,3,4   1,2,3,4   0,1,2,3,4

虽然本次题目只涉及到组合的知识,但是,为了知识体系的完整性,顺便给出排列的的定义和实现:

排列的定义:

从n个不同元素中,任取m(m≤n,m与n均为自然数,下同)个元素按照一定的顺序排成一列,叫做从n个不同元素中取出m个元素的一个排列;从n个不同元素中取出m(m≤n)个元素的所有排列的个数,叫做从n个不同元素中取出m个元素的排列数。

排列的实现:

import java.util.ArrayList;
import java.util.List;

public class MainClass {
    public static void main(String[] args) {

        String[] arr = { "0", "1", "2", "3", "4" };
        int len = arr.length;

        // 排列的结果集
        List<String> list = new ArrayList<String>();

        // 排列:从5个数理选择1个数、2个数、3个数、4个数、5个数
        for (int k = 0; k < len; k++) { // k为选择数的个数(编码习惯,没有将k初值设置为1,即k=0表示选择1个数,以此类推)
            if (k == 0) { // 选择1个数进行排列的时候
                for (int i = 0; i < len; i++) {
                    list.add(arr[i]);
                }
                System.out.println(list);
            } else { // 选择多个数进行排列的时候
                int size = list.size();
                for (int i = 0; i < size; i++) {
                    for (int j = 0; j < len; j++) {
                        if (list.get(i).length() == k && !list.get(i).contains(arr[j])) {
                            // 去重判断
                            if (list.contains(list.get(i) + arr[j])) {
                                continue;
                            }
                            list.add(list.get(i) + arr[j]);
                            // 去重判断
                            if (list.contains(arr[j] + list.get(i))) {
                                continue;
                            }
                            list.add(arr[j] + list.get(i));
                        }
                    }
                }
                System.out.println(list);
            }
        }
    }
}

总结:本题考查的核心是能否实现组合算法,这也是个人理解。本题可能存在N种解法,目前我只找到此种做法,既然有二进制数,也曾考虑过二进制数移位等算法,可惜囿于天分,尚不能实现。

排列、组合的定义,参考网址:
http://baike.baidu.com/link?url=vzBv42SG4QSi5YA-Bq0C7eopY2FliKV_0wynU8F82CYkQbKZu2pqznx7wEGMyCQQcoUJWeYxBnLx4WAH3Rld7KFWYpmec0SjljauXsjj6ou

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值