从三个数组中选择满足条件的三个数

Given 3 arrays, pick 3 nos, one from each array, say a,b,c such that |a-b|+|b-c|+|c-a| is minimum

如果假设a >=b >= c, 就是求2(a-c), 也就是说最终的值只与最大值和最小值有关

我的想法是将这三个数组的元素加上所属数组类别的信息,然后进行排序,下面的工作就是和最短链珠的做法一样了,依次找出包含a,b,c数组元素的最小span,然后计算这个span最大值和最小值之差。


网上的做法更为精巧,整个是3数组归并的过程。首先计算三元组(ai,bj,ck)的值,然后找出三元组中最小的元素,然后将这个最小元素所属的数组的指针加1.

可以用反证法证明上述思路,设 ai >= bj >= ck

如果j++, 那么获得的新的三元组的值大于等于之前的三元组

如果i++,那么获得的新的三元组的值大于等于之前的三元组

所以只有k++, 才有可能获得的新元祖的值小于之前的三元组


int CalcABS(int a, int b, int c)
{
        return abs(a-b) + abs(a-c) + abs(b-c);
}

int GetMin(vector<int>& vec)
{
        assert(!vec.empty());
        
        int nMin = vec[0];
        for (int i = 0; i < vec.size(); i++)
        {
                if (vec[i] < nMin)
                        nMin = vec[i];
        }

        return nMin;
}

int GetABC(int a[], int na, int b[], int nb, int c[], int nc, int& sa, int& sb, int& sc)
{
        assert(a && na>0 && b && nb>0 && c && nc>0);

        sort(a, a+na);
        sort(b, b+nb);
        sort(c, c+nc);

        int i = 0;
        int j = 0;
        int k = 0;
        sa = sb = sc = 0;

        int nMin = CalcABS(a[i], b[j], c[k]);
        while (i != na-1 || j != nb-1 || k != nc-1)//应该用&&连接
        {
                vector<int> vec;
                if (i != na-1) vec.push_back(a[i]);
                if (j != nb-1) vec.push_back(b[j]);
                if (k != nc-1) vec.push_back(c[k]);

                int nRes = GetMin(vec);

                if (i != na-1 && a[i] == nRes)
                        i++;
                else if (j != nb-1 && b[j] == nRes)
                        j++;
                else k++;

                nRes = CalcABS(a[i], b[j], c[k]);
                if (nRes < nMin)
                {
                        sa = a[i];
                        sb = b[j];
                        sc = c[k];
                        nMin = nRes;
                }
        }

        return nMin;
}


你可能感兴趣的:(从三个数组中选择满足条件的三个数)