Java 找到递增的三元组,使总和小于或等于k
这个问题更容易或更流行的版本是找到具有给定总和的三元组。但是这一个附加了一个条件。查找未排序数组中的所有三元组,以便Java 找到递增的三元组,使总和小于或等于k,java,algorithm,triplet,Java,Algorithm,Triplet,这个问题更容易或更流行的版本是找到具有给定总和的三元组。但是这一个附加了一个条件。查找未排序数组中的所有三元组,以便 d[i]+d[j]+d[k] <= t; & d[i]<d[j]<d[k] where i<j<k d[i]+d[j]+d[k]哈哈,很高兴看到这里引用了我的博客。然而,你链接的帖子解决了d[i]+d[j]+d[k]
d[i]+d[j]+d[k] <= t; & d[i]<d[j]<d[k] where i<j<k
d[i]+d[j]+d[k]哈哈,很高兴看到这里引用了我的博客。然而,你链接的帖子解决了d[i]+d[j]+d[k]
我认为您应该清楚地询问数组是否已排序,那么您的问题是对
所以对于您的情况(假设数组是排序的),您只需要确保i,j,k总是按递增顺序排列
因此,考虑到N个元素和一个目标T,一个经典的昼夜方法(即j,k相互移动),您可以尝试:
for (int i = 0; i < N, i++) {
int j = i;
int k = N-1;
while (j < k) {
int currSum = i+j+k;
if (currSum < T) { // increase sum
j++;
}
else if (currSum > T) { // decrease sum
k--;
}
else {
System.out.println("Found triple: " + i + ", " + j + ", " + k);
j++;
}
}
}
for(int i=0;iT){//减少sum
k--;
}
否则{
System.out.println(“发现三元组:“+i+”,“+j+”,“+k”);
j++;
}
}
}
//i、 j,k保证为递增顺序
如果数组未排序,则可以执行优化的蛮力操作。求出所有的i,j,使得d[i] 如果修复i和j,则必须在数组中找到一个小于或等于t-d[i]-d[j]
的数字。存储数组的第二个版本,其中每个元素也存储其索引。按递增顺序排序此数组
现在,对于具有i
的所有对i,j
(这只是两个嵌套的循环),您可以对t-d[i]-d[j]
进行二进制搜索;如果存在这样一个数字,则检查从左到右的所有数字,并检查其索引是否大于j,如果是,则添加到输出中。复杂性是O(n*n*lgn+k)
其中k是满足条件的输出数
编辑:OP的第一篇帖子是=
现在他改成了首先,值得指出的是,最坏情况下的复杂性不可能比O(n^3)
更好,因为在最坏情况下有O(n^3)
三元组,显然每个三元组至少需要恒定的时间来存储/打印它。还有一个非常简单和明显的O(n^3)
算法
这就是说,这里有一个复杂度O(n^2 log n+k)
的方法,其中k
是答案的大小。(尽管@saadtaame声称具有相同的复杂性,但他的估计中存在一个问题,请参见其答案下面的评论)
首先,让我们修复一个元素,比如a[i]
。现在,让我们创建一个新数组b
,由a
中的所有元素组成,它们的索引都大于i
,值也大于a[i]
。现在问题归结为在b
中找到两个索引j
和k
,例如j
和b[j]
为此,我们可以使用某种排序集,比如Java中的TreeSet
。我们将迭代k
的所有可能值,在TreeSet
中维护索引小于k
的所有元素。由于TreeSet
只包含索引小于k
(因为我们构建它的方式)且大于i
(因为b
只包含这样的元素)的元素,并且被排序,因此TreeSet
中的每个元素q
的值都小于b[k]
形成一个答案三元组(a[i],q,b[k])
。下面是一个伪代码:
for i from 0 to size(a):
b = empty array
for j from i + 1 to size(a):
if a[j] > a[i]:
add a[j] to b
treeSet = new TreeSet
for k from 0 to size(b):
for each element 'e' in the treeSet in sorted order: // (1)
if e >= b[k] or a[i] + e + b[k] > t:
break
add (a[i], e, b[k]) to the answer // (2)
add b[k] to the treeSet // (3)
这里,如果我们返回的元素数小于O(n^2 logn)
,那么算法的复杂性将是O(n^2 logn)
。原因是,行(2)
被精确地执行k次,因此可以忽略(并且在树集上迭代已经在元素数量上摊销了线性时间),而内部循环的其余部分:在(1)
处初始化迭代器,并在(3)处向树集添加一个元素
最多都是O(log n)
操作
编辑:这里有一个小例子。假设数组是a=[5,3,7,9,8,1]
和t=20
。然后i
首先指向5
,我们将5
和更大的元素放到b
,因此b=[7,9,8]
。然后k
将进行三次迭代:
b[k]=7
。此时树集是空的,因此不会发生任何事情,7
被添加到树集中
b[k]=9
。此时树集有元素7。它小于9,但和5+7+9>20
,因此我们中断了树集上的迭代。我们把9
放在树集合中,集合现在包含(7,9)
b[k]=8
。我们在树集上迭代。对于元素7,两个条件都满足(7<8和5+7+8条件,其中i我认为你可以做得比O(n^2 log n+k)稍微好一些
假设您位于位置i。i(1…i)之前的所有元素都存储在一个BST中,i(1+1…n)之后的所有元素都存储在第二个BST中
在第一棵树中,找到最小的元素A[j],使A[j]
现在,在第二棵树中找到最大的元素A[k],这样A[k]
我们要做的是首先使用快速排序对数字进行排序,这样可以避免额外的循环,默认情况下i
我的逻辑是d[i]+d[j]+d[k]查找递增的三元组,使总和小于或等于k:
# include <stdio.h>
void find3Numbers(int A[], int arr_size, int sum)
{
int l, r;
for (int i = 0; i < arr_size-2; i++){
for (int j = i+1; j < arr_size-1; j++){
for (int k = j+1; k < arr_size; k++){
if (A[i] + A[j] + A[k] <= sum)
printf("Triplet is %d, %d, %d\n", A[i], A[j], A[k]);
}
}
}
}
int main()
{
int A[] = {1, 2, 3, 4, 6};
int sum = 8;
int arr_size = sizeof(A)/sizeof(A[0]);
find3Numbers(A, arr_size, sum);
return 0;
}
#包括
vo
Initialization: firstTree={A[1]}, secondTree = {A[3]..A[n]}
For i = 2:(n-1) do:
j = getFirst(firstTree)
firstIter = true;
while(true)
if A[j]>=A[i] or A[j]+A[i]>t break
if firstIter:
k = binSearch(secondTree, t - A[i] -A[j])
firstIter=false
else
if bestk<0:
break;
k = bestk
bestk = -1
jnext = nextElement(firstTree, A[j]);
while (A[k]>A[i]):
print (A[j], A[i], A[k])
if bestk<0 and A[i]+A[jnext]+A[k] < t:
bestk = k;
k = prevElement(secondTree, A[k])
Add(firstTree, A[i])
Remove(secondTree, A[i+1])
Arrays.sort(d);
for (int i = 0; i < d.length; i++) {
for (int j = i + 1; j < d.length; j++) {
int firstNumber = d[i];
int secondNumber = d[j];
int temp = t - firstNumber - secondNumber;
if ((firstNumber < secondNumber) && (secondNumber < temp)) {
int index = Arrays.binarySearch(d, temp);
if (index >= 0) {
......
}
}
}
}
}
# include <stdio.h>
void find3Numbers(int A[], int arr_size, int sum)
{
int l, r;
for (int i = 0; i < arr_size-2; i++){
for (int j = i+1; j < arr_size-1; j++){
for (int k = j+1; k < arr_size; k++){
if (A[i] + A[j] + A[k] <= sum)
printf("Triplet is %d, %d, %d\n", A[i], A[j], A[k]);
}
}
}
}
int main()
{
int A[] = {1, 2, 3, 4, 6};
int sum = 8;
int arr_size = sizeof(A)/sizeof(A[0]);
find3Numbers(A, arr_size, sum);
return 0;
}
Execution :
arr_size = 5
Step:1 i=0 and i<3 (arr_size-2)
j=1 and j<4 (arr_size-1)
k=2 and k<5 (arr_size)
A[0]+A[1]+A[2]<=sum --> 1+2+3 <=8 --> 6<=8 ( true )
k=3 and k<5
A[0]+A[1]+A[3]<=sum --> 1+2+4 <=8 --> 7<=8 ( true )
k=4 and k<5
A[0]+A[1]+A[4]<=sum --> 1+2+6 <=8 --> 9<=8 ( false )
j=2 and j<4
k=3 and k<5
A[0]+A[2]+A[3]<=sum --> 1+3+4 <=8 --> 8<=8 ( true )
k=4 and k<5
A[0]+A[2]+A[4]<=sum --> 1+3+6 <=8 --> 10<=8 ( false )
j=3 and j<4
k=4 and k<5
A[0]+A[3]+A[4]<=sum --> 1+4+6 <=8 --> 11<=8 ( false )
j=4 and j<4 (false)
Step:2 i=1 and i<3
j=2 and j<4
k=3 and k<5
A[1]+A[2]+A[3]<=sum --> 2+3+4 <=8 --> 9<=8 ( false )
k=4 and k<5
A[1]+A[2]+A[4]<=sum --> 2+3+6 <=8 --> 11<=8 ( false )
j=3 and j<4
k=4 and k<5
A[1]+A[3]+A[4]<=sum --> 2+4+6 <=8 --> 12<=8 ( false )
j=4 and j<4 (false)
Step:3 i=2 and i<3
j=3 and j<4
k=4 and k<5
A[2]+A[3]+A[4]<=sum --> 3+4+6 <=8 --> 13<=8 ( false )
j=4 and j<4 (false)
Step:4 i=3 and i<3 (false)
import java.util.*;
public class Main
{
public static void main(String[] args) {
int arr[]={1,2,3,3,4,4,9,10,11,342,43};
int n=arr.length,t=98,cnt=0;
Arrays.sort(arr);
for(int k=2;k<n;k++)
{
TreeMap<Integer,Integer> ts1=new TreeMap<>();
for(int j=0;j<k;j++)
{
if(arr[j]==arr[k])
break;
int i=Math.min(t-arr[k]-arr[j],arr[j]); //try to get the number of elements less than arr[j] and target-arr[k]-arr[j]
cnt+=(ts1.lowerKey(i)==null?0:ts1.get(ts1.lowerKey(i)));
if(ts1.containsKey(arr[j]))
ts1.put(arr[j],ts1.get(arr[j])+1);
else
{
Integer val=ts1.lowerKey(arr[j]);
ts1.put(arr[j],1+(val==null?0:ts1.get(val)));
}
}
}
System.out.println(cnt);
}
}
#include <bits/stdc++.h>
using namespace std;
vector<int> helper(vector<int> &A, int T)
{
vector<int> ans;
int N = A.size();
for (int i = 0; i < N; i++)
{
vector<int> B;
for (int j = i + 1; j < N; j++)
{
if (A[j] > A[i])
B.push_back(A[j]);
}
set<int> S;
set<int>::iterator it;
for (int k = 0; k < B.size(); k++)
{
for (auto it = S.begin(); it != S.end(); it++)
{
int sum = A[i] + *it + B[k];
if (*it >= B[k] || sum > T)
break;
cout << A[i] << " - " << *it << " - " << B[k] << endl;
ans.push_back(sum);
}
S.insert(B[k]);
}
}
return ans;
}
vector<int> helper1(vector<int> &A, int T)
{
vector<int> ans;
int N = A.size();
for (int i = 0; i < N - 2; i++)
{
for (int j = i + 1; j < N - 1; j++)
{
for (int k = j + 1; k < N; k++)
{
int sum = A[i] + A[j] + A[k];
if (sum <= T && A[i] < A[j] && A[j] < A[k])
{
cout << A[i] << " - " << A[j] << " - " << A[k] << endl;
ans.push_back(sum);
}
}
}
}
return ans;
}
void print(vector<int> &A)
{
for (int a : A)
cout << a << " ";
cout << endl;
}
int main()
{
vector<int> A({1, 4, 12, 3, 6, 10, 14, 3});
int T = 11;
vector<int> ans = helper(A, T); // O(n^2log n)
print(ans);
vector<int> ans1 = helper1(A, T); // )(n^3)
print(ans1);
return 0;
}