LeetCode--Binary Search

来源:互联网 发布:淘宝it代购是真的吗 编辑:程序博客网 时间:2024/05/21 06:34

29. Divide Two Integers

Divide two integers without using multiplication, division and mod operator.
If it is overflow, return MAX_INT.

C++代码实现:

class Solution {public:    int divide(int dividend, int divisor) {        if(dividend==0)            return 0;        if(divisor==0 || (dividend==INT_MIN && divisor==-1))            return INT_MAX;        int result = 0;        int flag = (dividend<0)^(divisor<0) ? -1 : 1;        long long dvd = fabs(dividend);        long long dvs = fabs(divisor);        while(dvs<=dvd){            long long temp = dvs, multiple = 1;            //找到使的 dvs*2^n<=dvd 成立的 最大的 n,加快查找速度            while(dvd>=(temp<<1)){                temp<<=1;                multiple<<=1;            }            dvd -= temp;            result += multiple;        }        return (flag>0) ? result : -result;    }};

153. Find Minimum in Rotated Sorted Array

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).
Find the minimum element.
You may assume no duplicate exists in the array.

C++代码实现:

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

33. Search in Rotated Sorted Array

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).
You are given a target value to search. If found in the array return its index, otherwise return -1.
You may assume no duplicate exists in the array.

C++代码实现:

class Solution {public:    int findMin(vector<int>& nums) {        int left = 0, right = nums.size()-1;        while(left<right){            if(nums[left]<nums[right])                return nums[left];            int middle = (left+right)/2;            if(nums[middle]>nums[right])                left = middle+1;            else                right = middle;        }        return nums[left];    }};
class Solution {public:    int search(vector<int>& nums, int target) {        int size = nums.size();        if(size==0)            return -1;        int middle = 0;        while(middle<(size-1)){            if(nums[middle]>nums[middle+1])                break;            middle++;        }       // cout<<middle<<endl;        if(nums[middle]==target)            return middle;        else if(target>nums[middle])            return -1;        else if(target>=nums[0])                return binarySearch(nums,target,0,middle);        else            return binarySearch(nums,target,middle+1,size-1);    }private:    int binarySearch(vector<int>& nums, int target,int left,int right){        //cout<<left<<","<<right<<endl;        if(left>right)            return -1;        if(left==right && target!=nums[left])            return -1;        else if(left==right)            return left;        int middle = (left+right)/2;        if(nums[middle]==target)            return middle;        else if(nums[middle]>target)            return binarySearch(nums,target,left,middle);        else            return binarySearch(nums,target,middle+1,right);    }};

34. Search for a Range

Given an array of integers sorted in ascending order, find the starting and ending position of a given target value.
Your algorithm’s runtime complexity must be in the order of O(log n).
If the target is not found in the array, return [-1, -1].

For example

Given [5, 7, 7, 8, 8, 10] and target value 8,
return [3, 4].

C++代码实现:

class Solution {public:    vector<int> searchRange(vector<int>& nums, int target) {        vector<int> result;        int left = 0, right = nums.size()-1;        int start = -1, end = -1;        while(left<=right){            int middle = (left+right)/2;            if(nums[middle]==target){                int temp = middle;                start = end = middle;                while(temp>left && nums[--temp]==target)                    start = temp;                temp = middle;                while(temp<right && nums[++temp]==target)                    end = temp;                break;            }            else if(nums[middle]>target)                right = middle-1;            else                left = middle+1;        }        result.push_back(start);        result.push_back(end);        return result;    }};

162. Find Peak Element

A peak element is an element that is greater than its neighbors.
Given an input array where num[i] ≠ num[i+1], find a peak element and return its index.
The array may contain multiple peaks, in that case return the index to any one of the peaks is fine.
You may imagine that num[-1] = num[n] = -∞.
For example, in array [1, 2, 3, 1], 3 is a peak element and your function should return the index number 2.

C++实现:

class Solution {public:    int findPeakElement(vector<int>& nums) {        if(nums.size()<=1)            return 0;        int left = 0, right = nums.size()-1;        while(left<right){            int mid1 = (left+right)/2;            int mid2 = mid1+1;            if(nums[mid1] < nums[mid2])                left = mid2;            else                right = mid1;        }        return left;        /*        for(int i = 1; i < num.size(); i ++)        {            if(num[i] < num[i-1])            {                return i-1;            }        }        return num.size()-1;        */    }};

378. Kth Smallest Element in a Sorted Matrix(重要)

Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth smallest element in the matrix.
Note that it is the kth smallest element in the sorted order, not the kth distinct element.

Example:

matrix = [ [ 1, 5, 9], [10, 11, 13], [12, 13, 15]],k = 8,return 13.

Note:

You may assume k is always valid, 1 ≤ k ≤ n2.

解析:

(1)方法一:对矩阵进行排序,然后输出第K的数即可。复杂度O(n*nlogn*n)。
(2)方法二:二分搜索。由于是有序矩阵,那么左上角的数字一定是最小的,而右下角的数字一定是最大的,所以这个是我们搜索的范围,然后我们算出中间数字mid,由于矩阵中不同行之间的元素并不是严格有序的,所以我们要在每一行都查找一下mid,我们使用upper_bound,这个函数是查找第一个大于目标数的元素位置,如果目标数比该行的尾元素大,则upper_bound返回该行end(),如果目标数比该行首元素小,则upper_bound返回begin(), 我们遍历完所有的行可以找出中间数是第几小的数,然后k比较,继续进行二分查找,本解法的整体时间复杂度为O(nlgn*lgX),其中X为最大值和最小值的差值。

可参考:http://www.cnblogs.com/grandyang/p/5727892.html

C++代码实现:

class Solution {public:    int kthSmallest(vector<vector<int>>& matrix, int k) {        if(matrix.size()==0 || matrix[0].size()==0)            return 0;        if(k==1)            return matrix[0][0];        int n = matrix.size();        int left = matrix[0][0];        int right = matrix[n-1][n-1];        int mid = 0;        while(left < right){            mid = left + (right-left)/2;            int num = 0;            for(int i=0; i<n; ++i){                num += upper_bound(matrix[i].begin(),matrix[i].end(),mid)-matrix[i].begin();            }            if(num < k)                left = mid+1;            else                right = mid;        }        return left;    }};

230. Kth Smallest Element in a BST

Given a binary search tree, write a function kthSmallest to find the kth smallest element in it.

Note:

You may assume k is always valid, 1<=k <= BST’s total elements.

Follow up:

What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How would you optimize the kthSmallest routine?

解析:

(1)方法一:中序遍历。对二叉搜索树进行中序遍历,放入vector中,然后输出第k值即为第k小的数。
(2)方法二:二分查找。

C++代码实现:
方法一:中序遍历

/** * Definition for a binary tree node. * struct TreeNode { *     int val; *     TreeNode *left; *     TreeNode *right; *     TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */class Solution {public:    int kthSmallest(TreeNode* root, int k) {        int count = 0;        stack<TreeNode*> s;        vector<int> node;        TreeNode* p = root;        while(p!=NULL || !s.empty()) {            while(p!=NULL){                s.push(p);                p = p->left;            }            if(!s.empty()) {                p = s.top();                node.push_back(p->val);                s.pop();                p = p->right;            }        }        return node[k-1];    }};

方法二:二分查找

/** * Definition for a binary tree node. * struct TreeNode { *     int val; *     TreeNode *left; *     TreeNode *right; *     TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */class Solution {public:    int kthSmallest(TreeNode* root, int k) {        int count = 0;        count = getTreeNodeCount(root->left);        if(k<=count) {   //left            return kthSmallest(root->left,k);        }else if(k>(count+1)) { //right            return kthSmallest(root->right,k-1-count);        }        return root->val;    }private:    int getTreeNodeCount(TreeNode* root) {        if(root==NULL)            return 0;        return 1+getTreeNodeCount(root->left)+getTreeNodeCount(root->right);    }};

209. Minimum Size Subarray Sum

Given an array of n positive integers and a positive integer s, find the minimal length of a contiguous subarray of which the sum ≥ s. If there isn’t one, return 0 instead.
For example, given the array [2,3,1,2,4,3] and s = 7,
the subarray [4,3] has the minimal length under the problem constraint.

解析:

(1)方法一:双指针+移动窗口,定义left和right指针,初始分别指向array[0],temp代表剩余容量,初始为s。不断向右移动right,temp -= array[right],如果temp小于0,则表示[left,right]形成的窗口的数字总和>=s,为题目的候选解,[left,right]窗口中数字最少的即为答案。时间复杂度为O(n)
(2)方法二:二分搜索。array中数字不是严格有序的,但是array中数字累积和肯定是有序的,因此可以定义sums[array.len+1],使得sum[i] = sum[i-1]+array[i-1]。对于sums中每个元素i,二分查找[i+1,sums.len]之间大于等于sums[i]+s的第一个值的下标end,end-i即为元素个数。至于为什么是从[i+1,sums.len]之间大于等于sums[i]+s?,因为sums记录的是累积和,查找的数应该是sums[i]+s(相当于在array中查找和为s的某几个连续的数)。

C++代码实现:
方法一:

class Solution {public:    int minSubArrayLen(int s, vector<int>& nums) {        int result = INT_MAX;        int left = 0, right = 0;        int temp = s;        int count = 0;        while(right<nums.size()) {            temp -= nums[right++];            count++;            while(temp<=0) {                result = count < result ? count : result;                temp += nums[left++];                count--;            }        }        if(result==INT_MAX)            return 0;        return result;    }};

方法二:

class Solution {public:    int minSubArrayLen(int s, vector<int>& nums) {        int result = INT_MAX;        vector<int> sums(nums.size()+1,0);          for(int i=1; i<sums.size(); ++i)            sums[i] = sums[i-1] + nums[i-1];        for(int i=0; i<sums.size(); i++) {            int end = binarySearch(i+1,sums.size()-1,sums[i]+s,sums);            if(end==sums.size())                break;            if(end-i < result)                result = end-i;        }        return result==INT_MAX ? 0 : result;    }private:    int binarySearch(int left,int right,int key,vector<int>& sums) {        while(left<=right) {            int mid = (left+right)/2;            if(sums[mid]>=key)                right = mid-1 ;            else                left = mid+1;        }        return left;    }};

300. Longest Increasing Subsequence

Given an unsorted array of integers, find the length of longest increasing subsequence.
For example,
Given [10, 9, 2, 5, 3, 7, 101, 18],
The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4. Note that there may be more than one LIS combination, it is only necessary for you to return the length.
Your algorithm should run in O(n2) complexity.
Follow up: Could you improve it to O(n log n) time complexity?

解析:

(1)方法一:DP算法。用lis[]记录每个数所能形成的最长升序子序列的长度。循环对于每个array中每个元素array[i],判断其前面的元素array[j]是否比他小,如果array[i]小于array[j],判断lis[j]+1 是否大于 lis[i],如果大于则更新lis[i]。最后,从lis中选取最大值。时间复杂度O(n^2)。

C++代码实现:

class Solution {public:    int lengthOfLIS(vector<int>& nums) {        int size = nums.size();        if(size<=1)            return size;        int result = 1;        vector<int> lis(size,1);      //记录最长升序子序列的长度        for(int i=1; i<size; ++i) {            for(int j=0; j<i; ++j) {                if(nums[j]<nums[i]) {                    if(lis[j]+1 > lis[i])                        lis[i] = lis[j]+1;                }            }        }        for(auto a : lis)            if(a>result)                result = a;        return result;    }};

483. Smallest Good Base

For an integer n, we call k>=2 a good base of n, if all digits of n base k are 1.
Now given a string representing n, you should return the smallest good base of n in string format.
Example 1:
Input: “13”
Output: “3”
Explanation: 13 base 3 is 111.
Example 2:
Input: “4681”
Output: “8”
Explanation: 4681 base 8 is 11111.
Example 3:
Input: “1000000000000000000”
Output: “999999999999999999”
Explanation: 1000000000000000000 base 999999999999999999 is 11.

Note:

The range of n is [3, 10^18].
The string representing n is always valid and will not have leading zeros.

解析:

现将字符串转成long long类型数字n,n=1+k^1+k^2+…+k^d,且n<=10^18,k>=2, 则以二进制为底,d<=62。即d的范围为[1,62]. 对于任意n>=3,n以(n-1)为底,其结果为11。d越大,则k越小。对于确定的d和n,可以确定k的取值范围为[2,n^(1.0/d)],此时采用二分搜索k。

C++代码实现:

class Solution {public:    string smallestGoodBase(string n) {        unsigned long long num = (unsigned long long)stoll(n);        unsigned long long x = 1;        unsigned long long k = 0;        for(int d=62; d>0; d--) {   //n=1+k^1+k^2+...+k^d,且n<=10^18,则以二进制为底,d<=62            if((x<<d)<num) {                k = binarySearch(num,d);                if(k!=0)                    return to_string(k);            }        }        return to_string(num-1);      //对于任意n>=3,n以(n-1)为底,其结果为11.    }private:    unsigned long long binarySearch(unsigned long long n,int d) {        double tn=(double) n;        unsigned long long right=(unsigned long long)(pow(tn,1.0/d)); //n=1+k^1+k^2+...+k^d,则k最大为n^(1/d)        unsigned long long left=2;          //k最小为2        while (left<=right){            unsigned long long mid=left+(right-left)/2;            unsigned long long sum=1,cur=1;            for (int i=1;i<=d;i++) {                cur*=mid;                sum+=cur;            }            if (sum==n) return mid;            if (sum>n) right=mid-1;            else left=mid+1;        }        return 0;    }};

154. Find Minimum in Rotated Sorted Array II

Follow up for “Find Minimum in Rotated Sorted Array”:
What if duplicates are allowed?
Would this affect the run-time complexity? How and why?
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., 1,2,10,10,10,10,10 might become 10,10,1,2,10,10,10)
Find the minimum element.
The array may contain duplicates.

解析:

(1)方法一:找前后两半的分割点。即nums[left] < nums[left+1],则此时left为分割点。时间复杂度为O(n)。
(2)方法二:二分查找。取中间值mid,如果nums[mid] > nums[right],说明最小值在mid右半边,即[mid+1,right];如果nums[mid] < nums[right],则说明最小值在mid左半边,即[left,mid];如果nums[mid]==nums[right],无法确切判断最小值在哪边,但是可以去掉末尾最大值,继续二分查找。时间复杂度O(logn)

C++代码实现:
方法二:

class Solution {public:    int findMin(vector<int>& nums) {        if(nums.size()==1)            return nums[0];        int left = 0, right = nums.size()-1;        while(left<right) {            int mid = left+(right-left)/2;            if(nums[mid] > nums[right])         //说明最小值在mid右半边,即[mid+1,right]                left = mid+1;            else if(nums[mid] < nums[right])    //说明最小值在mid左半边,即[left,mid]                right = mid;            else        //mid和right相等,无法确切判断最小值在哪边,但是可以去掉末尾最大值,继续二分查找                --right;            }        return nums[left];    }};

方法一:

class Solution {public:    int findMin(vector<int>& nums) {        if(nums.size()==1)            return nums[0];        int left = 0, right = nums.size()-1;        if(nums[left]<nums[right])            return nums[left];        int middle = 0;                 while(middle<right){            if(nums[middle]>nums[middle+1])                break;                      //分割点            middle++;        }        if(middle==right)            return nums[middle];        return nums[middle+1];    }};