算法-二分查找与二叉排序树

示例:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。


示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

 

提示:

    你可以假设 nums 中的所有元素是不重复的。
    n 将在 [1, 10000]之间。
    nums 的每个元素都将在 [-9999, 9999]之间。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-search
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

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

1.搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

你可以假设数组中无重复元素。

示例 1:

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

示例 2:

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

示例 3:

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

示例 4:

输入: [1,3,5,6], 0
输出: 0

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-insert-position
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

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

 

2. 在排序数组中查找元素的第一个和最后一个位置

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

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

如果数组中不存在目标值,返回 [-1, -1]。

示例 1:

输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]

示例 2:

输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

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

3.搜索旋转排序数组

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

( 例如,数组 [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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

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

4.最长上升子序列

给定一个无序的整数数组,找到其中最长上升子序列的长度(严格上升,不必连续)。

示例:

输入: [10,9,2,5,3,7,101,18]
输出: 4 
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4

说明:

  • 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
  • 你算法的时间复杂度应该为 O(n2) 。

进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?

//寻找第一个大于x的元素下标,返回start.
int binary_search(int x, vector<int>& s) {
    int start = 0;
    int end = s.size() - 1;
    int mid;
    while (start<=end) {
        mid = (start + end) / 2;
        if (s[mid] > x) {
            end = mid - 1;
        } else if (s[mid] < x) {
            start = mid + 1;
        } else {
            return mid;
        }
    }
    return start;
}
    

class Solution{
public:
    int lengthOfLIS(vector<int>& nums) {
        int len=nums.size();
        if(len==0) return 0;
        vector<int> stack;
        stack.push_back(nums[0]);
        int index=-1;
        for(int i=1;i<len;i++){
            if(nums[i]>stack.back()){
                stack.push_back(nums[i]);
            }else{
                index=binary_search(nums[i],stack);
                stack[index]=nums[i];
            }
        }
        return stack.size();
    }
};

 若是寻找第一个小于x的元素下标,则返回end


 5.序列化和反序列化二叉搜索树

序列化是将数据结构或对象转换为一系列位的过程,以便它可以存储在文件或内存缓冲区中,或通过网络连接链路传输,以便稍后在同一个或另一个计算机环境中重建。

设计一个算法来序列化和反序列化二叉搜索树。 对序列化/反序列化算法的工作方式没有限制。 您只需确保二叉搜索树可以序列化为字符串,并且可以将该字符串反序列化为最初的二叉搜索树。

编码的字符串应尽可能紧凑。

注意:不要使用类成员/全局/静态变量来存储状态。 你的序列化和反序列化算法应该是无状态的。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/serialize-and-deserialize-bst
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Codec {
public:

    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        string data="";
        preorder(root,data);
        return data;
    }
    void preorder(TreeNode* root,string& data){
        if(!root) return;  
        data+=intToString(root->val);
        data+='#';
        preorder(root->left,data);
        preorder(root->right,data);
    }
    //整数转化为字符串
    string intToString(int val) {
        string s = "";
        while (val) {
            s += val % 10 + '0';
            val /= 10;
        }    
        string res="";
        //需要倒序得到正确字符串
        for(int i=s.size()-1;i>=0;i--){
            res+=s[i];
        }
        return res;
    }
    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        TreeNode* root=NULL;
        int tmp=0;
        for(int i=0;i<data.size();i++){ 
            while(data[i]!='#'){
                tmp=tmp*10+data[i]-'0';
                i++;
            }            
            TreeNode* node=new TreeNode(tmp);
            if(root==NULL) root=node;
            else{
               insert(root,node); 
            }            
            tmp=0;
        }
        return root;
        
    }
    //逐个插入构成二叉排序树
    void insert(TreeNode* root,TreeNode* node){      
        if(node->val<root->val){
            if(root->left==nullptr){
                root->left=node;
                
            }else{
                insert(root->left,node);
            }
        }else{
            if(root->right==nullptr){
                root->right=node;
            }else{
                insert(root->right,node);
            }
        }
    }
};

// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));

6. 计算右侧小于当前元素的个数 (逆序数)

给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i] 的值是  nums[i] 右侧小于 nums[i] 的元素的数量。

示例:

输入: [5,2,6,1]
输出: [2,1,1,0]
解释:
5 的右侧有 2 个更小的元素 (2 和 1).
2 的右侧仅有 1 个更小的元素 (1).
6 的右侧有 1 个更小的元素 (1).
1 的右侧有 0 个更小的元素.

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-of-smaller-numbers-after-self
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

猜你喜欢

转载自www.cnblogs.com/chendaniu/p/10743108.html