资讯专栏INFORMATION COLUMN

得到一个数组中任意X个元素的所有组合 即C(n,m)

haoguo / 1397人阅读

摘要:一个面试题一个数组找出这样的三个元素它们的和与目标值最接近如原始数组目标值这样的三个元素算法没有想到什么好的算法可以快捷的找到这样的三个元素只想到了穷举法即找出所有的任意三元素数组长度放到优先队列中按三个元素的和与目标值的差值绝对值进行排序

一个面试题

一个数组 找出这样的三个元素 它们的和与目标值最接近

原始数组: [15, 27, 31, 33, 39, 44, 50, 57, 86, 91]
目标值: 98
这样的三个元素:15,33,50 (15+33+50=98)

算法

没有想到什么好的算法 可以快捷的找到这样的三个元素
只想到了穷举法 即

找出所有的任意三元素 C(数组长度,3)

放到优先队列中 按三个元素的和与目标值的差值(绝对值)进行排序

第一个即是与目标值最接近的三元素

伪代码
// 得到所有的三元素组合列表 如["1,2,3", "4,5,6" , ...]
List allUniqueThreeElements = getAllUniqueThreeElements(a,3);

// 三元素列表转成对象  对象中提供了这样的方法:getDiff (计算三元素的和与目标值的差值(绝对值))
List threeElementsList = new ArrayList<>();
for (String s : allUniqueThreeElements) {
    elementsList.add(new ThreeElements(s));
}
// 构造优先队列 按三元素的和与目标值的差值(绝对值)进行排序 优先队列默认大小为三元素组合列表大小
PriorityQueue pq = new PriorityQueue<>(threeElementsList.size(),comparingInt(o -> o.getDiff(target))); 

// 将三元素组合对象 逐一放到优先队列中
for (ThreeElements e : threeElementsList) {
    pq.offer(e);
}

ThreeElements poll = pq.poll(); // 优先队列中 第一个即为要找的三元素
详细介绍 如何找到一个数组中的所有的X元素组合

即C(n,m)

如 数组 [1,2,3,4,5] 找出所有的元素组合

index 0 1 2 3 4
copy1 1 2 3 4 5
copy2 1 2 3 4 5
copy3 1 2 3 4 5

相当于将同一数组复制三份 每一份中 取一个元素 不重复即可

这样的取法

copy1 copy2 copy3 -
0 1 2 1,2,3
0 1 3 1,2,4
0 1 4 1,2,5
0 1 5 超过最大索引值 从前一位开始递增 同时逐个更新后面的值 即后一位的值 = 前一位 + 1
0 2 3 1,3,4
0 2 4 1,3,5
0 2 5 超过最大索引值 从前一位开始递增
0 3 4 1,4,5
0 3 5 超过最大索引值 从前一位开始递增
0 4 5 超过最大索引值 从更一位开始递增
1 2 3 2,3,4
1 2 4 2,3,5
1 2 5 超过最大索引值 从前一位开始递增
1 3 4 2,4,5
1 3 5 超过最大索引值 从前一位开始递增
1 4 5 超过最大索引值 从更一位开始递增
2 3 4 3,4,5
2 3 5 超过最大索引值 从前一位开始递增
2 4 5 超过最大索引值 从更一位开始递增
3 4 5 超过最大索引值 且此时不存在更前一位了 退出
对应的代码
    /**
     * 
     * @param indexArray 索引数组
     * @param maxIndexValue 最大索引值
     * @param startIndex indexArray中从此位开始递增
     * @return
     */
    private boolean next(final int[] indexArray, final int maxIndexValue, int startIndex){
//        System.out.println("indexArray: "+Arrays.toString(indexArray));
//        System.out.println("startIndex: "+startIndex);
        indexArray[startIndex]++; // 从此位开始递增
        if(indexArray[startIndex] > maxIndexValue){ // 超过最大索引值 从前一位开始递增
            return next(indexArray,maxIndexValue,startIndex-1);
        }else{
            // 同时逐个累加之后的元素 后一位的值 = 前一位+1
            for (int i = startIndex+1; i < indexArray.length; i++) {
                indexArray[i] = indexArray[i-1]+1;
                if(indexArray[i] > maxIndexValue){
                    if(startIndex -1 < 0){ // 如果是从第一位开始递增的 即不存在更前一位了 则退出递归
                        return false;
                    }
                    return next(indexArray,maxIndexValue,startIndex-1);
                }
            }
            return true;
        }
    }

测试代码

    @Test
    public void test_next(){
        // 测试从一个数组中得到所有的三元素组合
        int[] a = {1, 2, 3, 4, 5}; // 数组
        int maxIndexValue = a.length-1; // 最大索引值
        int[] indexArray = {0,1,2}; // 初始化索引数组
        int startIndex = indexArray.length-1; // 从末位开始递增

        // 验证  [0,1,2] --> [0,1,3]
        boolean next = next(indexArray, maxIndexValue, startIndex);
        assertTrue(next);
        assertArrayEquals(new int[]{0,1,3}, indexArray);

        // 验证 [0,1,4] --> [0,2,3]
        indexArray = new int[]{0, 1, 4};
        next = next(indexArray, maxIndexValue, startIndex);
        assertTrue(next);
        assertArrayEquals(new int[]{0,2,3}, indexArray);

        // 验证 [0,3,4] --> [1,2,3]
        indexArray = new int[]{0, 3, 4};
        next = next(indexArray, maxIndexValue, startIndex);
        assertTrue(next);
        assertArrayEquals(new int[]{1,2,3}, indexArray);

        // 验证 [2,3,4] --> X
        indexArray = new int[]{2, 3, 4};
        next = next(indexArray, maxIndexValue, startIndex);
        assertFalse(next);
    }

当验证其他一些极端情况的时候 如从一个数组中得到所有一个元素的组合 即C(n,1) 测试没有通过

    @Test
    public void test_next_and_only_choose_one_element(){
        // 测试一些更极端的情况 如 一个数组中选出所有1个元素的组合(C(n,1))
        final int[] a = {1, 2, 3, 4, 5};
        int maxIndexValue = a.length-1;
        int[] indexArray = {0};
        int startIndex = indexArray.length-1;


        //验证 [0] -> [1]
        boolean next = next(indexArray, maxIndexValue, startIndex);
        assertTrue(next);
        assertArrayEquals(new int[]{1},indexArray);
        System.out.println();
        // 验证 [4] -> X
        indexArray = new int[]{4};
        next = next(indexArray, maxIndexValue, startIndex);
        assertFalse(next);
    }

修复代码 将判断最后没有下一组的代码给提取出来了

    private boolean next(final int[] indexArray, final int maxIndexValue, int startIndex){
        if(startIndex < 0){ // 如果不存在更前一位了 则退出递归
            return false;
        }
        indexArray[startIndex]++; // 从此位开始递增
        if(indexArray[startIndex] > maxIndexValue){ // 超过最大索引值 从前一位开始递增
            return next(indexArray,maxIndexValue,startIndex-1);
        }else{
            // 同时逐个累加之后的元素 后一位的值 = 前一位+1
            for (int i = startIndex+1; i < indexArray.length; i++) {
                indexArray[i] = indexArray[i-1]+1;
                if(indexArray[i] > maxIndexValue){
                    return next(indexArray,maxIndexValue,startIndex-1);
                }
            }
            return true;
        }
    }
参考文档

http://wiki.jikexueyuan.com/p...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/66647.html

相关文章

  • javasm>cm>ript 最长公共子序列

    摘要:但不是和的最长公共子序列,而序列和也均为和的最长公共子序列,长度为,而和不存在长度大于等于的公共子序列。最长公共子序列给定序列和,从它们的所有公共子序列中选出长度最长的那一个或几个。为和的最长公共子序列长度。 最长公共子序列(Longest Common Subsequence LCS)是从给定的两个序列X和Y中取出尽可能多的一部分字符,按照它们在原序列排列的先后次序排列得到。LCS问...

    Xufc 评论0 收藏0
  • Pythom>nm>学习之路21-序列构成数组

    摘要:第行把具名元组以的形式返回。对序列使用和通常号两侧的序列由相同类型的数据所构成当然不同类型的也可以相加,返回一个新序列。从上面的结果可以看出,它虽抛出了异常,但仍完成了操作查看字节码并不难,而且它对我们了解代码背后的运行机制很有帮助。 《流畅的Python》笔记。接下来的三篇都是关于Python的数据结构,本篇主要是Python中的各序列类型 1. 内置序列类型概览 Python标准库...

    ralap 评论0 收藏0
  • 由三道 Leetm>Cm>ode 题目简单了解一下位运算

    摘要:使用位运算数组只出现一次数字的数组得到最低的有效位,即两个数不同的那一位看完上面的解法,我脑海中只有问号的存在,啥意思啊下面就让我们简单了解一下位运算并解析一下这三道题目。另,负数按补码形式参加按位与运算。你可做过这几道题? 在面试的准备过程中,刷算法题算是必修课,当然我也不例外。某天,我刷到了一道神奇的题目: # 136. 只出现一次的数字 给定一个非空整数数组,除了某个元素只出现一次以外...

    daydream 评论0 收藏0

发表评论

0条评论

haoguo

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<