满足和为定值的两个数或多个数

一、和接近定值的三个数

给定一个数组,任意选三个数,求这三个数之和与给定的数最接近的组合。例如给定数组S={-1,2,1,-4},定值target=1。则结果是(-1+2+1)=2。

解答:先对数组排序,之后每次选一个数,然后再固定两端,用两端向中间靠近的方式找。时间复杂度O(n^2),空间复杂度O(1)。

int threeSumClosest(vector<int> &num, int target) {
        sort(num.begin(),num.end());
        int m = num[0]+num[1]+num[2];
        for(int i=0; i<num.size(); i++){
            // 先选中元素i,再固定端点i+1和n-1,向中间移动
            int low = i+1, high = num.size()-1;
            while(low < high){
                int cur = num[i]+num[low]+num[high];
                if(abs(cur-target) < abs(m-target)) m = cur;
                if(m == target) return m;   // 如果当前和跟目标值相等,则已经找到最接近的值
                if(cur < target) low++;     // 当前当前和小于目标值,则左端点右移
                else high--;
            }
        }
        return m;
    }

扩展:三个数和为某个定值(去重);四个数和为某个定值(去重,在外层再加一个for循环,时间复杂度O(n^3))

二、和为定值的两个数

给定一个数组,任意选两个数,找出两个数之和等于某个定值,返回这两个数的下标(小下标在前)。

解答:用hashmap存下当前元素ai相对于target的差(target-ai)。之后再扫描一遍数组查看是否有数在hashmap之中。时间复杂度O(n),空间复杂度O(n)。

vector<int> twoSum(vector<int> &numbers, int target) {
        vector<int> ret;
        // hashmap
        unordered_map<int,int> m;
        int n = numbers.size();
        // 记录元素与target的差值,value记录下标
        for(int i=0; i<n; i++) m.insert(make_pair(target-numbers[i],i));
        for(int i=0; i<n; i++){
            // 查找hashmap里面是否存在
            if(m.find(numbers[i]) != m.end() && i != m[numbers[i]]){ 
                ret.push_back(min(i+1,m[numbers[i]]+1));
                ret.push_back(max(i+1,m[numbers[i]]+1));
                break;
            }
        }
        return ret;
    }

扩展:若不要求返回下标,而是返回具体哪两个数,则可以使用先排序,然后再首尾指针的方法来做。时间复杂度O(nlogn),空间复杂度O(1)。

点赞