首页 > 代码库 > 序列相关的趣题 之二

序列相关的趣题 之二

(4)数组中找到两个数和的绝对值最小 

像不像2-SUM? 不多解释,主要是绝对值大的动就行,两头扫的方法真好!当然要先排序,出去排序就是O(n),算上排序的话退化到O(nlogn)

这也是codility上的问题,还没来得及整理。

上个代码:

// you can also use includes, for example:
// #include <algorithm>

#include <algorithm>

int ab(int x) {
    return (x >= 0)?x:(-x);
}

int f(int x,int y) {
    return ab(x + y);
}

int solution(vector<int> &A) {
    // write your code in C++98
    vector<int> a = A;
    sort(a.begin(),a.end());
    int answer = f(a[0],a[0]); 
    for (int i = 0, j = a.size() - 1; i <= j; ) {
        answer = min(answer, f(a[i], a[j]));
        if (ab(a[i]) > ab(a[j])) {
            ++i;
        }
        else {
            --j;
        }
        
    }
    return answer;
}


(5) 给定非负实数数组,已经按照非递减排好序了。设数组为C,长度为N,0 ≤ P < Q < N and C[P] * C[Q] ≥ C[P] + C[Q]的下标对数。

codility上问题是这样定义的C[i] = A[i] + B[i] / 10^6,A是整数部分[0..1000], 而B是分数部分的分子[0..999999] (分数部分的分母统一是1000000)。时间复杂度要O(N)

这个题其实就是分析要细致,再次强调数个数并不一定要枚举。我们无非要计算a * b >= a + b,由于都是正数,再由对称性我们只考虑0<=a<=b的情况,

考虑较大的数b可能的情形

(1) b == 0 只有a == 0才符合条件

  (2)   0 < b < 2 无解

  (3) b >= 2 则 b / (b - 1) <= a <= b 


注意到如果我们由小到大 枚举b, 对条件(3) 那个b / (b - 1) = 1 / (1 - 1 / b)  是单调减小的,所以对更大的b,我们考虑a的时候,之前合法的a也是合法的,这是O(N)的关键,我们只需要记录上一次最后一个合法的a的位置即可。

上代码:


// you can use includes, for example:
// #include <algorithm>

// you can write to stdout for debugging purposes, e.g.
// cout << "this is a debug message" << endl;

const int M = 1000000000;
const int W = 1000000;

long long cmp(long long x1,long long y1, long long x2, long long y2) { // x1 / y1 - x2 / y2
    return x1 * y2 - x2 * y1;   
}
int solution(vector<int> &A, vector<int> &B) {
    // write your code in C++11
    /*
        let a <= b
        a * b >= a + b
        b == 0 a == 0
        0 < b < 2  no solution
        b >= 2
        b / (b - 1) <= a <= b 
    */
    int n = A.size(), num0 = 0, last = n, answer = 0;
    for (int i = 0; i < n; ++i) {
        if ((A[i] == 0) && (B[i] == 0)) { // b == 0
            answer += num0++;
        }
        else if (A[i] >= 2) { // b >= 2
            if (last >= n) {
                last = i - 1;
            }
            int x = A[i] * W + B[i], y = x - W;
            for (; (last >= 0) && (cmp(A[last] * W + B[last],W ,x ,y) >= 0); --last)
            ;
            answer += i - 1 - last;
        }
        if (answer >= M) {
            return M;
        }
       // printf("%d %d\n",i, answer);
        
    }
    return answer;
        
}