Leetcode2300——咒语和药水的成功对数

这道题我想的是对药水数组从大到小排序,然后从大到小开始计算遍历,每当发现没办法大于了那后面也没有必要考虑了就直接break,但是还是超时了:

class Solution {
public:
    vector<int> successfulPairs(vector<int>& spells, vector<int>& potions, long long success) {
        sort( potions.begin(), potions.end(), greater<int>());
        // 先从大到小排序
        vector<int> result(spells.size(), 0);
        for(int i = 0; i < spells.size(); i++){
            for( int j = 0; j < potions.size(); j++){
                if( (long long)spells[i]*potions[j] >= success){
                    result[i]++;
                }
                else{
                    break;
                }
            }
        }
        return result;
    }
};

那么题解中的思路在于:

先计算目标值除以当前的毒药数值,得到我们最小需要的药水强度,然后再去药水数组中进行操作该数值的位置即可,用到类似于二分查找的算法来实现。或者是直接用二分法查找出每一个数值然后查看它们是否能够跟当前毒药值相乘大于目标值,都是相同的思路,就是很典型的二分法!

最近还没有复习到排序和查找的相关章节,一下子还是没能够反应过来。

class Solution {
public:
    vector<int> successfulPairs(vector<int>& spells, vector<int>& potions, long long success) {
        sort( potions.begin(), potions.end());
        for( int & x: spells){
            long long target = (success - 1) / x;
            if( target < potions.back()){
                x = potions.end() - upper_bound(potions.begin(), potions.end(), (int) target);
            } else {
                x = 0;
            }
        }
        return spells;
    }
};

参考了某段题解的写法,由于它写得很简洁,那么我尽可能去理解代码,其中具体要关注这行代码:

x = potions.end() - upper_bound(potions.begin(), potions.end(), (int) target);
//如果"target"小于"potions"向量的最后一个元素
//那么将x更新为"potions"向量中大于等于"target"的元素数量。
//这是通过使用二分查找函数"upper_bound"来实现的
//该函数返回指向第一个大于等于给定值的元素的迭代器。
//然后,通过减去这个迭代器与"potions.begin()"之间的距离来计算大于等于"target"的元素数量。

然后总感觉这样写不够清晰,因此自己用二分法重新写了一遍:

class Solution {
public:
    vector<int> successfulPairs(vector<int>& spells, vector<int>& potions, long long success) {
        sort( potions.begin(), potions.end());
        vector<int>result;
        for(int i = 0; i < spells.size(); i++){
            long long target = ( success - 1) / spells[i];
            int left = 0;
            int right = potions.size() - 1;
            while( left <= right){
                int mid = ( right - left) / 2 + left;
                if((long long) potions[mid] <= target){
                    left = mid + 1;
                }
                else{
                    right = mid - 1;
                }
            }
            result.push_back( potions.size() - left );
        }
        return result;
    }
};

那么需要注意几个点:
为何 t a r g e t = ( s u c c e s s − 1 ) / s p e l l s [ i ] target= ( success - 1) / spells[i] target=(success1)/spells[i]**:**因为如果是本来目标是查找 p o t i o n s [ i ] > = ⌈ s u c c e s s s p e l l [ i ] ⌉ potions[i] >= \lceil \frac{success}{spell[i]} \rceil potions[i]>=spell[i]success,经过化简即可得: ⌈ s u c c e s s s p e l l [ i ] ⌉ = ⌊ s u c c e s s + s p e l l [ i ] − 1 s p e l l [ i ] ⌋ = ⌊ s u c c e s s − 1 s p e l l [ i ] ⌋ + 1 \lceil \frac{success}{spell[i]} \rceil=\lfloor \frac{success + spell[i] -1}{spell[i]}\rfloor=\lfloor \frac{success-1}{spell[i]} \rfloor+1 spell[i]success=spell[i]success+spell[i]1=spell[i]success1+1,那么此时我们只要让 p o t i o n s [ i ] > ⌊ s u c c e s s − 1 s p e l l [ i ] ⌋ potions[i] > \lfloor \frac{success-1}{spell[i]} \rfloor potions[i]>spell[i]success1就可以满足上述大于等于式子。
那么在得知上述寻找条件后,我们就相当于要在数组potions找到大于目标值 t a r g e t target target的元素数目,因此在二分法的时候有所不同,每次只要是小于等于(因为我们只希望大于)我们就缩小左边界,大于的时候就缩小右边界,那么这样的话(可以自己用例子模拟两种情况,分别是目标值在数组中和目标值不在数组中),最后得到大于目标值的数目都是 p o t i o n s . s i z e ( ) − l e f t potions.size() - left potions.size()left

你可能感兴趣的:(力扣刷题记录,算法,数据结构,c++,力扣)