二分查找&二叉排序树

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

递归实现:

 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;
        }
        vectornode_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 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;
    }
};

 

你可能感兴趣的:(二分查找&二叉排序树)