獲得一個數組中任意X個元素的全部組合 即C(n,m)

一個面試題html

一個數組 找出這樣的三個元素 它們的和與目標值最接近

原始數組: [15, 27, 31, 33, 39, 44, 50, 57, 86, 91]
目標值: 98
這樣的三個元素:15,33,50 (15+33+50=98)面試

算法

沒有想到什麼好的算法 能夠快捷的找到這樣的三個元素
只想到了窮舉法 即算法

  • 找出全部的任意三元素 C(數組長度,3)數組

  • 放到優先隊列中 按三個元素的和與目標值的差值(絕對值)進行排序測試

  • 第一個便是與目標值最接近的三元素code

僞代碼

// 獲得全部的三元素組合列表 如["1,2,3", "4,5,6" , ...]
List<String> allUniqueThreeElements = getAllUniqueThreeElements(a,3);

// 三元素列表轉成對象  對象中提供了這樣的方法:getDiff (計算三元素的和與目標值的差值(絕對值))
List<ThreeElements> threeElementsList = new ArrayList<>();
for (String s : allUniqueThreeElements) {
    elementsList.add(new ThreeElements(s));
}
// 構造優先隊列 按三元素的和與目標值的差值(絕對值)進行排序 優先隊列默認大小爲三元素組合列表大小
PriorityQueue<Elements> 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)htm

如 數組 [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...

相關文章
相關標籤/搜索