Tìm ba phần tử trong một mảng có tổng gần nhất với một số đã cho


155

Cho một mảng các số nguyên, A 1 , A 2 , ..., A n , bao gồm cả số âm và số dương và một số nguyên khác S. Bây giờ chúng ta cần tìm ba số nguyên khác nhau trong mảng, có tổng gần nhất với số nguyên S đã cho Nếu có nhiều hơn một giải pháp, bất kỳ giải pháp nào cũng được.

Bạn có thể giả sử tất cả các số nguyên nằm trong phạm vi int32_t và sẽ không xảy ra tràn số học khi tính tổng. S không có gì đặc biệt ngoài một số được chọn ngẫu nhiên.

Có thuật toán hiệu quả nào khác ngoài tìm kiếm vũ phu để tìm ba số nguyên không?


1
Nếu bạn đang tìm kiếm một số tiền bằng một số (và không phải là gần nhất), đây sẽ là vấn đề 3SUM .
Bernhard Barker

Câu trả lời:


186

Có thuật toán hiệu quả nào khác ngoài tìm kiếm vũ phu để tìm ba số nguyên không?

Vâng; chúng ta có thể giải quyết điều này trong thời gian O (n 2 )! Đầu tiên, hãy xem xét rằng vấn đề của bạn Pcó thể được diễn đạt tương đương theo một cách hơi khác để loại bỏ sự cần thiết của "giá trị mục tiêu":

vấn đề ban đầu P: Cho một mảng Acác nsố nguyên và giá trị đích S, có tồn tại 3 tuple từ Asố tiền đó Skhông?

vấn đề được sửa đổi P': Cho một mảng Acác nsố nguyên, có tồn tại 3-tuple từ Atổng đó thành 0 không?

Chú ý rằng bạn có thể đi từ phiên bản này của vấn đề P'từ Pbằng cách trừ S / 3 của bạn từ mỗi phần tử trong A, nhưng bây giờ bạn không cần giá trị mục tiêu nữa.

Rõ ràng, nếu chúng ta chỉ đơn giản kiểm tra tất cả các bộ 3 có thể, chúng ta sẽ giải quyết vấn đề trong O (n 3 ) - đó là đường cơ sở vũ phu. Có thể làm tốt hơn? Điều gì sẽ xảy ra nếu chúng ta chọn các bộ dữ liệu theo cách thông minh hơn?

Đầu tiên, chúng tôi đầu tư một chút thời gian để sắp xếp mảng, khiến chúng tôi phải chịu một hình phạt ban đầu là O (n log n). Bây giờ chúng tôi thực hiện thuật toán này:

for (i in 1..n-2) {
  j = i+1  // Start right after i.
  k = n    // Start at the end of the array.

  while (k >= j) {
    // We got a match! All done.
    if (A[i] + A[j] + A[k] == 0) return (A[i], A[j], A[k])

    // We didn't match. Let's try to get a little closer:
    //   If the sum was too big, decrement k.
    //   If the sum was too small, increment j.
    (A[i] + A[j] + A[k] > 0) ? k-- : j++
  }
  // When the while-loop finishes, j and k have passed each other and there's
  // no more useful combinations that we can try with this i.
}

Thuật toán này hoạt động bằng cách đặt ba con trỏ, i, j, và ktại các điểm khác nhau trong mảng. ibắt đầu từ đầu và từ từ làm việc đến cuối. kchỉ đến yếu tố cuối cùng jchỉ vào nơi iđã bắt đầu tại. Chúng tôi lặp đi lặp lại cố gắng tổng hợp các yếu tố tại các chỉ số tương ứng của chúng và mỗi lần xảy ra một trong những điều sau đây:

  • Tổng hợp là chính xác! Chúng tôi đã tìm thấy câu trả lời.
  • Số tiền quá nhỏ. Di chuyển jđến gần cuối để chọn số lớn nhất tiếp theo.
  • Số tiền quá lớn. Di chuyển kđến gần đầu để chọn số nhỏ nhất tiếp theo.

Đối với mỗi i, con trỏ của jksẽ dần dần gần nhau hơn. Cuối cùng, họ sẽ vượt qua nhau và tại thời điểm đó, chúng tôi không cần phải thử bất cứ điều gì khác cho điều đó i, vì chúng tôi sẽ tổng hợp các yếu tố giống nhau, chỉ theo một thứ tự khác. Sau thời điểm đó, chúng tôi thử tiếp theo ivà lặp lại.

Cuối cùng, chúng ta sẽ cạn kiệt các khả năng hữu ích, hoặc chúng ta sẽ tìm ra giải pháp. Bạn có thể thấy rằng đây là O (n 2 ) vì chúng ta thực hiện vòng lặp O (n) vòng ngoài và chúng ta thực hiện vòng lặp O (n) vòng trong. Bạn có thể thực hiện điều này theo phương pháp bậc hai nếu bạn thực sự thích, bằng cách biểu diễn mỗi số nguyên dưới dạng một vectơ bit và thực hiện một phép biến đổi Fourier nhanh, nhưng điều đó nằm ngoài phạm vi của câu trả lời này.


Lưu ý: Vì đây là câu hỏi phỏng vấn, tôi đã lừa một chút ở đây: thuật toán này cho phép lựa chọn cùng một yếu tố nhiều lần. Đó là, (-1, -1, 2) sẽ là một giải pháp hợp lệ, như (0, 0, 0). Nó cũng chỉ tìm thấy câu trả lời chính xác , không phải câu trả lời gần nhất, như tiêu đề đề cập. Như một bài tập cho người đọc, tôi sẽ cho phép bạn tìm ra cách làm cho nó hoạt động chỉ với các yếu tố riêng biệt (nhưng đó là một thay đổi rất đơn giản) và câu trả lời chính xác (cũng là một thay đổi đơn giản).


8
Có vẻ như thuật toán chỉ có thể tìm thấy 3-tuple bằng với S, không gần nhất với S.
ZelluX

7
ZelluX: Như tôi đã đề cập trong ghi chú, tôi không muốn cho đi quá nhiều vì đó là một vấn đề phỏng vấn. Tuy nhiên, hy vọng bạn có thể thấy cách sửa đổi nó để nó giúp bạn có câu trả lời gần nhất. (Gợi ý: một cách là theo dõi câu trả lời gần nhất cho đến nay và ghi đè lên nếu bạn tìm thấy câu trả lời hay hơn.)
John Women'sella

12
Điều gì xảy ra nếu chúng ta không sửa đổi báo cáo vấn đề, thay vào đó chúng ta sẽ tìm kiếm aj và ak tổng đó cho ai + S.
Boolean

3
@ZelluX: Nó tương tự như cách một loại hợp nhất hoạt động (đó là cách nó được nhấp lần đầu tiên đối với tôi). Điều mà vòng lặp bên trong đang cố gắng làm là chứng minh rằng A [j] hoặc A [k] không thể là một phần của bất kỳ giải pháp thỏa mãn nào . Vấn đề tại bất kỳ thời điểm nào là: "Có cặp j '> = j và k' <= k sao cho A [j] + A [k] = S - A [i]?" Nhìn vào cặp hiện tại (i, j), có 3 khả năng: tổng tiền được bật (dừng lại - chúng tôi đã thắng!), Nó quá thấp hoặc quá cao. Nếu nó quá thấp, thì tổng A [j] + A [k '] cũng phải quá thấp cho mọi k' <= k, vì trong mỗi tổng như vậy, số hạng đầu tiên (A [j]) sẽ giống nhau. ..
j_random_hacker

1
... và thuật ngữ thứ hai (A [k ']) sẽ giống hoặc thậm chí thấp hơn A [k]. Vì vậy, trong trường hợp này, chúng tôi đã chứng minh rằng A [j] không thể tham gia vào bất kỳ khoản tiền thỏa mãn nào - vì vậy chúng tôi cũng có thể loại bỏ nó! Chúng tôi làm gì bằng cách đặt j = j + 1 và bắt đầu lại (mặc dù điều này có thể giúp suy nghĩ về mặt giải quyết một bài toán con nhỏ hơn theo cách đệ quy thay thế). Tương tự như vậy nếu tổng A [j] + A [k] quá cao, thì chúng ta biết rằng A [j '] + A [k] cũng phải quá cao cho mọi j'> = j, vì A [j '] ít nhất phải lớn bằng A [j] và chúng tôi đã quá cao. Điều này có nghĩa là chúng ta có thể loại bỏ A [k] một cách an toàn bằng cách đặt k = k-1 và bắt đầu lại.
j_random_hacker

28

chắc chắn đây là một giải pháp tốt hơn vì nó dễ đọc hơn và do đó ít bị lỗi hơn. Vấn đề duy nhất là, chúng ta cần thêm một vài dòng mã để tránh nhiều lựa chọn của một yếu tố.

Một giải pháp O (n ^ 2) khác (bằng cách sử dụng hàm băm).

// K is the sum that we are looking for
for i 1..n
    int s1 = K - A[i]
    for j 1..i
        int s2 = s1 - A[j]
        if (set.contains(s2))
            print the numbers
    set.add(A[i])

8
Nhược điểm là lưu trữ O (N), thay vì thực hiện tại chỗ.
Charles Munger

6
Sử dụng hàm băm không nghiêm ngặt O (n ^ 2) vì bộ băm có thể suy biến trong các trường hợp hiếm gặp, dẫn đến thời gian tra cứu tuyến tính.
Ext3h

@Charles - Cũng là giải pháp của John cần không gian O (N), vì bạn thay đổi mảng ban đầu trong khi sắp xếp. Điều đó có nghĩa là người gọi có thể cần một bản sao phòng thủ trước khi sử dụng chức năng.
gamliela

Tôi nghĩ rằng có một lỗi trong thuật toán của bạn. s2có thể là một yếu tố đã được chọn. Ví dụ, nếu mảng là 0,1,2K2, không nên có câu trả lời. Tôi nghĩ rằng thuật toán của bạn sẽ xuất ra 0,1,1mà rõ ràng là không chính xác.
Yamcha

7

Giải pháp của John Women'sella có một lỗi.

Tại dòng

if (A[i] + A[j] + A[k] == 0) return (A[i], A[j], A[k])

Chúng ta cần kiểm tra xem i, j, k có khác biệt không. Mặt khác, nếu phần tử đích của tôi là 6và nếu mảng đầu vào của tôi chứa {3,2,1,7,9,0,-4,6}. Nếu tôi in ra các tuple có tổng bằng 6, thì tôi cũng sẽ nhận được 0,0,6như là đầu ra. Để tránh điều này, chúng ta cần sửa đổi điều kiện theo cách này.

if ((A[i] + A[j] + A[k] == 0) && (i!=j) && (i!=k) && (j!=k)) return (A[i], A[j], A[k])

2
Giải pháp John Women'sella chỉ là trình bày thuật toán để giải quyết vấn đề, anh ta cũng đã xác định rằng giải pháp của anh ta sẽ không hoạt động với điều kiện số khác biệt và bạn phải sửa đổi mã trên một chút mà anh ta đã để lại cho người đọc.
EmptyData

3
Trên thực tế, tôi sẽ không bao giờ là j vì bạn luôn bắt đầu nó ở j = i + 1. Điều kiện thực tế duy nhất mà bạn nên kiểm tra là liệu j == k. Tuy nhiên, bằng cách đặt vòng lặp while thành j <k, bạn đã giải quyết các vấn đề mà không cần câu lệnh if dài vì k sẽ luôn lớn hơn j và j luôn lớn hơn i.
lorenzocastillo

2
Đây dường như không phải là một câu trả lời cho câu hỏi, mà giống như một nhận xét về câu trả lời của John Women'sella.
Bernhard Barker

6

Làm thế nào về một cái gì đó như thế này, đó là O (n ^ 2)

for(each ele in the sorted array)
{
    ele = arr[i] - YOUR_NUMBER;
    let front be the pointer to the front of the array;
    let rear be the pointer to the rear element of the array.;

    // till front is not greater than rear.                    
    while(front <= rear)
    {
        if(*front + *rear == ele)
        {
            print "Found triplet "<<*front<<","<<*rear<<","<<ele<<endl;
            break;
        }
        else
        {
            // sum is > ele, so we need to decrease the sum by decrementing rear pointer.
            if((*front + *rear) > ele)
                decrement rear pointer.
            // sum is < ele, so we need to increase the sum by incrementing the front pointer.
            else
                increment front pointer.
        }
    }

Điều này tìm thấy nếu tổng của 3 phần tử chính xác bằng số của bạn. Nếu bạn muốn gần nhất, bạn có thể sửa đổi nó để ghi nhớ delta nhỏ nhất (chênh lệch giữa số lượng bộ ba hiện tại của bạn) và ở cuối in bộ ba tương ứng với delta nhỏ nhất.


Nếu bạn muốn tìm k phần tử để lấy tổng thì độ phức tạp là gì? Làm thế nào bạn đối phó với điều này?
coder_15

Với cách tiếp cận này, độ phức tạp của các phần tử k là O (n ^ (k-1)) cho k> = 2. Bạn cần thêm một vòng lặp bên ngoài cho mỗi triệu hồi bổ sung.
Ext3h

5

Lưu ý rằng chúng ta có một mảng được sắp xếp. Giải pháp này tương tự như giải pháp của John chỉ là nó tìm tổng và không lặp lại cùng một phần tử.

#include <stdio.h>;

int checkForSum (int arr[], int len, int sum) { //arr is sorted
    int i;
    for (i = 0; i < len ; i++) {
        int left = i + 1;
        int right = len - 1;
        while (right > left) {
            printf ("values are %d %d %d\n", arr[i], arr[left], arr[right]);
            if (arr[right] + arr[left] + arr[i] - sum == 0) {
                printf ("final values are %d %d %d\n", arr[i], arr[left], arr[right]);
                return 1;
            }
            if (arr[right] + arr[left] + arr[i] - sum > 0)
                right--;
            else
                left++;
        }
    }
    return -1;
}
int main (int argc, char **argv) {
    int arr[] = {-99, -45, -6, -5, 0, 9, 12, 16, 21, 29};
    int sum = 4;
    printf ("check for sum %d in arr is %d\n", sum, checkForSum(arr, 10, sum));
}

Nó là cần thiết để tính sự khác biệt tuyệt đối của a[r] + a[l] + a[i] - sum. Hãy thử arr = [-1, 2, 1, -4] sum = 1.
Dimitry

3

Đây là mã C ++:

bool FindSumZero(int a[], int n, int& x, int& y, int& z)
{
    if (n < 3)
        return false;

    sort(a, a+n);

    for (int i = 0; i < n-2; ++i)
    {
        int j = i+1;
        int k = n-1;

        while (k >= j)
        {
            int s = a[i]+a[j]+a[k];

            if (s == 0 && i != j && j != k && k != i)
            {
                x = a[i], y = a[j], z = a[k];
                return true;
            }

            if (s > 0)
                --k;
            else
                ++j;
        }
    }

    return false;
}

2

Giải pháp logN N ^ 2 * rất đơn giản: sắp xếp mảng đầu vào, sau đó đi qua tất cả các cặp A i , A j (N ^ 2 lần) và cho mỗi cặp kiểm tra xem (S - A i - A j ) có nằm trong mảng không ( thời gian logN).

Một giải pháp O (S * N) khác sử dụng phương pháp lập trình động cổ điển .

Nói ngắn gọn:

Tạo mảng 2 chiều V [4] [S + 1]. Điền vào nó theo cách như vậy, rằng:

V [0] [0] = 1, V [0] [x] = 0;

V 1 [A i ] = 1 với mọi i, V 1 [x] = 0 cho tất cả các x khác

V [2] [A i + A j ] = 1, với mọi i, j. V [2] [x] = 0 cho tất cả các x khác

V [3] [tổng của 3 phần tử bất kỳ] = 1.

Để điền vào nó, lặp qua A i , với mỗi A i lặp qua mảng từ phải sang trái.


thay đổi nhỏ đối với thuật toán đầu tiên .. nếu phần tử không tồn tại, thì khi kết thúc tìm kiếm nhị phân, chúng ta phải xem xét phần tử bên trái, hiện tại và bên phải để xem phần tử nào cho kết quả gần nhất .
Anurag

Mảng quá lớn và nó không phải là O (s * N). Bước này là O (N ^ 2): V [2] [Ai + Aj] = 1, với mọi i, j. V [2] [x] = 0 cho tất cả các x khác.
Richard

1

Điều này có thể được giải quyết hiệu quả trong O (n log (n)) như sau. Tôi đang đưa ra giải pháp cho biết nếu tổng của ba số bất kỳ bằng một số đã cho.

import java.util.*;
public class MainClass {
        public static void main(String[] args) {
        int[] a = {-1, 0, 1, 2, 3, 5, -4, 6};
        System.out.println(((Object) isThreeSumEqualsTarget(a, 11)).toString());
}

public static boolean isThreeSumEqualsTarget(int[] array, int targetNumber) {

    //O(n log (n))
    Arrays.sort(array);
    System.out.println(Arrays.toString(array));

    int leftIndex = 0;
    int rightIndex = array.length - 1;

    //O(n)
    while (leftIndex + 1 < rightIndex - 1) {
        //take sum of two corners
        int sum = array[leftIndex] + array[rightIndex];
        //find if the number matches exactly. Or get the closest match.
        //here i am not storing closest matches. You can do it for yourself.
        //O(log (n)) complexity
        int binarySearchClosestIndex = binarySearch(leftIndex + 1, rightIndex - 1, targetNumber - sum, array);
        //if exact match is found, we already got the answer
        if (-1 == binarySearchClosestIndex) {
            System.out.println(("combo is " + array[leftIndex] + ", " + array[rightIndex] + ", " + (targetNumber - sum)));
            return true;
        }
        //if exact match is not found, we have to decide which pointer, left or right to move inwards
        //we are here means , either we are on left end or on right end
        else {

            //we ended up searching towards start of array,i.e. we need a lesser sum , lets move inwards from right
            //we need to have a lower sum, lets decrease right index
            if (binarySearchClosestIndex == leftIndex + 1) {
                rightIndex--;
            } else if (binarySearchClosestIndex == rightIndex - 1) {
                //we need to have a higher sum, lets decrease right index
                leftIndex++;
            }
        }
    }
    return false;
}

public static int binarySearch(int start, int end, int elem, int[] array) {
    int mid = 0;
    while (start <= end) {
        mid = (start + end) >>> 1;
        if (elem < array[mid]) {
            end = mid - 1;
        } else if (elem > array[mid]) {
            start = mid + 1;
        } else {
            //exact match case
            //Suits more for this particular case to return -1
            return -1;
        }
    }
    return mid;
}
}

Tôi không nghĩ rằng điều này sẽ làm việc. Cấp, bạn có hai trường hợp đơn giản về cách tiến leftIndexhoặc rightIndexkhi tất cả các yếu tố ở giữa đều nhỏ hơn hoặc lớn hơn số bạn muốn. Nhưng những gì về trường hợp khi tìm kiếm nhị phân dừng ở đâu đó ở giữa? Bạn sẽ cần phải kiểm tra cả hai chi nhánh (ở đâu rightIndex--leftIndex++). Trong giải pháp của bạn, bạn chỉ cần bỏ qua tình huống này. Nhưng tôi không nghĩ rằng có một cách để khắc phục vấn đề này.
Aivean

0

Giảm: Tôi nghĩ rằng giải pháp @John Women'sella O (n2) là thanh lịch nhất. Chúng ta vẫn có thể giảm A [n] để tìm kiếm tuple. Bằng cách quan sát A [k] sao cho tất cả các phần tử sẽ nằm trong A [0] - A [k], khi mảng tìm kiếm của chúng tôi rất lớn và SUM (s) thực sự nhỏ.

Một [0] là tối thiểu: - Tăng dần mảng được sắp xếp.

s = 2A [0] + A [k]: Cho s và A [] chúng ta có thể tìm thấy A [k] bằng cách sử dụng tìm kiếm nhị phân trong thời gian log (n).


0

Đây là chương trình trong java là O (N ^ 2)

import java.util.Stack;


public class GetTripletPair {

    /** Set a value for target sum */
    public static final int TARGET_SUM = 32;

    private Stack<Integer> stack = new Stack<Integer>();

    /** Store the sum of current elements stored in stack */
    private int sumInStack = 0;
    private int count =0 ;


    public void populateSubset(int[] data, int fromIndex, int endIndex) {

        /*
        * Check if sum of elements stored in Stack is equal to the expected
        * target sum.
        * 
        * If so, call print method to print the candidate satisfied result.
        */
        if (sumInStack == TARGET_SUM) {
            print(stack);
        }

        for (int currentIndex = fromIndex; currentIndex < endIndex; currentIndex++) {

            if (sumInStack + data[currentIndex] <= TARGET_SUM) {
                ++count;
                stack.push(data[currentIndex]);
                sumInStack += data[currentIndex];

                /*
                * Make the currentIndex +1, and then use recursion to proceed
                * further.
                */
                populateSubset(data, currentIndex + 1, endIndex);
                --count;
                sumInStack -= (Integer) stack.pop();
            }else{
            return;
        }
        }
    }

    /**
    * Print satisfied result. i.e. 15 = 4+6+5
    */

    private void print(Stack<Integer> stack) {
        StringBuilder sb = new StringBuilder();
        sb.append(TARGET_SUM).append(" = ");
        for (Integer i : stack) {
            sb.append(i).append("+");
        }
        System.out.println(sb.deleteCharAt(sb.length() - 1).toString());
    }

    private static final int[] DATA = {4,13,14,15,17};

    public static void main(String[] args) {
        GetAllSubsetByStack get = new GetAllSubsetByStack();
        get.populateSubset(DATA, 0, DATA.length);
    }
}

Cách tiếp cận đẹp, nhưng tôi không thể hiểu được rằng bạn giới hạn số lượng kết quả trong một bộ ba. Ví dụ: hãy xem xét đầu vào: [1,11,3,4,5,6,7,8, 2] và tổng 12, từ giải pháp của bạn, có vẻ như [1, 11] [4,8] [1,4, 5,2] vv tất cả sẽ làm việc.
Anupam Saini

0

Vấn đề có thể được giải quyết trong O (n ^ 2) bằng cách mở rộng bài toán 2 tổng với các sửa đổi nhỏ. Là vectơ chứa các phần tử và B là tổng cần thiết.

int Solution :: ThreeSumClosest (vector & A, int B) {

sort(A.begin(),A.end());

int k=0,i,j,closest,val;int diff=INT_MAX;

while(k<A.size()-2)
{
    i=k+1;
    j=A.size()-1;

    while(i<j)
    {
        val=A[i]+A[j]+A[k];
        if(val==B) return B;
        if(abs(B-val)<diff)
        {
            diff=abs(B-val);
            closest=val;
        }
        if(B>val)
        ++i;
        if(B<val) 
        --j;
    }
    ++k;

}
return closest;

0

Đây là mã Python3

class Solution:
    def threeSumClosest(self, nums: List[int], target: int) -> int:
        result = set()
        nums.sort()
        L = len(nums)     
        for i in range(L):
            if i > 0 and nums[i] == nums[i-1]:
                continue
            for j in range(i+1,L):
                if j > i + 1 and nums[j] == nums[j-1]:
                    continue  
                l = j+1
                r = L -1
                while l <= r:
                    sum = nums[i] + nums[j] + nums[l]
                    result.add(sum)
                    l = l + 1
                    while l<=r and nums[l] == nums[l-1]:
                        l = l + 1
        result = list(result)
        min = result[0]
        for i in range(1,len(result)):
            if abs(target - result[i]) < abs(target - min):
                min = result[i]
        return min

-1

Một giải pháp khác kiểm tra và thất bại sớm:

public boolean solution(int[] input) {
        int length = input.length;

        if (length < 3) {
            return false;
        }

        // x + y + z = 0  => -z = x + y
        final Set<Integer> z = new HashSet<>(length);
        int zeroCounter = 0, sum; // if they're more than 3 zeros we're done

        for (int element : input) {
            if (element < 0) {
                z.add(element);
            }

            if (element == 0) {
                ++zeroCounter;
                if (zeroCounter >= 3) {
                    return true;
                }
            }
        }

        if (z.isEmpty() || z.size() == length || (z.size() + zeroCounter == length)) {
            return false;
        } else {
            for (int x = 0; x < length; ++x) {
                for (int y = x + 1; y < length; ++y) {
                    sum = input[x] + input[y]; // will use it as inverse addition
                    if (sum < 0) {
                        continue;
                    }
                    if (z.contains(sum * -1)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

Tôi đã thêm một số bài kiểm tra đơn vị ở đây: GivenArrayReturnTrue IfThreeElementsSumZeroTest .

Nếu tập hợp đang sử dụng quá nhiều không gian, tôi có thể dễ dàng sử dụng java.util.BitSet sẽ sử dụng không gian O (n / w) .


-1

Chương trình để có được ba yếu tố. Tôi vừa sắp xếp mảng / danh sách trước và chúng được cập nhật minClosenessdựa trên mỗi bộ ba.

public int[] threeSumClosest(ArrayList<Integer> A, int B) {
    Collections.sort(A);
    int ansSum = 0;
    int ans[] = new int[3];
    int minCloseness = Integer.MAX_VALUE;
    for (int i = 0; i < A.size()-2; i++){
        int j = i+1;
        int k = A.size()-1;
        while (j < k){
            int sum = A.get(i) + A.get(j) + A.get(k);
            if (sum < B){
                j++;
            }else{
                k--;
            }
            if (minCloseness >  Math.abs(sum - B)){
                minCloseness = Math.abs(sum - B);
                ans[0] = A.get(i); ans[1] = A.get(j); ans[2] = A.get(k);
            }
        }
    }
    return ans;
}

-2

Tôi đã làm điều này trong n ^ 3, mã giả của tôi ở bên dưới;

// Tạo một hashMap với khóa là Integer và value là ArrayList // lặp qua danh sách bằng vòng lặp for, cho mỗi giá trị trong danh sách lặp lại bắt đầu từ giá trị tiếp theo;

for (int i=0; i<=arr.length-1 ; i++){
    for (int j=i+1; j<=arr.length-1;j++){

// nếu tổng của mảng [i] và Array [j] nhỏ hơn tổng mong muốn thì có khả năng tìm thấy một chữ số thứ ba, vì vậy hãy thực hiện một vòng lặp khác cho vòng lặp

      if (arr[i]+arr[j] < sum){
        for (int k= j+1; k<=arr.length-1;k++)

// trong trường hợp này chúng ta đang tìm kiếm giá trị thứ ba; nếu tổng của mảng [i] và mảng [j] và mảng [k] là tổng mong muốn thì hãy thêm chúng vào HashMap bằng cách tạo mảng [i] và sau đó thêm mảng [j] và mảng [k] vào ArrayList trong giá trị của khóa đó

          if (arr[i]+arr[j]+arr[k] ==  sum){              
              map.put(arr[i],new ArrayList<Integer>());
              map.get(arr[i]).add(arr[j]);
              map.get(arr[i]).add(arr[k]);}

sau này bạn có một từ điển có tất cả các mục đại diện cho ba giá trị cộng vào tổng mong muốn. Trích xuất tất cả các mục này bằng cách sử dụng các hàm HashMap. Điều này làm việc hoàn hảo.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.