【leetcode】二分法题目记录:leetcode33和leetcode153

一、在前面

最近准备了个面试,算法题考到了二分法。故而刷了leetcode上几个经典的二分法题目。这里记录两个medium难度的二分法题目。

二、leetcode33

(1)题目描述

假设按照升序排序的数组在预先未知的某个点上进行了旋转。

( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。

你可以假设数组中不存在重复的元素。

你的算法时间复杂度必须是 O(log n) 级别。

示例 1:

输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4

示例 2:

输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1

(2)代码

class Solution {
    
    
public:
    int search(vector<int>& nums, int target) {
    
    
        int begin=0;
        int end=nums.size()-1;
        int index;
        while(begin<=end)
        {
    
    
            index=(begin+end)/2;
            if(nums[index]==target)
                return index;
            else if(nums[end]>=nums[index])
            {
    
    
                if(target>=nums[index]&&target<=nums[end])
                    begin=index+1;
                else
                    end=index-1;
            }
            else
            {
    
    
                if(target>=nums[begin]&&target<=nums[index])
                    end=index-1;
                else
                    begin=index+1;
            }
        }
        return -1;
    }
};

(3)分析

这个题目的重点是要知道,每次二分的时候,二分位置(也就是上面代码中的index)的左右两侧,也就是代码中的[begin,index]和[index,end]这部分的数据中,必定有一个是单调递增的。因为这里的旋转数组的定义,就决定了这个。这样的话,我们每次在while(begin<=end)循环中,就可以通过判断nums[end]和nums[index]这两个数据的大小,来判断这个递增区间是[begin,index]还是[index,end]。如果递增区间是[begin,index],通过判断target是否大于nums[begin],小于nums[index],就可以知道target是否在[begin,index]这个区间。如果在[begin,index]这个区间就相应的将其作为下一个二分的区间,否则就将另外一个[index,end]作为下一个二分的区间。
重点就是要想清楚,每次二分的时候,左右两个区间中,必定有一个递增的。

三、leetcode153

(1)题目描述

假设按照升序排序的数组在预先未知的某个点上进行了旋转。

( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

请找出其中最小的元素。

你可以假设数组中不存在重复元素。

示例 1:

输入: [3,4,5,1,2]
输出: 1

示例 2:

输入: [4,5,6,7,0,1,2]
输出: 0

(2)代码

我的代码:

class Solution {
    
    
public:
    int findMin(vector<int>& nums) {
    
    
        int minimun=10000;
        int left=0;
        int right=nums.size()-1;
        int center;
        if(nums.size()==1)
        return nums[0];
        if(nums[nums.size()-1]>nums[0])
        return nums[0];
        // if(nums[nums.size()-1]<nums[nums.size()-2])
        // return nums[nums.size()-1];
        while(left<=right)
        {
    
    
            center=(left+right)/2;
            if(center!=0&&center!=(nums.size()-1))
            {
    
    
                if(nums[center]<nums[center-1]&&nums[center]<nums[center+1])
                {
    
    
                    return nums[center];
                }
            }
            if(right>=(center+1)&&nums[right]>=nums[center+1])
            {
    
    
                if((center+1)>0&&(center+1)<(nums.size()-1))
                {
    
    
                    if(nums[center+1]<nums[center]&&nums[center+1]<nums[center+2])
                    {
    
    
                        return nums[++center];
                    }
                }
                right=center-1;
            }
            if((center-1)>=left&&nums[center-1]>=nums[left])
            {
    
    
                if((center-1)>0&&(center-1)<(nums.size()-1))
                {
    
    
                    if(nums[center-1]<nums[center-2]&&nums[center-1]<nums[center])
                    {
    
    
                        return nums[--center];
                    }
                }
                left=center+1;
            }
        }
        return -1;
    }
};

网上的较为简洁的代码:

class Solution {
    
    
public:
    int findMin(vector<int>& nums) {
    
    
        int left=0;
        int right=nums.size()-1;
        int center;
        if(nums.size()==1)
        return nums[0];
        if(nums[nums.size()-1]>nums[0])
        return nums[0];
        while(left<right)
        {
    
    
            center=(left+right)/2;
            if(nums[center]>nums[left])
            left=center;
            else
            right=center;
        }
        return min(nums[left],nums[left+1]);
    }
};

(3)分析

这个题目,我的代码过于复杂了,主要是我自己写的时候,想的太复杂了,考虑到了很多种情况,所以代码越来越复杂。其实这个题目就跟上面的leetcode33的解题思路是差不多的,也是要利用旋转数组的这种特性,左右两个区间中必定有一个递增的。那每次就可以先找到递增的区间,找到之后,我们的最小元素肯定不在这个递增区间啊,但是这个思路有一个很重要的点就是,要知道每次二分得到的center位置的数据,也有可能是我们要找到的最小元素。所以我们确定了递增区间后,在确定下一次循环的区间时,必须要将center位置考虑进去。也就是此时的操作是left=center或者是right=center,而不是left=center+1或者right=center-1.

猜你喜欢

转载自blog.csdn.net/qq_38391210/article/details/108150126