zoukankan      html  css  js  c++  java
  • 二分查找&二叉排序树

    首先我们先来复习一下二分查找的算法 对于正向序列的二分查找

    递归实现:

     1 bool binary_search(vector<int> &sort_arry,int begin,int end,int target)
     2 {
     3     if(begin>end)
     4         return false;
     5     int mid = (begin + end) / 2;
     6     if(sort_arry[mid] == target)
     7         return true;
     8     else if(sort_arry[mid] > target)
     9     {
    10         return binary_search(sort_arry,begin,mid-1,target);
    11     }
    12     else
    13     {
    14         return binary_search(sort_arry,mid+1,end,target);
    15     }
    16 }

    循环实现:

     1 bool binary_search(vector<int> &sort_arry,int target)
     2 {
     3 int begin = 0; 
     4 int end = sort_arry.size() - 1;
     5 int mid = (begin + end) / 2;
     6 while(begin <= end)
     7 {
     8     if(sort_arry[mid] == target)
     9         return true;
    10     else if(sort_arry[mid] > target)
    11     {
    12         end = mid - 1;
    13     }
    14     else
    15     {
    16         begin = mid + 1;
    17     }
    18     mid = (begin + end) / 2;
    19 }
    20 return false;
    21 }

    35. 搜索插入位置

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

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

    示例 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 index = -1;
        int begin =0;
        int end = nums.size();
        while(index == -1)
        {
            int mid = (begin + end) / 2;
            if(target == nums[mid])
                index =mid;
            else if(target < nums[mid])
            {
                if(mid ==0 ||target > nums[mid-1])
                    index = mid;
                end = mid - 1;
            }
            else if(target > nums[mid])
            {
                if(mid == nums.size()-1 || target < nums[mid+1])
                    return mid + 1;
                 begin = mid + 1;
            }
    
        }
        return index;
        }
    };

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

    给定一个按照升序排列的整数数组 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
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    int left_bond(vector<int> &nums,int target)
    {
        int begin;
        int end = nums.size()-1;
        while(begin <= end)
        {
            int mid = (begin + end)/2;
            if(target == nums[mid])
            {
                if(mid == 0 || nums[mid-1] < target)
                {
    
                    return mid;
                }
                end = mid - 1;
            }
            else if(target < nums[mid])
            {
                end = mid - 1;
            }
            else
            {
                begin = mid + 1;
            }
        }
        return -1;
    }
    
    int right_bond(vector<int> &nums,int target)
    {
        int begin;
        int end = nums.size()-1;
        while(begin <= end)
        {
            int mid = (begin + end)/2;
            if(target == nums[mid])
            {
                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;
    }
    
    class Solution {
    public:
        vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> result;
        result.push_back(left_bond(nums,target));
        result.push_back(right_bond(nums,target));
        return result;
        }
    };

     旋转数组:

    33. 搜索旋转排序数组

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

    ( 例如,数组 [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
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    分析:

    ·如果target < nums[mid]的情况:

    1:如果nums[begin] < nums[end]:

    有两种可能 要么没转过 要么 转过(nums[begin] >nums[end])

    说明此时递增区间为begin~mid-1 旋转区间为mid+1~end

    比如是[7 9 12 15 20 1 3 6]的target =12

    因为12  >begin 所以就在递增区间找

    否则如果target = 3 < begin 应该在旋转区间中查找

    2:如果begin > mid 说明旋转区间在begin到mid-1之间,递增区间在mid+1到end之间

    比如[20 1 3 6 7 8 12 15]

    target = 3 (< mid) 说明递增区间已经不可能了,直接在旋转区间begin到mid-1中查找

    3:如果begin == mid 说明目标只能在mid+1到end之间查找 比如target = 1的时候数组是[6,1]

    ·如果目标target > nums[mid]的情况:

    1:当nums[begin] < nums[mid],说明递增区间是[begin,mid-1]旋转区间为[mid+1,end]

    比如数组[7 9 12 15 20 1 3 6]

    递增区间7~15旋转区间在20~6

    因为target已经大于mid处的值了,因此直接在旋转区间查找。

    例如查找target=20就在20~6里面找

    2:如果是nums[begin] > nums[mid]的情况 (有可能存在begin>end)

    说明递增区间在后半部分mid+1~end旋转区间在前半部分begin~mid-1

    比如15 20 1 3 6 7 9 12

    如果target=20>begin 那就在旋转区间begin~mid-1里找 ,否则在递增区间mid+1~end里找

    3:如果是begin == mid的情况那么也只可能在mid+1~end之间

    比如target = 7 数组是[6 7]

    class Solution {
    public:
        int search(vector<int>& nums, int target) {
        int begin =0;
        int end = nums.size() - 1;
        if(nums.size()==1)
        {
            if(nums[0]==target)
                return 0;
            else
                return -1;
        }
        while(begin <= end)//递增区间在前半部分
        {
            int mid = (begin + end) / 2;
            if(target == nums[mid])
            {
                return mid;
            }
            else if(target < nums[mid])
            {
                if(nums[begin] < nums[mid])
                {
                    if(target >= nums[begin])//说明应递增区间为begin~mid-1之间 旋转区间为mid+1~end之间
                    {
                        end = mid -1;
                    }
                    else
                    {
                        begin = mid + 1;
                    }
                }
            else if(nums[begin] > nums[mid])//说明递增区间在后面mid+1~end
            {
                end = mid -1;
            }
            else if(nums[begin] == nums[mid])//说明目标只可能在mid+1~end之间
            {
                begin = mid + 1;
            }
            }
            
            else if(target > nums[mid])
            {
                if(nums[begin] < nums[mid])//说明递增区间是begin~mid-1,旋转区间在后半部分
                {
                    begin = mid + 1;
                }
                else if(nums[begin] > nums[mid])
                {
                    if(target >= nums[begin])//说明递增区间在mid+1到end 旋转区间在前半部分。
                    {
                        end = mid - 1;
                    }
                    else
                    {
                        begin = mid + 1;
                    }
                }
                else if(nums[begin] == nums[mid])//说明只能在mid+1~end之间
                {
                    begin = mid + 1;
                }
            }
        }
        return -1;
        }
    };

    这题的边界真的很恶心…

    接下来介绍一个数据结构 二叉查找树

    二叉查找树是具有以下性质的二叉树:

    1:若左子树不为空,则左子树上所有节点的值均小于或等于他的根节点

    2:若右子树不为空,则右子树上所有节点的值均大于或等于他的根节点

    3:二叉查找树的左右子树也是二叉查找树

    4:等于的情况只能出现在左子树或右子树的某一侧(不能同时出现)

    由于二叉查找树的中序遍历是从小到大的,所以称之为二叉查找树。

    二叉查找树的插入操作:

    if   insert_node节点的值小于当前node的节点值

    {

    if (node有左子树) 则递归的将该节点插入到左子树为根的二叉排序树中,

    else (将node的left赋值为该节点的地址

    }

    else//(大于等于的情况下)

    {

    if(node有右子树)则递归的将该节点插入到右子树为根的二叉排序树中

    else (将node->right赋值为该节点的地址)

    }

    void BST_insert(TreeNode *node,TreeNode *insert_node)
    {
    if(insert_node->val< node->val)
    {
        if(node->left)
        {
            BST_insert(node->left,insert_node);
        }
        else
        {
            node->left = insert_node;
        }
    }
    else
    {
        if(node->right)
        {
            BST_insert(node->right,insert_node);
        }
        else
        {
            node->right = insert_node;
        }
    }
    }

    二叉树的查找:

    查找数组val是否在二叉树中出现:

    如果val == 当前节点的值返回真,

    如果val  < 当前节点的值 

    {

    如果当前节点有左子树,继续左子树中查找该值,否则返回false;

    否则{

    如果当前节点有右子树,就继续在右子树中查找,否则返回false;

    }

    }

    void BST_search(TreeNode*node,int val)
    {
        if(node->val == val)
            return true;
        if(val < node->val)
        {
            if(node->left)
            {
                BST_search(node,val);
            }
            else
            {
                return false;
            }
        }
        else
        {
            if(node->right)
            {
                BST_search(node,val);
            }
            else
            {
                return false;
            }
        }
    }

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

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

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

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

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

    来源:力扣(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:
        void BST_insert(TreeNode *node,TreeNode *insert_node)
    {
    if(insert_node->val< node->val)
    {
        if(node->left)
        {
            BST_insert(node->left,insert_node);
        }
        else
        {
            node->left = insert_node;
        }
    }
    else
    {
        if(node->right)
        {
            BST_insert(node->right,insert_node);
        }
        else
        {
            node->right = insert_node;
        }
    }
    }
    bool BST_search(TreeNode*node,int val)
    {
        if(node->val == val)
            return true;
        if(val < node->val)
        {
            if(node->left)
            {
                BST_search(node,val);
            }
            else
            {
                return false;
            }
        }
        else
        {
            if(node->right)
            {
                BST_search(node,val);
            }
            else
            {
                return false;
            }
        }
    }
        void change_int_to_str(int val, string &str)
        {
            string temp;
            while(val)
            {
            temp += (val % 10) +'0';
            val = val / 10;
            }
            for(int i = temp.length() - 1;i >= 0;i--)//逆序将字符串插入到str中
            {
                str += temp[i];
            }
            str += '#';//转换完以后用#分割
    
        }
        void BST_preorder(TreeNode *node,string &data)
        {
            if(!node)
            {
                return;
            }
            string str;//前序遍历把每次val添加到str中。
            change_int_to_str(node->val,str);
            data += str;//每次转换就添加,然后继续递归遍历
            BST_preorder(node->left,data);
            BST_preorder(node->right,data);
        }
    
        // Encodes a tree to a single string.
    
        string serialize(TreeNode* root) {
            string data;
            BST_preorder(root,data);
            return data;
    
        }
    
        // Decodes your encoded data to tree.
        TreeNode* deserialize(string data) {
            if(data.length() == 0)
            {
                return NULL;
            }
            vector<TreeNode*>node_vec;
            int val = 0;
            for(int i = 0; i < data.length();i++)
            {
                if(data[i] == '#')
                {
                    node_vec.push_back(new TreeNode(val));
                    val = 0;
                }
                else
                {
                   val = val *10 + data[i] - '0';
                }
            }
            for(int i = 1;i < node_vec.size();i++)
            {
                BST_insert(node_vec[0],node_vec[i]);
            }
            return node_vec[0];
        }
    };
    
    // Your Codec object will be instantiated and called as such:
    // Codec codec;
    // codec.deserialize(codec.serialize(root));

    315. 计算右侧小于当前元素的个数

    给定一个整数数组 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
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

     思路分析:

    将元素安装原数组逆置后的顺序插入到二叉查找树中,设置变量count_small = 0记录在插入过程中,有多少个元素比插入节点值小,

    若待插入的节点值<=node->val,那么node->count++,并且递归的将该节点插入到当前节点的左子树。

    若当待插入节点值大于当前节点的node的值,count_small+=node->count+1(当前节点左子树量+1)

    递归将该节点插入到当前节点的右子树。

    struct BSTNode
    {
        int val;
        int icount;
        BSTNode* left;
        BSTNode* right;
        BSTNode(int val)
        {
            val = val;
            left = NULL;
            right = NULL;
            icount = 0;
        }
    };
    class Solution {
    public:
    
        void BST_insert(BSTNode *node,BSTNode *insert_node,int &count_small)
        {
            if(insert_node->val <= node->val)
            {
                node->icount++;
                if(node->left)
                {
                    BST_insert(node->left,insert_node,count_small);
                }
                else
                {
                    node->left = insert_node;
                }
            }
            else
            {
                count_small += node->icount + 1;
                if(node->right)
                {
                    BST_insert(node->right,insert_node,count_small);
                }
                else
                {
                    node->right = insert_node;
                }
            }
        }
    
        vector<int> countSmaller(vector<int>& nums) {
            vector <int> result;//最终逆序数组
            vector<BSTNode*> node_vec;//创建二叉查找树节点池
            vector<int> icount;//从后插入过程中比当前节点小的count_small数组。
            for(int i = nums.size() - 1;i >= 0;i--)
            {
                node_vec.push_back(new BSTNode(nums[i]));
            }
            icount.push_back(0);//第一个节点count_small = 0
            for(int i = 1; i < node_vec.size(); i++)
            {
                int count_small = 0;
                BST_insert(node_vec[0],node_vec[i],count_small);
                icount.push_back(count_small);
            }
            for(int i = node_vec.size() - 1; i >= 0; i--)//将countsmall倒push到result数组中
            {
                delete node_vec[i];
                result.push_back(icount[i]);
            }
            return result;
        }
    };
  • 相关阅读:
    Node.js meitulu图片批量下载爬虫1.04版
    Node.js meitulu图片批量下载爬虫1.03版
    Node.js meitulu图片批量下载爬虫1.02版
    Node.js 解析gzip网页(https)
    Node.js 访问https网站
    Node.js meitulu图片批量下载爬虫1.01版
    我曾经七次鄙视自己的灵魂 卡里.纪伯伦
    ZT:有些人,活了一辈子,其实不过是认真过了一天,其余时间都在重复这一天而已
    节点对象图与DOM树形图
    DOM(文档对象模型)基础加强
  • 原文地址:https://www.cnblogs.com/KID-XiaoYuan/p/12470664.html
Copyright © 2011-2022 走看看