二分法模板以及例题 (三)

167. 两数之和 II - 输入有序数组
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]。
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2]
解题思路:首先散列表可以直接秒了,双指针也秒了
二分法是这里面性能不好的一种做法nlog(n),得遍历后找,其他两个O(n)

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        for(int i=0, j=numbers.size()-1;i<j;i++){
            int l =i+1,r =j;
            int mid;
            while(l<r){
                mid = (l+r+1)/2;
                if(numbers[i]+numbers[mid]>target)r=mid-1;
                else l=mid;
            }
            if(numbers[i]+numbers[l]==target)return {i+1,l+1};
        }
        return {};
    }
};

240. 搜索二维矩阵 II
在这里插入图片描述
解题思路:双指针秒了,ij从左下角开始,搜索二维矩阵I 是拍平二维数组然后二分,这题应该也是考虑如何拍平
278. 第一个错误的版本
你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。

假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。

你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

这里也可以二分,分从这以后的版本都是错误,从这以前的版本可能正确的,直接使用二分法模板一

// The API isBadVersion is defined for you.
// bool isBadVersion(int version);

class Solution {
public:
    int firstBadVersion(int n) {
        int left=0;
        int right=n;
        int mid=0;
        while(left<right){
            mid = (right - left) / 2 + left; 
            if(isBadVersion(mid)){
                right=mid;
            }
            else
                left=mid+1;
                

        }
        return left;
    }
};

300. 最长递增子序列
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
解题思路:这明显是dp啊
dp五部曲:TODO

class Solution {
public:

    int lengthOfLIS(vector<int>& nums) { 
        int ans=1;
        int n=nums.size();
        vector<int>dp(n,1);
        for(int i=0;i<n;++i)
        {
            for(int j=0;j<i;++j)
            {
                if(nums[i]>nums[j])
                {
                    dp[i]=max(dp[i],dp[j]+1);
                    if(ans<dp[i])
                        ans=dp[i];
                }
            }
            
        }
        return ans;
    }

};

349. 两个数组的交集
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]
解题思路:暴力做法使用stl set去重去交集,空间换时间,性能不会差(突然想到,然后如果是多数组取交集呢)

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> result_set; // 存放结果
        unordered_set<int> nums_set(nums1.begin(), nums1.end());
        for (int num : nums2) {
            // 发现nums2的元素 在nums_set里又出现过
            if (nums_set.find(num) != nums_set.end()) {
                result_set.insert(num);
            }
        }
        return vector<int>(result_set.begin(), result_set.end());
    }
};

611. 有效三角形的个数
输入: nums = [2,2,3,4]
输出: 3
解释:有效的组合是:
2,3,4 (使用第一个 2)
2,3,4 (使用第二个 2)
2,2,3
解题思路:暴力点的做法就选两个(双指针)之后更具二分法找到第一个位两数之和的位置

class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        int n = nums.size();
        sort(nums.begin(), nums.end());
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                int left = j + 1, right = n - 1, k = j;
                while (left < right) {
                    int mid = (left + (long long)right+1 )/2;
                    if (nums[mid] < nums[i] + nums[j]) {
                        
                        left = mid;
                    }
                    else {
                        right = mid - 1;
                    }
                }
                if (left == right && nums[i] + nums[j] > nums[left]) ans += right-j;
                
            }
        }
        return ans;
    }

};

658. 找到 K 个最接近的元素
输入:arr = [1,2,3,4,5], k = 4, x = 3
输出:[1,2,3,4]
解题思路:二分法找到对应的位置,应该插入的位置,如刚好大于等于位置,然后窗口函数了双指针计算一下

class Solution {
public:
    vector<int> findClosestElements(vector<int>& arr, int k, int x) {
        int right = lower_bound(arr.begin(), arr.end(), x) - arr.begin();
        int left = right - 1;
        while (k--) {
            if (left < 0) {
                right++;
            } else if (right >= arr.size()) {
                left--;
            } else if (x - arr[left] <= arr[right] - x) {
                left--;
            } else {
                right++;
            }
        }
        return vector<int>(arr.begin() + left + 1, arr.begin() + right);
    }
};

官方还提供了一个思路,根据差值做个排序,选出窗口大小的值

class Solution {
public:
    vector<int> findClosestElements(vector<int>& arr, int k, int x) {
        sort(arr.begin(), arr.end(), [x](int a, int b) -> bool {
            return abs(a - x) < abs(b - x) || abs(a - x) == abs(b - x) && a < b;
        });
        sort(arr.begin(), arr.begin() + k);
        return vector<int>(arr.begin(), arr.begin() + k);
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值