Как узнать, что треугольная тройка существует в нашем массиве?
Я застрял в решении следующего вопроса практики интервью:
Мне нужно написать функцию:
int triangle(int[] A);
что для нулевого индекса массива A, состоящего из N
integers, возвращается 1
, если существует тройка (P, Q, R) такая, что 0 < P < Q < R < N
.
A[P] + A[Q] > A[R],
A[Q] + A[R] > A[P],
A[R] + A[P] > A[Q].
Функция должна возвращать 0
, если такая тройка не существует. Предположим, что 0 < N < 100,000
. Предположим, что каждый элемент массива является целым числом в диапазоне [-1,000,000..1,000,000]
.
Например, данный массив A
такой, что
A[0]=10, A[1]=2, A[2]=5, A[3]=1, A[4]=8, A[5]=20
функция должна возвращать 1
, потому что тройка (0, 2, 4)
выполняет все необходимые условия.
Для массива A
такого, что
A[0]=10, A[1]=50, A[2]=5, A[3]=1
функция должна возвращать 0
.
Если я делаю тройной цикл, это будет очень очень медленно (сложность: O(n^3)
). Я думаю, возможно, использовать для хранения дополнительной копии массива и сортировки его, а также использовать двоичный поиск для определенного числа. Но я не знаю, как разрушить эту проблему.
Любые идеи?
Ответы
Ответ 1
Прежде всего, вы можете сортировать свою последовательность. Для отсортированной последовательности достаточно проверить, что A[i] + A[j] > A[k]
для i < j < k
, потому что A[i] + A[k] > A[k] > A[j]
и т.д., Поэтому остальные 2 неравенства автоматически верны.
(С этого момента i < j < k
.)
Затем достаточно проверить, что A[i] + A[j] > A[j+1]
, потому что другие A[k]
еще больше (поэтому, если неравенство выполняется для некоторого k
, оно выполняется и для k = j + 1
).
Далее, достаточно проверить, что A[j-1] + A[j] > A[j+1]
, потому что другие A[i]
еще меньше (поэтому, если для некоторого i
выполняется неравенство, оно выполняется и для i = j - 1
).
Итак, у вас есть только линейная проверка: вам нужно проверить, верно ли хотя бы один j
A[j-1] + A[j] > A[j+1]
.
В целом O(N log N) {sorting} + O(N) {check} = O(N log N)
.
Адресация комментария об отрицательных числах: действительно, это то, что я не рассматривал в исходном решении. Рассмотрение отрицательных чисел не сильно меняет решение, так как никакое отрицательное число не может быть частью треугольной тройки. Действительно, если A[i]
, A[j]
и A[k]
образуют треугольную тройку, то A[i] + A[j] > A[k]
, A[i] + A[k] > A[j]
, откуда следует 2 * A[i] + A[j] + A[k] > A[k] + A[j]
, поэтому 2 * A[i] > 0
, поэтому A[i] > 0
и по симметрии A[j] > 0
A[k] > 0
.
Это означает, что мы можем безопасно удалить отрицательные числа и нули из последовательности, которая выполняется в O(log n)
после сортировки.
Ответ 2
В Java:
public int triangle2(int[] A) {
if (null == A)
return 0;
if (A.length < 3)
return 0;
Arrays.sort(A);
for (int i = 0; i < A.length - 2 && A[i] > 0; i++) {
if (A[i] + A[i + 1] > A[i + 2])
return 1;
}
return 0;
}
Ответ 3
Вот реализация алгоритма, предложенного Владом. Теперь вопрос требует, чтобы избежать переполнения, поэтому приведение к long long
.
#include <algorithm>
#include <vector>
int solution(vector<int>& A) {
if (A.size() < 3u) return 0;
sort(A.begin(), A.end());
for (size_t i = 2; i < A.size(); i++) {
const long long sum = (long long) A[i - 2] + (long long) A[i - 1];
if (sum > A[i]) return 1;
}
return 0;
}
Ответ 4
Сначала выполните быстрый сортировку, это, как правило, займет nlogn.
И вы можете опустить третий цикл двоичным поиском, который может принимать log (n).
Таким образом, сложность сводится к n ^ 2log (n).
Ответ 5
В рубине о
def check_triangle (_array)
for p in 0 .. _array.length-1
for q in p .. _array.length-1
for r in q .. _array.length-1
return true if _array[p] + _array[q] > _array[r] && _array[p] + _array[r] > _array[q] && _array[r] + _array[q] > _array[p]
end
end
end
return false
end
Просто поместите его на выбранный вами язык
Ответ 6
Решение 100/100 php: http://www.rationalplanet.com/php-related/maxproductofthree-demo-task-at-codility-com.html
function solution($A) {
$cnt = count($A);
sort($A, SORT_NUMERIC);
return max($A[0]*$A[1]*$A[$cnt-1], $A[$cnt-1]*$A[$cnt-2]*$A[$cnt-3]);
}
Ответ 7
Python:
def solution(A):
A.sort()
for i in range(0,len(A)-2):
if A[i]+A[i+1]>A[i+2]:
return 1
return 0
Сортировка: Логарифмическая сложность O (N log N)
Ответ 8
У меня есть другое решение для подсчета треугольников. Его временная сложность - O (N ** 3) и занимает много времени для обработки длинных массивов.
Private Function solution(A As Integer()) As Integer
' write your code in VB.NET 4.0
Dim result, size, i, j, k As Integer
size = A.Length
Array.Sort(A)
For i = 0 To Size - 3
j = i + 1
While j < size
k = j + 1
While k < size
If A(i) + A(j) > A(k) Then
result += 1
End If
k += 1
End While
j += 1
End While
Next
Return result
End Function
Ответ 9
Решение PHP:
function solution($x){
sort($x);
if (count($x) < 3) return 0;
for($i = 2; $i < count($x); $i++){
if($x[$i] < $x[$i-1] + $x[$i-2]){
return 1;
}
}
return 0;
}
Ответ 10
Реверсирование цикла из решения Vlad для меня кажется более понятным.
Уравнение A [j-1] + A [j] > A [j + 1] можно было бы заменить на A [k-2] + A [k-1] > A [k]. Объяснив слова, сумма последних двух наибольших чисел должна быть больше, чем текущее наибольшее значение, которое проверяется (A [k]). Если результат добавления двух последних наибольших чисел (A [k-2] и A [k-1]) не больше A [k], мы можем перейти к следующей итерации цикла.
Кроме того, мы можем добавить проверку на отрицательные числа, о которых говорил Влад, и остановить цикл раньше.
int solution(vector<int> &A) {
sort(A.begin(),A.end());
for (int k = A.size()-1; k >= 2 && A[k-2] > 0 ; --k) {
if ( A[k-2]+A[k-1] > A[k] )
return 1;
}
return 0;
}
Ответ 11
Здесь мое решение в С#, которое получает 90% правильности (неправильный ответ возвращается для теста extreme_arith_overflow1 -overflow test, 3 MAXINTs-
) и 100% производительности.
private struct Pair
{
public int Value;
public int OriginalIndex;
}
private static bool IsTriplet(Pair a, Pair b, Pair c)
{
if (a.OriginalIndex < b.OriginalIndex && b.OriginalIndex < c.OriginalIndex)
{
return ((long)(a.Value + b.Value) > c.Value
&& (long)(b.Value + c.Value) > a.Value
&& (long)(c.Value + a.Value) > b.Value);
}
else if (b.OriginalIndex < c.OriginalIndex && c.OriginalIndex < a.OriginalIndex)
{
return ((long)(b.Value + c.Value) > a.Value
&&(long)(c.Value + a.Value) > b.Value
&& (long)(a.Value + b.Value) > c.Value);
}
// c.OriginalIndex < a.OriginalIndex && a.OriginalIndex < b.OriginalIndex
return ((long)(c.Value + a.Value) > b.Value
&& (long)(a.Value + b.Value) > c.Value
&& (long)(b.Value + c.Value) > a.Value);
}
public static int Triplets(int[] A)
{
const int IS_TRIPLET = 1;
const int IS_NOT_TRIPLET = 0;
Pair[] copy = new Pair[A.Length];
// O (N)
for (var i = 0; i < copy.Length; i++)
{
copy[i].Value = A[i];
copy[i].OriginalIndex = i;
}
// O (N log N)
Array.Sort(copy, (a, b) => a.Value > b.Value ? 1 : (a.Value == b.Value) ? 0 : -1);
// O (N)
for (var i = 0; i < copy.Length - 2; i++)
{
if (IsTriplet(copy[i], copy[i + 1], copy[i + 2]))
{
return IS_TRIPLET;
}
}
return IS_NOT_TRIPLET;
}
Ответ 12
public static int solution(int[] A) {
// write your code in Java SE 8
long p, q, r;
int isTriangle = 0;
Arrays.sort(A);
for (int i = 0; i < A.length; i += 1) {
if (i + 2 < A.length) {
p = A[i];
q = A[i + 1];
r = A[i + 2];
if (p >= 0) {
if (Math.abs(p) + Math.abs(q) > Math.abs(r) && Math.abs(q) + Math.abs(r) > Math.abs(p) && Math.abs(r) + Math.abs(p) > Math.abs(q))
return 1;
}
} else return 0;
}
return isTriangle;
}
Вышеупомянутая реализация - линейная по времени сложность. Концепция проста в использовании formaula, которую они дали для извлечения серии триплетов отсортированных элементов.
Ответ 13
Здесь простое решение в Java с 100/100 счетом
class Solution {
public int solution(int[] A) {
// write your code in Java SE 8
Arrays.sort(A);
for (int i = 0; i < A.length - 2; ++i) {
long a = A[i] + (long) A[i + 1];
long b = A[i + 2];
if (a > b) {
return 1;
}
}
return 0;
}
}